Makefile
Ref: Size: 4.7 KiB History
CARGO := cargo
PROFILE ?= debug
BIN := git-collab
SERVER_BIN := git-collab-server
# A personal forge is installed by one person onto their own machine, so the
# default has to be a directory that person can write to. `~/.local` is already
# on most PATHs via `~/.local/bin` and is where a per-user install belongs;
# `make install PREFIX=/usr/local` under sudo remains the system-wide install.
PREFIX ?= $(HOME)/.local
# --- Building blocks ---
.PHONY: fmt check clippy test build install clean
fmt:
$(CARGO) fmt
check:
$(CARGO) check
clippy:
$(CARGO) clippy -- -D warnings
test:
$(CARGO) test
build:
$(CARGO) build $(if $(filter release,$(PROFILE)),--release,)
# --- Composites ---
.PHONY: lint ci
lint: fmt check clippy
ci: lint test build
# --- Install ---
.PHONY: uninstall
# The binaries go in first, and the man pages are attempted afterwards without
# the power to fail the install. Man pages are a convenience; the binaries are
# the thing being installed. Someone whose `$(MAN_INSTALL_DIR)` is not writable
# still wants `git-collab` on their PATH, and the old ordering — man pages as a
# prerequisite — meant the convenience could abort the install before a single
# binary had been written. `make install-man` on its own stays strict: asking
# for man pages explicitly and silently not getting them would be worse.
install: PROFILE := release
install: build man
install -Dm755 target/release/$(BIN) $(PREFIX)/bin/$(BIN)
install -Dm755 target/release/$(SERVER_BIN) $(PREFIX)/bin/$(SERVER_BIN)
@install -d $(MAN_INSTALL_DIR) 2>/dev/null && \
install -m644 $(MAN_DIR)/*.1 $(MAN_INSTALL_DIR)/ 2>/dev/null && \
echo "installed man pages to $(MAN_INSTALL_DIR)" || \
echo "warning: could not write $(MAN_INSTALL_DIR) — binaries are installed, man pages are not"
# Removes exactly what `install` creates. The man pages are matched by name
# rather than regenerated: they are `git-collab.1` plus one page per subcommand,
# all named `git-collab-*.1`, so the two patterns are the whole set — including
# pages for subcommands that an older version installed and this one no longer
# generates, which are precisely the litter worth clearing.
uninstall:
rm -f $(PREFIX)/bin/$(BIN) $(PREFIX)/bin/$(SERVER_BIN)
rm -f $(MAN_INSTALL_DIR)/$(BIN).1 $(MAN_INSTALL_DIR)/$(BIN)-*.1
clean: clean-man
$(CARGO) clean
# --- Man pages ---
MAN_DIR := man/man1
MAN_INSTALL_DIR := $(PREFIX)/share/man/man1
.PHONY: man install-man clean-man
man:
MAN_OUT_DIR=$(MAN_DIR) $(CARGO) build
@echo "Man pages written to $(MAN_DIR)/"
install-man: man
install -d $(MAN_INSTALL_DIR)
install -m644 $(MAN_DIR)/*.1 $(MAN_INSTALL_DIR)/
clean-man:
rm -rf man/
# --- Docker ---
REGISTRY := registry.a73x.sh
IMAGE := $(REGISTRY)/git-collab-server
# `.dockerignore` excludes `.git/`, correctly — the image needs the source, not
# the repository — so the build inside the container has nothing to read the
# commit from and `--version` there would report the crate version alone. A
# deployed container is the artifact whose identity is hardest to establish
# after the fact: you cannot `git log` it, and an image tagged by commit is only
# as good as whoever typed the tag. So the commit is passed in, and the binary
# carries it. Tag and stamp come from the same `git rev-parse` for that reason.
GIT_COMMIT ?= $(shell git rev-parse HEAD 2>/dev/null)
# `1` when tracked files differ from HEAD, so an image built from a
# work-in-progress tree says `-dirty` instead of claiming to be the commit.
# The `test -n` rather than the porcelain output itself: `$(if ...)` strips
# whitespace from its condition, and porcelain lines start with a space.
GIT_DIRTY ?= $(shell test -n "$$(git status --porcelain --untracked-files=no 2>/dev/null)" && echo 1)
TAG ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo 0.0.1)
.PHONY: docker docker-push
docker:
docker build \
$(if $(GIT_COMMIT),--build-arg GIT_COMMIT=$(GIT_COMMIT),) \
$(if $(GIT_DIRTY),--build-arg GIT_DIRTY=1,) \
-t $(IMAGE):$(TAG) .
docker-push: docker
docker push $(IMAGE):$(TAG)
# --- Dev helpers ---
.PHONY: run serve dev dashboard base-check
run:
$(CARGO) run -- $(ARGS)
serve:
$(CARGO) run --bin $(SERVER_BIN) -- $(ARGS)
dev: fmt
$(CARGO) run -- $(ARGS)
dashboard: fmt
$(CARGO) run -- dashboard
# Test another revision without moving this worktree's HEAD or index.
base-check:
@test -n "$(strip $(REF))" || { echo "usage: make base-check REF=<ref>" >&2; exit 2; }
@set -eu; \
root=$$(mktemp -d "$${TMPDIR:-/tmp}/git-collab-base-check.XXXXXX"); \
checkout="$$root/checkout"; \
cleanup() { \
git worktree remove --force "$$checkout" >/dev/null 2>&1 || true; \
rm -rf "$$root"; \
}; \
trap cleanup 0; \
git worktree add --detach "$$checkout" "$(REF)"; \
$(MAKE) -C "$$checkout" test