mirror of
https://github.com/cheat/cheat.git
synced 2026-03-07 03:03:32 +01:00
Bug fixes: - Fix inverted pager detection logic (returned error instead of path) - Fix repo.Clone ignoring destination directory parameter - Fix sheet loading using append on pre-sized slices - Clean up partial files on copy failure - Trim whitespace from editor config Security: - Add path traversal protection for cheatsheet names Performance: - Move regex compilation outside search loop - Replace string concatenation with strings.Join in search Build: - Remove go:generate; embed config and usage as string literals - Parallelize release builds - Add fuzz testing infrastructure Testing: - Improve test coverage from 38.9% to 50.2% - Add fuzz tests for search, filter, tags, and validation Documentation: - Fix inaccurate code examples in HACKING.md - Add missing --conf and --all options to man page - Add ADRs for path traversal, env parsing, and search parallelization - Update CONTRIBUTING.md to reflect project policy Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
286 lines
7.6 KiB
Makefile
286 lines
7.6 KiB
Makefile
# paths
|
|
makefile := $(realpath $(lastword $(MAKEFILE_LIST)))
|
|
cmd_dir := ./cmd/cheat
|
|
dist_dir := ./dist
|
|
|
|
# parallel jobs for build-release (can be overridden)
|
|
JOBS ?= 8
|
|
|
|
# executables
|
|
CAT := cat
|
|
COLUMN := column
|
|
CTAGS := ctags
|
|
DOCKER := docker
|
|
GO := go
|
|
GREP := grep
|
|
GZIP := gzip --best
|
|
LINT := revive
|
|
MAN := man
|
|
MKDIR := mkdir -p
|
|
PANDOC := pandoc
|
|
RM := rm
|
|
SCC := scc
|
|
SED := sed
|
|
SORT := sort
|
|
ZIP := zip -m
|
|
|
|
docker_image := cheat-devel:latest
|
|
|
|
# build flags
|
|
BUILD_FLAGS := -ldflags="-s -w" -mod vendor -trimpath
|
|
GOBIN :=
|
|
TMPDIR := /tmp
|
|
|
|
# release binaries
|
|
releases := \
|
|
$(dist_dir)/cheat-darwin-amd64 \
|
|
$(dist_dir)/cheat-darwin-arm64 \
|
|
$(dist_dir)/cheat-linux-386 \
|
|
$(dist_dir)/cheat-linux-amd64 \
|
|
$(dist_dir)/cheat-linux-arm5 \
|
|
$(dist_dir)/cheat-linux-arm6 \
|
|
$(dist_dir)/cheat-linux-arm64 \
|
|
$(dist_dir)/cheat-linux-arm7 \
|
|
$(dist_dir)/cheat-netbsd-amd64 \
|
|
$(dist_dir)/cheat-openbsd-amd64 \
|
|
$(dist_dir)/cheat-solaris-amd64 \
|
|
$(dist_dir)/cheat-windows-amd64.exe
|
|
|
|
## build: build an executable for your architecture
|
|
.PHONY: build
|
|
build: | clean $(dist_dir) fmt lint vet vendor man
|
|
$(GO) build $(BUILD_FLAGS) -o $(dist_dir)/cheat $(cmd_dir)
|
|
|
|
## build-release: build release executables
|
|
# Runs prepare once, then builds all binaries in parallel
|
|
# Override jobs with: make build-release JOBS=16
|
|
.PHONY: build-release
|
|
build-release: prepare
|
|
$(MAKE) -j$(JOBS) $(releases)
|
|
|
|
# cheat-darwin-amd64
|
|
$(dist_dir)/cheat-darwin-amd64:
|
|
GOARCH=amd64 GOOS=darwin \
|
|
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(GZIP) $@ && chmod -x $@.gz
|
|
|
|
# cheat-darwin-arm64
|
|
$(dist_dir)/cheat-darwin-arm64:
|
|
GOARCH=arm64 GOOS=darwin \
|
|
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(GZIP) $@ && chmod -x $@.gz
|
|
|
|
# cheat-linux-386
|
|
$(dist_dir)/cheat-linux-386:
|
|
GOARCH=386 GOOS=linux \
|
|
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(GZIP) $@ && chmod -x $@.gz
|
|
|
|
# cheat-linux-amd64
|
|
$(dist_dir)/cheat-linux-amd64:
|
|
GOARCH=amd64 GOOS=linux \
|
|
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(GZIP) $@ && chmod -x $@.gz
|
|
|
|
# cheat-linux-arm5
|
|
$(dist_dir)/cheat-linux-arm5:
|
|
GOARCH=arm GOOS=linux GOARM=5 \
|
|
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(GZIP) $@ && chmod -x $@.gz
|
|
|
|
# cheat-linux-arm6
|
|
$(dist_dir)/cheat-linux-arm6:
|
|
GOARCH=arm GOOS=linux GOARM=6 \
|
|
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(GZIP) $@ && chmod -x $@.gz
|
|
|
|
# cheat-linux-arm7
|
|
$(dist_dir)/cheat-linux-arm7:
|
|
GOARCH=arm GOOS=linux GOARM=7 \
|
|
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(GZIP) $@ && chmod -x $@.gz
|
|
|
|
# cheat-linux-arm64
|
|
$(dist_dir)/cheat-linux-arm64:
|
|
GOARCH=arm64 GOOS=linux \
|
|
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(GZIP) $@ && chmod -x $@.gz
|
|
|
|
# cheat-netbsd-amd64
|
|
$(dist_dir)/cheat-netbsd-amd64:
|
|
GOARCH=amd64 GOOS=netbsd \
|
|
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(GZIP) $@ && chmod -x $@.gz
|
|
|
|
# cheat-openbsd-amd64
|
|
$(dist_dir)/cheat-openbsd-amd64:
|
|
GOARCH=amd64 GOOS=openbsd \
|
|
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(GZIP) $@ && chmod -x $@.gz
|
|
|
|
# cheat-plan9-amd64
|
|
$(dist_dir)/cheat-plan9-amd64:
|
|
GOARCH=amd64 GOOS=plan9 \
|
|
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(GZIP) $@ && chmod -x $@.gz
|
|
|
|
# cheat-solaris-amd64
|
|
$(dist_dir)/cheat-solaris-amd64:
|
|
GOARCH=amd64 GOOS=solaris \
|
|
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(GZIP) $@ && chmod -x $@.gz
|
|
|
|
# cheat-windows-amd64
|
|
$(dist_dir)/cheat-windows-amd64.exe:
|
|
GOARCH=amd64 GOOS=windows \
|
|
$(GO) build $(BUILD_FLAGS) -o $@ $(cmd_dir) && $(ZIP) $@.zip $@ -j
|
|
|
|
# ./dist
|
|
$(dist_dir):
|
|
$(MKDIR) $(dist_dir)
|
|
|
|
# .tmp
|
|
.tmp:
|
|
$(MKDIR) .tmp
|
|
|
|
## install: build and install cheat on your PATH
|
|
.PHONY: install
|
|
install: build
|
|
$(GO) install $(BUILD_FLAGS) $(GOBIN) $(cmd_dir)
|
|
|
|
## clean: remove compiled executables
|
|
.PHONY: clean
|
|
clean:
|
|
$(RM) -f $(dist_dir)/*
|
|
$(RM) -rf .tmp
|
|
|
|
## distclean: remove the tags file
|
|
.PHONY: distclean
|
|
distclean:
|
|
$(RM) -f tags
|
|
@$(DOCKER) image rm -f $(docker_image)
|
|
|
|
## setup: install revive (linter) and scc (sloc tool)
|
|
.PHONY: setup
|
|
setup:
|
|
$(GO) install github.com/boyter/scc@latest
|
|
$(GO) install github.com/mgechev/revive@latest
|
|
|
|
## sloc: count "semantic lines of code"
|
|
.PHONY: sloc
|
|
sloc:
|
|
$(SCC) --exclude-dir=vendor
|
|
|
|
## tags: build a tags file
|
|
.PHONY: tags
|
|
tags:
|
|
$(CTAGS) -R --exclude=vendor --languages=go
|
|
|
|
## man: build a man page
|
|
# NB: pandoc may not be installed, so we're ignoring this error on failure
|
|
.PHONY: man
|
|
man:
|
|
-$(PANDOC) -s -t man doc/cheat.1.md -o doc/cheat.1
|
|
|
|
## vendor: download, tidy, and verify dependencies
|
|
.PHONY: vendor
|
|
vendor:
|
|
$(GO) mod vendor && $(GO) mod tidy && $(GO) mod verify
|
|
|
|
## vendor-update: update vendored dependencies
|
|
.PHONY: vendor-update
|
|
vendor-update:
|
|
$(GO) get -t -u ./... && $(GO) mod vendor && $(GO) mod tidy && $(GO) mod verify
|
|
|
|
## fmt: run go fmt
|
|
.PHONY: fmt
|
|
fmt:
|
|
$(GO) fmt ./...
|
|
|
|
## lint: lint go source files
|
|
.PHONY: lint
|
|
lint: vendor
|
|
$(LINT) -exclude vendor/... ./...
|
|
|
|
## vet: vet go source files
|
|
.PHONY: vet
|
|
vet:
|
|
$(GO) vet ./...
|
|
|
|
## test: run unit-tests
|
|
.PHONY: test
|
|
test:
|
|
$(GO) test ./...
|
|
|
|
## test-integration: run integration tests (requires network)
|
|
.PHONY: test-integration
|
|
test-integration:
|
|
$(GO) test -tags=integration -count=1 ./...
|
|
|
|
## test-all: run all tests (unit and integration)
|
|
.PHONY: test-all
|
|
test-all: test test-integration
|
|
|
|
## test-fuzz: run quick fuzz tests for security-critical functions
|
|
.PHONY: test-fuzz
|
|
test-fuzz:
|
|
@./build/fuzz.sh 15s
|
|
|
|
## test-fuzz-long: run extended fuzz tests (10 minutes each)
|
|
.PHONY: test-fuzz-long
|
|
test-fuzz-long:
|
|
@./build/fuzz.sh 10m
|
|
|
|
## coverage: generate a test coverage report
|
|
.PHONY: coverage
|
|
coverage: .tmp
|
|
$(GO) test ./... -coverprofile=.tmp/cheat-coverage.out && \
|
|
$(GO) tool cover -html=.tmp/cheat-coverage.out -o .tmp/cheat-coverage.html && \
|
|
echo "Coverage report generated: .tmp/cheat-coverage.html" && \
|
|
(sensible-browser .tmp/cheat-coverage.html 2>/dev/null || \
|
|
xdg-open .tmp/cheat-coverage.html 2>/dev/null || \
|
|
open .tmp/cheat-coverage.html 2>/dev/null || \
|
|
echo "Please open .tmp/cheat-coverage.html in your browser")
|
|
|
|
## coverage-text: show test coverage by function in terminal
|
|
.PHONY: coverage-text
|
|
coverage-text: .tmp
|
|
$(GO) test ./... -coverprofile=.tmp/cheat-coverage.out && \
|
|
$(GO) tool cover -func=.tmp/cheat-coverage.out | $(SORT) -k3 -n
|
|
|
|
## benchmark: run performance benchmarks
|
|
.PHONY: benchmark
|
|
benchmark: .tmp
|
|
$(GO) test -tags=integration -bench=. -benchtime=10s -benchmem ./cmd/cheat | tee .tmp/benchmark-latest.txt && \
|
|
$(RM) -f cheat.test
|
|
|
|
## benchmark-cpu: run benchmarks with CPU profiling
|
|
.PHONY: benchmark-cpu
|
|
benchmark-cpu: .tmp
|
|
$(GO) test -tags=integration -bench=. -benchtime=10s -cpuprofile=.tmp/cpu.prof ./cmd/cheat && \
|
|
$(RM) -f cheat.test && \
|
|
echo "CPU profile saved to .tmp/cpu.prof" && \
|
|
echo "View with: go tool pprof -http=:8080 .tmp/cpu.prof"
|
|
|
|
## benchmark-mem: run benchmarks with memory profiling
|
|
.PHONY: benchmark-mem
|
|
benchmark-mem: .tmp
|
|
$(GO) test -tags=integration -bench=. -benchtime=10s -benchmem -memprofile=.tmp/mem.prof ./cmd/cheat && \
|
|
$(RM) -f cheat.test && \
|
|
echo "Memory profile saved to .tmp/mem.prof" && \
|
|
echo "View with: go tool pprof -http=:8080 .tmp/mem.prof"
|
|
|
|
## check: format, lint, vet, vendor, and run unit-tests
|
|
.PHONY: check
|
|
check: | vendor fmt lint vet test
|
|
|
|
.PHONY: prepare
|
|
prepare: | clean $(dist_dir) vendor fmt lint vet test
|
|
|
|
## docker-setup: create a docker image for use during development
|
|
.PHONY: docker-setup
|
|
docker-setup:
|
|
$(DOCKER) build -t $(docker_image) -f Dockerfile .
|
|
|
|
## docker-sh: shell into the docker development container
|
|
.PHONY: docker-sh
|
|
docker-sh:
|
|
$(DOCKER) run -v $(shell pwd):/app -ti $(docker_image) /bin/ash
|
|
|
|
## help: display this help text
|
|
.PHONY: help
|
|
help:
|
|
@$(CAT) $(makefile) | \
|
|
$(SORT) | \
|
|
$(GREP) "^##" | \
|
|
$(SED) 's/## //g' | \
|
|
$(COLUMN) -t -s ':'
|