Rewrite Makefile with required policy targets

test/lint/fmt/fmt-check/check/docker/hooks plus build, all, and clean.
make check no longer builds the binary (it must not modify files); the
test target uses the 30s-timeout conditional -v rerun pattern. Version
is injected via -ldflags and exposed as sfdupes --version.
This commit is contained in:
2026-07-23 05:37:29 +07:00
parent 065a533224
commit 316ea9072d
2 changed files with 44 additions and 10 deletions

View File

@@ -2,16 +2,43 @@
# toolchain. # toolchain.
export CGO_ENABLED = 0 export CGO_ENABLED = 0
.PHONY: all build check clean BINARY := sfdupes
VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo dev)
LDFLAGS := -X main.Version=$(VERSION)
all: build .PHONY: all build test lint fmt fmt-check check docker hooks clean
all: check build
build: build:
go build go build -ldflags "$(LDFLAGS)" -o $(BINARY)
check: build test:
test -z "$$(gofmt -l .)" @go test -timeout 30s -cover ./... || \
go vet ./... { echo "--- Rerunning with -v for details ---"; \
go test -timeout 30s -v ./...; exit 1; }
lint:
golangci-lint run --config .golangci.yml ./...
fmt:
gofmt -s -w .
fmt-check:
@files="$$(gofmt -l -s .)"; if [ -n "$$files" ]; then \
echo "gofmt: files not formatted:"; echo "$$files"; exit 1; fi
check: test lint fmt-check
docker:
docker build -t $(BINARY) .
hooks:
@printf '#!/bin/sh\nset -e\n' > .git/hooks/pre-commit
@printf 'go mod tidy\ngo fmt ./...\n' >> .git/hooks/pre-commit
@printf 'git diff --exit-code -- go.mod go.sum || { echo "go mod tidy changed files; please stage and retry"; exit 1; }\n' >> .git/hooks/pre-commit
@printf 'make check\n' >> .git/hooks/pre-commit
@chmod +x .git/hooks/pre-commit
clean: clean:
rm -f sfdupes files.dat rm -f $(BINARY) files.dat

13
main.go
View File

@@ -27,11 +27,18 @@ const (
exitUsage = 2 exitUsage = 2
) )
// Version is the build version, injected at link time via -ldflags
// (see the Makefile); "dev" for a plain go build.
//
//nolint:gochecknoglobals // written only by the linker
var Version = "dev"
func main() { func main() {
root := &cobra.Command{ root := &cobra.Command{
Use: "sfdupes", Use: "sfdupes",
Short: "Find candidate duplicate files by size and head/tail SHA-256", Short: "Find candidate duplicate files by size and head/tail SHA-256",
Args: cobra.NoArgs, Version: Version,
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, _ []string) { Run: func(cmd *cobra.Command, _ []string) {
// A missing subcommand prints usage and exits 2. // A missing subcommand prints usage and exits 2.
_ = cmd.Usage() _ = cmd.Usage()