diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..ca812e4 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +*.tmp +*.dockerimage +.git diff --git a/.drone.yml b/.drone.yml index 952e206..f8b7eaa 100644 --- a/.drone.yml +++ b/.drone.yml @@ -7,8 +7,17 @@ steps: network_mode: bridge settings: repo: sneak/mfer + build_args_from_env: [ DRONE_COMMIT_SHA ] dry_run: true custom_dns: [ 116.202.204.30 ] tags: - - ${DRONE_COMMIT_SHA} + - ${DRONE_COMMIT_SHA:0:7} - ${DRONE_BRANCH} + - latest +- name: notify + image: plugins/slack + settings: + webhook: + from_secret: SLACK_WEBHOOK_URL + when: + event: pull_request diff --git a/.gitignore b/.gitignore index 8c2487d..105d015 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,6 @@ mfer/*.pb.go /mfer.cmd +/tmp +*.tmp +*.dockerimage +/vendor diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..f23bddd --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,2 @@ +run: + tests: false diff --git a/Dockerfile b/Dockerfile index 634f6b7..79673cf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,42 +1,37 @@ -## lint image -## current as of 2022-01-25 -FROM golangci/golangci-lint:latest AS linter - -RUN mkdir -p /build -WORKDIR /build -COPY ./ ./ -RUN golangci-lint run - -## build image: -# this is golang:1.17.6-buster as of 2022-01-27 -FROM golang@sha256:52a48e0239f4d645b20ac268a60361703afe7feb2df5697fa89f72052cb87a3e AS builder -#FROM golang:1.16-buster AS builder - +################################################################################ +#2345678911234567892123456789312345678941234567895123456789612345678971234567898 +################################################################################ +FROM sneak/builder:2022-12-08 AS builder ENV DEBIAN_FRONTEND noninteractive -RUN apt update && apt install -y make bzip2 curl unzip - -# install newer protoc than what comes with buster -ENV PB_REL https://github.com/protocolbuffers/protobuf/releases -RUN curl -LO $PB_REL/download/v3.19.0/protoc-3.19.0-linux-x86_64.zip && \ - unzip protoc-3.19.0-linux-x86_64.zip -d /usr/local - -RUN mkdir -p /build WORKDIR /build +COPY ./Makefile ./.golangci.yml ./go.mod ./go.sum /build/ +COPY ./vendor.tzst /build/vendor.tzst +COPY ./modcache.tzst /build/modcache.tzst +COPY ./internal ./internal +COPY ./bin/gitrev.sh ./bin/gitrev.sh +COPY ./mfer ./mfer +COPY ./cmd ./cmd +ARG GITREV unknown +ARG DRONE_COMMIT_SHA unknown -COPY go.mod . -COPY go.sum . - -COPY ./ ./ -# don't lint again during build because there's no golangci-lint in this -# image and we already did it in a previous stage -#RUN make lint -RUN make mfer -#RUN go mod vendor -RUN tar -c . | bzip2 > /src.tbz2 - - +RUN mkdir -p "$(go env GOMODCACHE)" && cd "$(go env GOMODCACHE)" && \ + zstdmt -d --stdout /build/modcache.tzst | tar xf - && \ + rm /build/modcache.tzst && cd /build +RUN \ + cd mfer && go generate . && cd .. && \ + GOPACKAGESDEBUG=true golangci-lint run ./... && \ + mkdir vendor && cd vendor && \ + zstdmt -d --stdout /build/vendor.tzst | tar xf - && rm /build/vendor.tzst && \ + cd .. && \ + make mfer.cmd +RUN rm -rf /build/vendor && go mod vendor && tar -c . | zstdmt -19 > /src.tzst +################################################################################ +#2345678911234567892123456789312345678941234567895123456789612345678971234567898 +################################################################################ +## final image +################################################################################ FROM scratch -COPY --from=builder /src.tbz2 /src.tbz2 -COPY --from=builder /build/mfer /mfer +# we put all the source into the final image for posterity, it's small +COPY --from=builder /src.tzst /src.tzst +COPY --from=builder /build/mfer.cmd /mfer ENTRYPOINT ["/mfer"] - diff --git a/Makefile b/Makefile index 87ae6be..8bdb0ed 100644 --- a/Makefile +++ b/Makefile @@ -1,40 +1,52 @@ - +export DOCKER_BUILDKIT := 1 +export PROGRESS_NO_TRUNC := 1 GOPATH := $(shell go env GOPATH) export PATH := $(PATH):$(GOPATH)/bin PROTOC_GEN_GO := $(GOPATH)/bin/protoc-gen-go - +SOURCEFILES := mfer/*.go mfer/*.proto internal/*/*.go cmd/*/*.go go.mod go.sum ARCH := $(shell uname -m) -GITREV := $(shell git describe --always --dirty=-dirty) - -GOLDFLAGS += -X main.Version=0.1.0 -GOLDFLAGS += -X main.Gitrev=$(GITREV) +GITREV_BUILD := $(shell bash $(PWD)/bin/gitrev.sh) +APPNAME := mfer +VERSION := 0.1.0 +export DOCKER_IMAGE_CACHE_DIR := $(HOME)/Library/Caches/Docker/$(APPNAME)-$(ARCH) +GOLDFLAGS += -X main.Version=$(VERSION) +GOLDFLAGS += -X main.Gitrev=$(GITREV_BUILD) GOFLAGS := -ldflags "$(GOLDFLAGS)" -default: run +.PHONY: docker default run ci test fixme + +default: fmt test run: ./mfer.cmd ./$< ./$< gen --ignore-dotfiles +ci: test + +test: $(SOURCEFILES) mfer/mf.pb.go + go test -v --timeout 3s ./... + $(PROTOC_GEN_GO): - test -e $(PROTOC_GEN_GO) || go install -v google.golang.org/protobuf/cmd/protoc-gen-go@latest + test -e $(PROTOC_GEN_GO) || go install -v google.golang.org/protobuf/cmd/protoc-gen-go@v1.28.1 fixme: @grep -nir fixme . | grep -v Makefile devprereqs: which gofumpt || go install -v mvdan.cc/gofumpt@latest - which golangci-lint || go install -v github.com/golangci/golangci-lint/cmd/golangci-lint@latest + which golangci-lint || go install -v github.com/golangci/golangci-lint/cmd/golangci-lint@v1.50.1 -mfer.cmd: $(PROTOC_GEN_GO) mfer/*.go internal/*/*.go cmd/*/*.go - protoc --version +mfer/mf.pb.go: mfer/mf.proto cd mfer && go generate . + +mfer.cmd: $(SOURCEFILES) mfer/mf.pb.go + protoc --version cd cmd/mfer && go build -tags urfave_cli_no_docs -o ../../mfer.cmd $(GOFLAGS) . clean: - rm -rfv mfer/*.pb.go mfer.cmd cmd/mfer/mfer + rm -rfv mfer/*.pb.go mfer.cmd cmd/mfer/mfer *.dockerimage -fmt: devprereqs +fmt: mfer/mf.pb.go gofumpt -l -w mfer internal cmd golangci-lint run --fix -prettier -w *.json @@ -44,5 +56,27 @@ lint: golangci-lint run sh -c 'test -z "$$(gofmt -l .)"' -dockerbuild: - docker build . +docker: sneak-mfer.$(ARCH).tzst.dockerimage + +sneak-mfer.$(ARCH).tzst.dockerimage: $(SOURCEFILES) vendor.tzst modcache.tzst + docker build --progress plain --build-arg GITREV=$(GITREV_BUILD) -t sneak/mfer . + docker save sneak/mfer | pv | zstdmt -19 > $@ + du -sh $@ + +godoc: + open http://127.0.0.1:6060 + godoc -http=:6060 + +vendor.tzst: go.mod go.sum + go mod tidy + go mod vendor + cd vendor && tar -c . | pv | zstdmt -19 > $(PWD)/$@.tmp + rm -rf vendor + mv $@.tmp $@ + +modcache.tzst: go.mod go.sum + go mod tidy + cd $(HOME)/go/pkg && chmod -R u+rw . && rm -rf mod sumdb + go mod download -x + cd $(shell go env GOMODCACHE) && tar -c . | pv | zstdmt -19 > $(PWD)/$@.tmp + mv $@.tmp $@ diff --git a/bin/gitrev.sh b/bin/gitrev.sh new file mode 100644 index 0000000..cc44344 --- /dev/null +++ b/bin/gitrev.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# +if [[ ! -z "$DRONE_COMMIT_SHA" ]]; then + echo "${DRONE_COMMIT_SHA:0:7}" + exit 0 +fi + +if [[ ! -z "$GITREV" ]]; then + echo $GITREV +else + git describe --always --dirty=-dirty +fi diff --git a/cmd/mfer/main_test.go b/cmd/mfer/main_test.go new file mode 100644 index 0000000..907d1af --- /dev/null +++ b/cmd/mfer/main_test.go @@ -0,0 +1,11 @@ +package main + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBuild(t *testing.T) { + assert.True(t, true) +} diff --git a/go.mod b/go.mod index 1347520..2d4dcff 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,34 @@ module git.eeqj.de/sneak/mfer -go 1.16 +go 1.17 require ( + github.com/apex/log v1.9.0 github.com/davecgh/go-spew v1.1.1 github.com/pterm/pterm v0.12.35 github.com/spf13/afero v1.8.0 - github.com/urfave/cli/v2 v2.3.0 - github.com/visionmedia/go-cli-log v0.0.0-20151214173634-914d1b040b20 // indirect - google.golang.org/protobuf v1.27.1 + github.com/stretchr/testify v1.8.1 + github.com/urfave/cli/v2 v2.23.6 + google.golang.org/protobuf v1.28.1 + +) + +require ( + github.com/atomicgo/cursor v0.0.1 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/fatih/color v1.7.0 // indirect + github.com/gookit/color v1.4.2 // indirect + github.com/mattn/go-colorable v0.1.2 // indirect + github.com/mattn/go-isatty v0.0.8 // indirect + github.com/mattn/go-runewidth v0.0.13 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect + github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect + golang.org/x/sys v0.0.0-20211013075003-97ac67df715c // indirect + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect + golang.org/x/text v0.3.4 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 0772536..0a2d55c 100644 --- a/go.sum +++ b/go.sum @@ -37,6 +37,7 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs= github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8= @@ -44,8 +45,15 @@ github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBE github.com/MarvinJWendt/testza v0.2.10/go.mod h1:pd+VWsoGUiFtq+hRKSU1Bktnn+DMCSrDrXDpX2bG66k= github.com/MarvinJWendt/testza v0.2.12 h1:/PRp/BF+27t2ZxynTiqj0nyND5PbOtfJS0SuTuxmgeg= github.com/MarvinJWendt/testza v0.2.12/go.mod h1:JOIegYyV7rX+7VZ9r77L/eH6CfJHHzXjB69adAhzZkI= +github.com/apex/log v1.9.0 h1:FHtw/xuaM8AgmvDDTI9fiwoAL25Sq2cxojnZICUU8l0= +github.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA= +github.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= +github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= +github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= github.com/atomicgo/cursor v0.0.1 h1:xdogsqa6YYlLfM+GyClC/Lchf7aiMerFiZQn7soTOoU= github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= +github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= @@ -54,8 +62,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -65,9 +73,13 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -121,6 +133,7 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= @@ -129,19 +142,37 @@ github.com/gookit/color v1.4.2 h1:tXy44JFSFkKnELV6WaMo/lLfu/meqITX3iAV52do7lk= github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -156,25 +187,41 @@ github.com/pterm/pterm v0.12.35 h1:A/vHwDM+WByn0sTPlpL2L6kOTy12xqZuwNFMF/NlA+U= github.com/pterm/pterm v0.12.35/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= +github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= github.com/spf13/afero v1.8.0 h1:5MmtuhAgYeU6qpa7w7bP0dv6MBYuup0vekhSpSkoq60= github.com/spf13/afero v1.8.0/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= -github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= -github.com/visionmedia/go-cli-log v0.0.0-20151214173634-914d1b040b20 h1:RDJ3ggSqBL4Mu/ANRKmxuLrwnupJsvHRDXe4/KI+HWE= -github.com/visionmedia/go-cli-log v0.0.0-20151214173634-914d1b040b20/go.mod h1:iljxuLc3m07jsXOWojqehoTp/Fh0XP7irbhV+6sYNGc= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= +github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= +github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= +github.com/tj/go-buffer v1.1.0/go.mod h1:iyiJpfFcR2B9sXu7KvjbT9fpM4mOelRSDTbntVj52Uc= +github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= +github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= +github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= +github.com/urfave/cli/v2 v2.23.6 h1:iWmtKD+prGo1nKUtLO0Wg4z9esfBM4rAV4QRLQiEmJ4= +github.com/urfave/cli/v2 v2.23.6/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -186,6 +233,7 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -227,6 +275,7 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -276,7 +325,9 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -468,16 +519,22 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/bork/error.go b/internal/bork/error.go new file mode 100644 index 0000000..6ead94d --- /dev/null +++ b/internal/bork/error.go @@ -0,0 +1,15 @@ +package bork + +import ( + "errors" + "fmt" +) + +var ( + ErrMissingMagic = errors.New("missing magic bytes in file") + ErrFileTruncated = errors.New("file/stream is truncated abnormally") +) + +func Newf(format string, args ...interface{}) error { + return fmt.Errorf(format, args...) +} diff --git a/internal/bork/error_test.go b/internal/bork/error_test.go new file mode 100644 index 0000000..f98318f --- /dev/null +++ b/internal/bork/error_test.go @@ -0,0 +1,11 @@ +package bork + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBuild(t *testing.T) { + assert.NotNil(t, ErrMissingMagic) +} diff --git a/internal/cli/check.go b/internal/cli/check.go index 146cfc5..f38a5f2 100644 --- a/internal/cli/check.go +++ b/internal/cli/check.go @@ -3,12 +3,11 @@ package cli import ( "errors" - log "github.com/visionmedia/go-cli-log" - + "github.com/apex/log" "github.com/urfave/cli/v2" ) func (mfa *CLIApp) checkManifestOperation(c *cli.Context) error { - log.Error(errors.New("unimplemented")) + log.WithError(errors.New("unimplemented")) return nil } diff --git a/internal/cli/entry_test.go b/internal/cli/entry_test.go new file mode 100644 index 0000000..71d4a78 --- /dev/null +++ b/internal/cli/entry_test.go @@ -0,0 +1,12 @@ +package cli + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBuild(t *testing.T) { + m := &CLIApp{} + assert.NotNil(t, m) +} diff --git a/internal/cli/fetch.go b/internal/cli/fetch.go index d23f7bb..e20143b 100644 --- a/internal/cli/fetch.go +++ b/internal/cli/fetch.go @@ -1,12 +1,12 @@ package cli import ( - "fmt" - + "github.com/apex/log" "github.com/urfave/cli/v2" ) func (mfa *CLIApp) fetchManifestOperation(c *cli.Context) error { - fmt.Println("fetchManifestOperation()") - return nil + log.Debugf("fetchManifestOperation()") + panic("not implemented") + return nil //nolint } diff --git a/internal/cli/gen.go b/internal/cli/gen.go index fe0d087..1ed57ef 100644 --- a/internal/cli/gen.go +++ b/internal/cli/gen.go @@ -1,36 +1,54 @@ package cli import ( - "fmt" + "bytes" + "path/filepath" + "git.eeqj.de/sneak/mfer/internal/log" "git.eeqj.de/sneak/mfer/mfer" - "github.com/davecgh/go-spew/spew" "github.com/urfave/cli/v2" ) -func (mfa *CLIApp) generateManifestOperation(c *cli.Context) error { - fmt.Println("generateManifestOperation()") - myArgs := c.Args() - spew.Dump(myArgs) - - fmt.Printf("%#v\n", c.Args().First()) - if c.Args().Len() > 0 { - fmt.Printf("%#v\n", c.Args().Get(1)) - } - - // fmt.Printf("called with arg: %s\n", c.String("input")) +func (mfa *CLIApp) generateManifestOperation(ctx *cli.Context) error { + log.Debug("generateManifestOperation()") + myArgs := ctx.Args() + log.Dump(myArgs) opts := &mfer.ManifestScanOptions{ - IgnoreDotfiles: c.Bool("IgnoreDotfiles"), - FollowSymLinks: c.Bool("FollowSymLinks"), + IgnoreDotfiles: ctx.Bool("IgnoreDotfiles"), + FollowSymLinks: ctx.Bool("FollowSymLinks"), } - // FIXME add command flags for ignoring dotfiles and following symlinks - mf, err := mfer.NewFromPath(c.String("input"), opts) + paths := make([]string, ctx.Args().Len()-1) + for i := 0; i < ctx.Args().Len(); i++ { + ap, err := filepath.Abs(ctx.Args().Get(i)) + if err != nil { + return err + } + log.Dump(ap) + paths = append(paths, ap) + } + mf, err := mfer.NewFromPaths(opts, paths...) if err != nil { panic(err) } + mf.WithContext(ctx.Context) - spew.Dump(mf) + log.Dump(mf) + err = mf.Scan() + if err != nil { + return err + } + + buf := new(bytes.Buffer) + + err = mf.WriteTo(buf) + if err != nil { + return err + } + + dat := buf.Bytes() + + log.Dump(dat) return nil } diff --git a/internal/cli/mfer.go b/internal/cli/mfer.go index af7ed40..9f85ae1 100644 --- a/internal/cli/mfer.go +++ b/internal/cli/mfer.go @@ -5,9 +5,7 @@ import ( "os" "time" - log "github.com/visionmedia/go-cli-log" - - "github.com/pterm/pterm" + "git.eeqj.de/sneak/mfer/internal/log" "github.com/urfave/cli/v2" ) @@ -20,34 +18,47 @@ type CLIApp struct { app *cli.App } -func (mfa *CLIApp) printBanner() { - s, _ := pterm.DefaultBigText.WithLetters(pterm.NewLettersFromString(mfa.appname)).Srender() - pterm.DefaultCenter.Println(s) // Print BigLetters with the default CenterPrinter -} +const banner = ` ___ ___ ___ ___ + /__/\ / /\ / /\ / /\ + | |::\ / /:/_ / /:/_ / /::\ + | |:|:\ / /:/ /\ / /:/ /\ / /:/\:\ + __|__|:|\:\ / /:/ /:/ / /:/ /:/_ / /:/~/:/ + /__/::::| \:\ /__/:/ /:/ /__/:/ /:/ /\ /__/:/ /:/___ + \ \:\~~\__\/ \ \:\/:/ \ \:\/:/ /:/ \ \:\/:::::/ + \ \:\ \ \::/ \ \::/ /:/ \ \::/~~~~ + \ \:\ \ \:\ \ \:\/:/ \ \:\ + \ \:\ \ \:\ \ \::/ \ \:\ + \__\/ \__\/ \__\/ \__\/` -func (mfa *CLIApp) disableStyling() { - pterm.DisableColor() - pterm.DisableStyling() - pterm.Debug.Prefix.Text = "" - pterm.Info.Prefix.Text = "" - pterm.Success.Prefix.Text = "" - pterm.Warning.Prefix.Text = "" - pterm.Error.Prefix.Text = "" - pterm.Fatal.Prefix.Text = "" +func (mfa *CLIApp) printBanner() { + fmt.Println(banner) } func (mfa *CLIApp) VersionString() string { return fmt.Sprintf("%s (%s)", mfa.version, mfa.gitrev) } +func (mfa *CLIApp) setVerbosity(v int) { + _, present := os.LookupEnv("MFER_DEBUG") + if present { + log.EnableDebugLogging() + } else { + log.SetLevelFromVerbosity(v) + } +} + func (mfa *CLIApp) run() { mfa.startupTime = time.Now() if NO_COLOR { // shoutout to rob pike who thinks it's juvenile - mfa.disableStyling() + log.DisableStyling() } + log.Init() + + var verbosity int + mfa.app = &cli.App{ Name: mfa.appname, Usage: "Manifest generator", @@ -58,6 +69,7 @@ func (mfa *CLIApp) run() { Name: "verbose", Usage: "Verbosity level", Aliases: []string{"v"}, + Count: &verbosity, }, &cli.BoolFlag{ Name: "quiet", @@ -74,6 +86,7 @@ func (mfa *CLIApp) run() { if !c.Bool("quiet") { mfa.printBanner() } + mfa.setVerbosity(verbosity) return mfa.generateManifestOperation(c) }, Flags: []cli.Flag{ @@ -87,13 +100,6 @@ func (mfa *CLIApp) run() { Aliases: []string{"ignore-dotfiles"}, Usage: "Ignore any dot (hidden) files encountered", }, - // FIXME this should be a positional arg - &cli.StringFlag{ - Name: "input", - Value: ".", - Aliases: []string{"i"}, - Usage: "Specify input directory.", - }, &cli.StringFlag{ Name: "output", Value: "./index.mf", @@ -109,6 +115,7 @@ func (mfa *CLIApp) run() { if !c.Bool("quiet") { mfa.printBanner() } + mfa.setVerbosity(verbosity) return mfa.checkManifestOperation(c) }, }, @@ -127,6 +134,7 @@ func (mfa *CLIApp) run() { if !c.Bool("quiet") { mfa.printBanner() } + mfa.setVerbosity(verbosity) return mfa.fetchManifestOperation(c) }, }, @@ -137,6 +145,6 @@ func (mfa *CLIApp) run() { err := mfa.app.Run(os.Args) if err != nil { mfa.exitCode = 1 - log.Error(err) + log.WithError(err).Debugf("exiting") } } diff --git a/internal/log/log.go b/internal/log/log.go new file mode 100644 index 0000000..b52409b --- /dev/null +++ b/internal/log/log.go @@ -0,0 +1,89 @@ +package log + +import ( + "fmt" + "runtime" + + "github.com/apex/log" + acli "github.com/apex/log/handlers/cli" + "github.com/davecgh/go-spew/spew" + "github.com/pterm/pterm" +) + +type Level = log.Level + +func DisableStyling() { + pterm.DisableColor() + pterm.DisableStyling() + pterm.Debug.Prefix.Text = "" + pterm.Info.Prefix.Text = "" + pterm.Success.Prefix.Text = "" + pterm.Warning.Prefix.Text = "" + pterm.Error.Prefix.Text = "" + pterm.Fatal.Prefix.Text = "" +} + +func Init() { + log.SetHandler(acli.Default) + log.SetLevel(log.InfoLevel) +} + +func Debugf(format string, args ...interface{}) { + DebugReal(fmt.Sprintf(format, args...), 2) +} + +func Debug(arg string) { + DebugReal(arg, 2) +} + +func DebugReal(arg string, cs int) { + _, callerFile, callerLine, ok := runtime.Caller(cs) + if !ok { + return + } + tag := fmt.Sprintf("%s:%d: ", callerFile, callerLine) + log.Debug(tag + arg) +} + +func Dump(args ...interface{}) { + DebugReal(spew.Sdump(args...), 2) +} + +func EnableDebugLogging() { + SetLevel(log.DebugLevel) +} + +func VerbosityStepsToLogLevel(l int) log.Level { + switch l { + case 1: + return log.WarnLevel + case 2: + return log.InfoLevel + case 3: + return log.DebugLevel + } + return log.ErrorLevel +} + +func SetLevelFromVerbosity(l int) { + SetLevel(VerbosityStepsToLogLevel(l)) +} + +func SetLevel(arg log.Level) { + log.SetLevel(arg) +} + +func GetLogger() *log.Logger { + if logger, ok := log.Log.(*log.Logger); ok { + return logger + } + panic("unable to get logger") +} + +func GetLevel() log.Level { + return GetLogger().Level +} + +func WithError(e error) *log.Entry { + return GetLogger().WithError(e) +} diff --git a/internal/log/log_test.go b/internal/log/log_test.go new file mode 100644 index 0000000..b36c642 --- /dev/null +++ b/internal/log/log_test.go @@ -0,0 +1,12 @@ +package log + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBuild(t *testing.T) { + Init() + assert.True(t, true) +} diff --git a/mfer/deserialize.go b/mfer/deserialize.go new file mode 100644 index 0000000..85ff318 --- /dev/null +++ b/mfer/deserialize.go @@ -0,0 +1,89 @@ +package mfer + +import ( + "bytes" + "compress/gzip" + "errors" + "io" + + "git.eeqj.de/sneak/mfer/internal/bork" + "git.eeqj.de/sneak/mfer/internal/log" + "google.golang.org/protobuf/proto" +) + +func (m *manifest) validateProtoOuter() error { + if m.pbOuter.Version != MFFileOuter_VERSION_ONE { + return errors.New("unknown version") + } + if m.pbOuter.CompressionType != MFFileOuter_COMPRESSION_GZIP { + return errors.New("unknown compression type") + } + + bb := bytes.NewBuffer(m.pbOuter.InnerMessage) + + gzr, err := gzip.NewReader(bb) + if err != nil { + return err + } + + dat, err := io.ReadAll(gzr) + defer gzr.Close() + + if err != nil { + return err + } + + isize := len(dat) + if int64(isize) != m.pbOuter.Size { + log.Debugf("truncated data, got %d expected %d", isize, m.pbOuter.Size) + return bork.ErrFileTruncated + } + log.Debugf("inner data size is %d", isize) + log.Dump(dat) + log.Dump(m.pbOuter.Sha256) + return nil +} + +func validateMagic(dat []byte) bool { + ml := len([]byte(MAGIC)) + if len(dat) < ml { + return false + } + got := dat[0:ml] + expected := []byte(MAGIC) + return bytes.Equal(got, expected) +} + +func NewFromProto(input io.Reader) (*manifest, error) { + m := New() + dat, err := io.ReadAll(input) + if err != nil { + return nil, err + } + if !validateMagic(dat) { + return nil, errors.New("invalid file format") + } + + // remove magic bytes prefix: + ml := len([]byte(MAGIC)) + bb := bytes.NewBuffer(dat[ml:]) + dat = bb.Bytes() + + log.Dump(dat) + + // deserialize: + m.pbOuter = new(MFFileOuter) + err = proto.Unmarshal(dat, m.pbOuter) + + if err != nil { + return nil, err + } + + ve := m.validateProtoOuter() + if ve != nil { + return nil, ve + } + + // FIXME TODO deserialize inner + return m, nil +} diff --git a/mfer/example_test.go b/mfer/example_test.go new file mode 100644 index 0000000..af4164b --- /dev/null +++ b/mfer/example_test.go @@ -0,0 +1,42 @@ +package mfer + +import ( + "bytes" + "testing" + + "git.eeqj.de/sneak/mfer/internal/log" + "github.com/stretchr/testify/assert" +) + +func TestAPIExample(t *testing.T) { + // read from filesystem + m, err := NewFromFS(&ManifestScanOptions{ + IgnoreDotfiles: true, + }, big) + assert.Nil(t, err) + assert.NotNil(t, m) + + // scan for files + m.Scan() + + // serialize + var buf bytes.Buffer + m.WriteTo(&buf) + + // show serialized + log.Dump(buf.Bytes()) + + // do it again + var buf2 bytes.Buffer + m.WriteTo(&buf2) + + // should be same! + assert.True(t, bytes.Equal(buf.Bytes(), buf2.Bytes())) + + // deserialize + m2, err := NewFromProto(&buf) + assert.Nil(t, err) + assert.NotNil(t, m2) + + log.Dump(m2) +} diff --git a/mfer/gen.go b/mfer/gen.go deleted file mode 100644 index 3e68f5f..0000000 --- a/mfer/gen.go +++ /dev/null @@ -1,3 +0,0 @@ -package mfer - -//go:generate protoc --go_out=. --go_opt=paths=source_relative mf.proto diff --git a/mfer/manifest.go b/mfer/manifest.go index 6499d7a..d85e5c5 100644 --- a/mfer/manifest.go +++ b/mfer/manifest.go @@ -1,35 +1,42 @@ package mfer import ( + "bytes" + "context" + "errors" "fmt" - "io" "io/fs" - "os" + "path" "path/filepath" "strings" + "git.eeqj.de/sneak/mfer/internal/log" "github.com/spf13/afero" ) -type ManifestFile struct { - Path string - FileInfo fs.FileInfo +type manifestFile struct { + path string + info fs.FileInfo } -func (m *ManifestFile) String() string { - return fmt.Sprintf("", m.Path) +func (m *manifestFile) String() string { + return fmt.Sprintf("", m.path) } -type Manifest struct { - SourceFS afero.Fs - SourceFSRoot string - Files []*ManifestFile - ScanOptions *ManifestScanOptions - TotalFileSize int64 +type manifest struct { + sourceFS []afero.Fs + files []*manifestFile + scanOptions *ManifestScanOptions + totalFileSize int64 + pbInner *MFFile + pbOuter *MFFileOuter + output *bytes.Buffer + ctx context.Context + errors []*error } -func (m *Manifest) String() string { - return fmt.Sprintf("", len(m.Files), m.TotalFileSize) +func (m *manifest) String() string { + return fmt.Sprintf("", len(m.files), m.totalFileSize) } type ManifestScanOptions struct { @@ -37,78 +44,130 @@ type ManifestScanOptions struct { FollowSymLinks bool } -func NewFromPath(inputPath string, options *ManifestScanOptions) (*Manifest, error) { +func (m *manifest) HasError() bool { + return len(m.errors) > 0 +} + +func (m *manifest) AddError(e error) *manifest { + m.errors = append(m.errors, &e) + return m +} + +func (m *manifest) WithContext(c context.Context) *manifest { + m.ctx = c + return m +} + +func (m *manifest) addInputPath(inputPath string) error { abs, err := filepath.Abs(inputPath) - if err != nil { - return nil, err - } - afs := afero.NewBasePathFs(afero.NewOsFs(), abs) - m, err := NewFromFS(afs, options) - if err != nil { - return nil, err - } - m.SourceFSRoot = abs - return m, nil -} - -func NewFromFS(fs afero.Fs, options *ManifestScanOptions) (*Manifest, error) { - m := &Manifest{ - SourceFS: fs, - ScanOptions: options, - } - err := m.Scan() - if err != nil { - return nil, err - } - return m, nil -} - -func (m *Manifest) Scan() error { - // FIXME scan and whatever function does the hashing should take ctx - oe := afero.Walk(m.SourceFS, "./", func(path string, info fs.FileInfo, err error) error { - if m.ScanOptions.IgnoreDotfiles && strings.HasPrefix(path, ".") { - // FIXME make this check all path components BUG - return nil - } - - if info != nil && info.IsDir() { - // manifests contain only files, directories are implied. - return nil - } - - fileinfo, staterr := m.SourceFS.Stat(path) - if staterr != nil { - panic(staterr) - } - - nf := &ManifestFile{ - Path: path, - FileInfo: fileinfo, - } - m.Files = append(m.Files, nf) - m.TotalFileSize = m.TotalFileSize + info.Size() - return nil - }) - if oe != nil { - return oe - } - return nil -} - -func (m *Manifest) WriteToFile(path string) error { - // FIXME refuse to overwrite without -f if file exists - - f, err := os.Create(path) if err != nil { return err } - defer f.Close() - - return m.Write(f) + // FIXME check to make sure inputPath/abs exists maybe + afs := afero.NewReadOnlyFs(afero.NewBasePathFs(afero.NewOsFs(), abs)) + return m.addInputFS(afs) } -func (m *Manifest) Write(output io.Writer) error { - // FIXME implement - panic("nope") - return nil // nolint:all +func (m *manifest) addInputFS(f afero.Fs) error { + if m.sourceFS == nil { + m.sourceFS = make([]afero.Fs, 0) + } + m.sourceFS = append(m.sourceFS, f) + // FIXME do some sort of check on f here? + return nil +} + +func New() *manifest { + m := &manifest{} + return m +} + +func NewFromPaths(options *ManifestScanOptions, inputPaths ...string) (*manifest, error) { + log.Dump(inputPaths) + m := New() + m.scanOptions = options + for _, p := range inputPaths { + err := m.addInputPath(p) + if err != nil { + return nil, err + } + } + return m, nil +} + +func NewFromFS(options *ManifestScanOptions, fs afero.Fs) (*manifest, error) { + m := New() + m.scanOptions = options + err := m.addInputFS(fs) + if err != nil { + return nil, err + } + return m, nil +} + +func (m *manifest) GetFileCount() int64 { + return int64(len(m.files)) +} + +func (m *manifest) GetTotalFileSize() int64 { + return m.totalFileSize +} + +func pathIsHidden(p string) bool { + tp := path.Clean(p) + if strings.HasPrefix(tp, ".") { + return true + } + for { + d, f := path.Split(tp) + if strings.HasPrefix(f, ".") { + return true + } + if d == "" { + return false + } + tp = d[0 : len(d)-1] // trim trailing slash from dir + } +} + +func (m *manifest) addFile(p string, fi fs.FileInfo, sfsIndex int) error { + if m.scanOptions.IgnoreDotfiles && pathIsHidden(p) { + return nil + } + if fi != nil && fi.IsDir() { + // manifests contain only files, directories are implied. + return nil + } + // FIXME test if 'fi' is already result of stat + fileinfo, staterr := m.sourceFS[sfsIndex].Stat(p) + if staterr != nil { + return staterr + } + cleanPath := p + if cleanPath[0:1] == "/" { + cleanPath = cleanPath[1:] + } + nf := &manifestFile{ + path: cleanPath, + info: fileinfo, + } + m.files = append(m.files, nf) + m.totalFileSize = m.totalFileSize + fi.Size() + return nil +} + +func (m *manifest) Scan() error { + // FIXME scan and whatever function does the hashing should take ctx + for idx, sfs := range m.sourceFS { + if sfs == nil { + return errors.New("invalid source fs") + } + e := afero.Walk(sfs, "/", func(p string, info fs.FileInfo, err error) error { + return m.addFile(p, info, idx) + }) + if e != nil { + return e + } + } + return nil } diff --git a/mfer/mf.proto b/mfer/mf.proto index a6ba326..ebac757 100644 --- a/mfer/mf.proto +++ b/mfer/mf.proto @@ -1,26 +1,34 @@ syntax = "proto3"; -option go_package = "git.eeqj.de/sneak/mfer"; +option go_package = "git.eeqj.de/sneak/mfer/mfer"; message Timestamp { int64 seconds = 1; int32 nanos = 2; } -message MFFile { +message MFFileOuter { enum Version { - NONE = 0; - ONE = 1; // only one for now + VERSION_NONE = 0; + VERSION_ONE = 1; // only one for now } // required mffile root attributes 1xx Version version = 101; - bytes innerMessage = 102; + + enum CompressionType { + COMPRESSION_NONE = 0; + COMPRESSION_GZIP = 1; + } + + CompressionType compressionType = 102; + // these are used solely to detect corruption/truncation // and not for cryptographic integrity. int64 size = 103; bytes sha256 = 104; + bytes innerMessage = 199; // 2xx for optional manifest root attributes // think we might use gosignify instead of gpg: // github.com/frankbraun/gosignify @@ -54,10 +62,10 @@ message MFFileChecksum { bytes multiHash = 1; } -message MFFileInner { +message MFFile { enum Version { - NONE = 0; - ONE = 1; // only one for now + VERSION_NONE = 0; + VERSION_ONE = 1; // only one for now } Version version = 100; diff --git a/mfer/mfer_test.go b/mfer/mfer_test.go index 9b5c284..18858a6 100644 --- a/mfer/mfer_test.go +++ b/mfer/mfer_test.go @@ -1,12 +1,74 @@ package mfer -import "testing" +import ( + "bytes" + "fmt" + "testing" + + "git.eeqj.de/sneak/mfer/internal/log" + "github.com/spf13/afero" + "github.com/stretchr/testify/assert" +) // Add those variables as well var ( - existingFolder = "./testdata/a-folder-that-exists" - nonExistingFolder = "./testdata/a-folder-that-does-not-exists" + existingFolder = "./testdata/a-folder-that-exists" ) -func TestManifestGeneration(t *testing.T) { +var ( + af *afero.Afero = &afero.Afero{Fs: afero.NewMemMapFs()} + big *afero.Afero = &afero.Afero{Fs: afero.NewMemMapFs()} +) + +func init() { + log.EnableDebugLogging() + + // create test files and directories + af.MkdirAll("/a/b/c", 0o755) + af.MkdirAll("/.hidden", 0o755) + af.WriteFile("/a/b/c/hello.txt", []byte("hello world\n\n\n\n"), 0o755) + af.WriteFile("/a/b/c/hello2.txt", []byte("hello world\n\n\n\n"), 0o755) + af.WriteFile("/.hidden/hello.txt", []byte("hello world\n"), 0o755) + af.WriteFile("/.hidden/hello2.txt", []byte("hello world\n"), 0o755) + + big.MkdirAll("/home/user/Library", 0o755) + for i := range [25]int{} { + big.WriteFile(fmt.Sprintf("/home/user/Library/hello%d.txt", i), []byte("hello world\n"), 0o755) + } +} + +func TestPathHiddenFunc(t *testing.T) { + assert.False(t, pathIsHidden("/a/b/c/hello.txt")) + assert.True(t, pathIsHidden("/a/b/c/.hello.txt")) + assert.True(t, pathIsHidden("/a/.b/c/hello.txt")) + assert.True(t, pathIsHidden("/.a/b/c/hello.txt")) + assert.False(t, pathIsHidden("./a/b/c/hello.txt")) +} + +func TestManifestGenerationOne(t *testing.T) { + m, err := NewFromFS(&ManifestScanOptions{ + IgnoreDotfiles: true, + }, af) + assert.Nil(t, err) + assert.NotNil(t, m) + m.Scan() + assert.Equal(t, int64(2), m.GetFileCount()) + assert.Equal(t, int64(30), m.GetTotalFileSize()) +} + +func TestManifestGenerationTwo(t *testing.T) { + m, err := NewFromFS(&ManifestScanOptions{ + IgnoreDotfiles: false, + }, af) + assert.Nil(t, err) + assert.NotNil(t, m) + m.Scan() + assert.Equal(t, int64(4), m.GetFileCount()) + assert.Equal(t, int64(54), m.GetTotalFileSize()) + err = m.generate() + assert.Nil(t, err) + var buf bytes.Buffer + err = m.WriteTo(&buf) + assert.Nil(t, err) + log.Dump(buf.Bytes()) } diff --git a/mfer/output.go b/mfer/output.go new file mode 100644 index 0000000..5292767 --- /dev/null +++ b/mfer/output.go @@ -0,0 +1,33 @@ +package mfer + +import ( + "io" + "os" +) + +func (m *manifest) WriteToFile(path string) error { + // FIXME refuse to overwrite without -f if file exists + + f, err := os.Create(path) + if err != nil { + return err + } + defer f.Close() + + return m.WriteTo(f) +} + +func (m *manifest) WriteTo(output io.Writer) error { + if m.pbOuter == nil { + err := m.generate() + if err != nil { + return err + } + } + + _, err := output.Write(m.output.Bytes()) + if err != nil { + return err + } + return nil +} diff --git a/mfer/serialize.go b/mfer/serialize.go new file mode 100644 index 0000000..00e8a5e --- /dev/null +++ b/mfer/serialize.go @@ -0,0 +1,100 @@ +package mfer + +import ( + "bytes" + "compress/gzip" + "crypto/sha256" + "errors" + "time" + + "google.golang.org/protobuf/proto" +) + +//go:generate protoc --go_out=. --go_opt=paths=source_relative mf.proto + +// rot13("MANIFEST") +const MAGIC string = "ZNAVSRFG" + +func newTimestampFromTime(t time.Time) *Timestamp { + out := &Timestamp{ + Seconds: t.Unix(), + Nanos: int32(t.UnixNano() - (t.Unix() * 1000000000)), + } + return out +} + +func (m *manifest) generate() error { + if m.pbInner == nil { + e := m.generateInner() + if e != nil { + return e + } + } + if m.pbOuter == nil { + e := m.generateOuter() + if e != nil { + return e + } + } + dat, err := proto.MarshalOptions{Deterministic: true}.Marshal(m.pbOuter) + if err != nil { + return err + } + m.output = bytes.NewBuffer([]byte(MAGIC)) + _, err = m.output.Write(dat) + if err != nil { + return err + } + return nil +} + +func (m *manifest) generateOuter() error { + if m.pbInner == nil { + return errors.New("internal error") + } + innerData, err := proto.MarshalOptions{Deterministic: true}.Marshal(m.pbInner) + if err != nil { + return err + } + + h := sha256.New() + h.Write(innerData) + + idc := new(bytes.Buffer) + gzw, err := gzip.NewWriterLevel(idc, gzip.BestCompression) + if err != nil { + return err + } + _, err = gzw.Write(innerData) + if err != nil { + return err + } + + gzw.Close() + + o := &MFFileOuter{ + InnerMessage: idc.Bytes(), + Size: int64(len(innerData)), + Sha256: h.Sum(nil), + Version: MFFileOuter_VERSION_ONE, + CompressionType: MFFileOuter_COMPRESSION_GZIP, + } + m.pbOuter = o + return nil +} + +func (m *manifest) generateInner() error { + m.pbInner = &MFFile{ + Version: MFFile_VERSION_ONE, + CreatedAt: newTimestampFromTime(time.Now()), + Files: []*MFFilePath{}, + } + for _, f := range m.files { + nf := &MFFilePath{ + Path: f.path, + // FIXME add more stuff + } + m.pbInner.Files = append(m.pbInner.Files, nf) + } + return nil +} diff --git a/modcache.tzst b/modcache.tzst new file mode 100644 index 0000000..0be2836 Binary files /dev/null and b/modcache.tzst differ diff --git a/vendor.tzst b/vendor.tzst new file mode 100644 index 0000000..9f63bca Binary files /dev/null and b/vendor.tzst differ