diff --git a/.dockerignore b/.dockerignore index 90beabd..ec18f8e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -59,6 +59,5 @@ **/.vscode **/*.sublime-* -# This repo's own host-built archives (Makefile). -*.tmp -*.dockerimage +# This repo's own host-built binary (make build). +/bin/mfer diff --git a/.gitignore b/.gitignore index 94cf6c9..92f3769 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,6 @@ /bin/mfer /tmp /node_modules/ -*.tmp -*.dockerimage -/vendor -vendor.tzst -modcache.tzst # Generated manifest files /index.mf diff --git a/Dockerfile b/Dockerfile index 5110e92..b5c26f9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,7 @@ COPY . . # Go half of fmt-check only: this image has no node, so no prettier. The # markdown half runs in the mdfmt stage below. The image has no gofumpt # either; script/gofumpt builds the version it pins with `go run`. -RUN make fmt-check-go +RUN script/gofumpt --check # The linter directly, not `make lint`: script/lint builds this stage, and # there is no docker inside this build. RUN golangci-lint run --config .golangci.yml ./... diff --git a/Makefile b/Makefile index fc8f6eb..398f552 100644 --- a/Makefile +++ b/Makefile @@ -1,20 +1,8 @@ -export DOCKER_BUILDKIT := 1 -export PROGRESS_NO_TRUNC := 1 -GOPATH := $(shell go env GOPATH) -export PATH := $(PATH):$(GOPATH)/bin -SOURCEFILES := mfer/*.go mfer/*.proto internal/*/*.go cmd/*/*.go go.mod go.sum -ARCH := $(shell uname -m) -GITREV_BUILD := $(shell bash $(PWD)/bin/gitrev.sh 2>/dev/null || echo unknown) -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)" +.PHONY: bootstrap setup test lint fmt fmt-check check docker hooks build generate fuzz -.PHONY: bootstrap setup docker default run ci test fuzz check lint fmt fmt-check fmt-check-go fmt-check-md hooks fixme generate - -default: fmt test +# Makefile targets are thin shims; the implementations live in script/ +# per the scripts-to-rule-them-all pattern (see the Entrypoints section +# of README.md). bootstrap: @script/bootstrap @@ -22,75 +10,32 @@ bootstrap: setup: @script/setup -run: ./bin/mfer - ./$< - ./$< gen - -ci: test - test: @script/test -fuzz: - @script/fuzz - -fixme: - @grep -nir fixme . | grep -v Makefile - -check: - @script/check - -fmt-check: - @script/fmt-check - -# Halves of fmt-check, for environments that have only one toolchain: -# the Docker lint stage has Go but no node, the markdown stage the reverse. -fmt-check-go: - @script/gofumpt --check - -fmt-check-md: - @script/prettier --check - -hooks: - @script/install-precommit - -generate: - @script/generate - -bin/mfer: $(SOURCEFILES) - cd cmd/mfer && go build -tags urfave_cli_no_docs -o ../../bin/mfer $(GOFLAGS) . - -clean: - rm -rfv bin/mfer cmd/mfer/mfer *.dockerimage - -fmt: - @script/fmt - lint: @script/lint +fmt: + @script/fmt + +fmt-check: + @script/fmt-check + +check: + @script/check + docker: @script/docker -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 $@ +hooks: + @script/install-precommit -godoc: - open http://127.0.0.1:6060 - godoc -http=:6060 +build: + @script/build -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 $@ +generate: + @script/generate -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 $@ +fuzz: + @script/fuzz diff --git a/README.md b/README.md index 9d86d7f..2c18677 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ is committed, so no `protoc` toolchain is required: ```sh git clone https://git.eeqj.de/sneak/mfer.git cd mfer -go build -o bin/mfer ./cmd/mfer +make build ``` Generate a manifest for a directory tree, verify it later, and fetch a published @@ -74,6 +74,9 @@ provide: such as `script/docker` - `script/test` — run the test suite (`go test`); one test fails when `mfer/mf.proto` no longer matches the hash `script/generate` recorded +- `script/build` (`make build`) — build the `mfer` binary into `bin/mfer`, + stamped with the revision `mfer version` prints: the output of + `git describe --tags --always --dirty`, as `script/docker` passes it - `script/generate` (`make generate`) — regenerate `mfer/mf.pb.go` from `mfer/mf.proto` and record the hash of that `mfer/mf.proto` in `mfer/mf.proto.sha256`; the only thing that regenerates the committed @@ -83,8 +86,8 @@ provide: [its release](https://github.com/protocolbuffers/protobuf/releases/tag/v33.4) and put its `bin/protoc` on `PATH`) and `protoc-gen-go` v1.36.11 (`go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.36.11`, which - installs it in `$(go env GOPATH)/bin`; `make generate` adds that directory to - `PATH`) + installs it in `$(go env GOPATH)/bin`; `script/generate` adds that directory + to `PATH`) - `script/fuzz` — fuzz the manifest parser for one minute; run by hand (`make fuzz`), never by CI, while `script/test` runs its committed seed corpus as ordinary tests @@ -96,8 +99,8 @@ provide: - `script/gofumpt` — run `gofumpt` over every Go file in the repository in the given mode, `--write` or `--check`, at the one version it pins (built on demand by `go run`, so nothing installs it); `script/fmt`, `script/fmt-check` - and the Docker lint stage (`make fmt-check-go`) all go through it, so they - cannot disagree about Go formatting + and the Docker lint stage all go through it, so they cannot disagree about Go + formatting - `script/prettier` — run prettier over the repository's canonical file set (Markdown and JSON, minus `.prettierignore`) in the given mode, `--write` or `--check`; the single definition of that file set, so `script/fmt` and diff --git a/bin/gitrev.sh b/bin/gitrev.sh deleted file mode 100644 index ab0821c..0000000 --- a/bin/gitrev.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -main() { - if [[ -n "${GITREV:-}" ]]; then - echo "$GITREV" - else - git describe --tags --always --dirty=-dirty - fi -} - -main "$@" diff --git a/script/build b/script/build new file mode 100755 index 0000000..3e2bd02 --- /dev/null +++ b/script/build @@ -0,0 +1,20 @@ +#!/bin/sh +# script/build: build the mfer binary into bin/mfer, stamped with the +# revision `mfer version` prints, derived as script/docker derives it. +set -eu + +ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" + +main() { + cd "$ROOT" + # Own line: a failing command substitution inside an argument does + # not trip `set -e`, so the inline form degrades silently to an + # empty constant. + version="$(git describe --tags --always --dirty 2>/dev/null || true)" + [ -n "$version" ] || version="unknown" + go build -tags urfave_cli_no_docs \ + -ldflags "-X main.Gitrev=$version" \ + -o bin/mfer ./cmd/mfer +} + +main "$@" diff --git a/script/generate b/script/generate index 6d5c649..4ee62ff 100755 --- a/script/generate +++ b/script/generate @@ -40,6 +40,9 @@ sha256() { main() { cd "$ROOT/mfer" + # `go install` puts protoc-gen-go in $(go env GOPATH)/bin, which is + # often not on PATH. + PATH="$PATH:$(go env GOPATH)/bin" require_version protoc "libprotoc $PROTOC_VERSION" require_version protoc-gen-go "protoc-gen-go $PROTOC_GEN_GO_VERSION" # Hashed before regenerating, so a missing hash tool stops the script diff --git a/script/gofumpt b/script/gofumpt index 66dba19..1622d46 100755 --- a/script/gofumpt +++ b/script/gofumpt @@ -4,8 +4,8 @@ # Takes exactly one mode argument, --write or --check, and runs the same # gofumpt version over the same files in both modes. script/fmt and # script/fmt-check both go through here, and so does the Docker lint -# stage (make fmt-check-go), so what gets formatted and what gets -# verified cannot drift apart. +# stage, so what gets formatted and what gets verified cannot drift +# apart. set -eu ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"