1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
COLITUR := colitur
PREFIX ?= $(HOME)/.local
BINDIR := $(PREFIX)/bin
MANDIR := $(PREFIX)/share/man/man1
# Section 5 is file formats: the overlay format is a thing a user AUTHORS,
# not a command they run, so it belongs beside fstab(5) rather than in man1.
MAN5DIR := $(PREFIX)/share/man/man5
# The binary locates its calendar data relative to its own path
# (<prefix>/share/colitur/ef), so `dune install` -- not a hand-rolled copy --
# is what places the four .sexp files where a running colitur will look for
# them. See bin/main.ml's own [data_dir] for the full resolution order.
#
# dune needs the project-local opam switch on PATH. Every recipe that invokes
# dune goes through this, so `make` works from a plain shell with no
# `eval $(opam env)` first -- which is the whole point of having a Makefile
# over documenting the dune commands.
DUNE := opam exec --
.PHONY: help build test check install uninstall reinstall clean fmt man doc release
help: ## show this help
@grep -hE '^[a-z-]+:.*##' $(MAKEFILE_LIST) | sed -E 's/:.*## /\t/' | sort
build: ## build the binary
$(DUNE) dune build
test: ## fast suite (~5s): properties sample 200 years
$(DUNE) dune test
check: ## full gate (~2min): every year 1583-9999, not a sample
COLITUR_EXHAUSTIVE_SWEEP=1 $(DUNE) dune test --force
install: build ## install binary, calendar data and man page into PREFIX (default ~/.local)
$(DUNE) dune install --prefix $(PREFIX)
@mkdir -p $(MANDIR)
install -m 644 man/colitur.1 $(MANDIR)/colitur.1
@mkdir -p $(MAN5DIR)
install -m 644 man/colitur-overlay.5 $(MAN5DIR)/colitur-overlay.5
@echo "installed $(BINDIR)/$(COLITUR), data in $(PREFIX)/share/colitur/ef, man pages in $(MANDIR) and $(MAN5DIR)"
@command -v $(COLITUR) >/dev/null 2>&1 || \
echo "note: $(BINDIR) is not on PATH -- add it, or run $(BINDIR)/$(COLITUR) directly"
uninstall: ## remove everything install put into PREFIX
-$(DUNE) dune uninstall --prefix $(PREFIX)
rm -f $(MANDIR)/colitur.1 $(MAN5DIR)/colitur-overlay.5
@echo "removed $(COLITUR) from $(PREFIX)"
reinstall: uninstall install ## uninstall then install (the installed copy is a snapshot, not a link)
man: ## preview the man pages
man -l man/colitur.1
man -l man/colitur-overlay.5
doc: ## lint the man pages (groff warnings; silence means clean)
groff -man -Tutf8 -ww -z man/colitur.1
groff -man -Tutf8 -ww -z man/colitur-overlay.5
fmt: ## format the OCaml sources
$(DUNE) dune build @fmt --auto-promote
clean: ## remove build artifacts
$(DUNE) dune clean
# Mirrors lectio's own release target, including its refusals: no release from
# a dirty tree, no release without a CHANGELOG line, and no release whose
# version bump silently failed to apply. The version lives in TWO places
# (dune-project, which feeds colitur.opam, and bin/main.ml's own constant,
# which is what --version prints), so both are rewritten and both are
# re-checked -- a release that bumped one and not the other would ship a
# binary disagreeing with its own package metadata.
release: ## cut a release: make release VERSION=0.1.0 (add its CHANGELOG line first)
@test -n "$(VERSION)" || { echo "set VERSION=X.Y.Z" >&2; exit 2; }
@echo "$(VERSION)" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$$' || { echo "VERSION must be X.Y.Z" >&2; exit 2; }
@test -z "$$(git status --porcelain)" || { echo "working tree not clean; commit or stash first" >&2; exit 2; }
@grep -q '## \[$(VERSION)\]' CHANGELOG.md || { echo "add a one-line CHANGELOG.md entry under '## [$(VERSION)]' first" >&2; exit 2; }
@sed -i 's/^(version .*)$$/(version $(VERSION))/' dune-project
@sed -i 's/^let version = ".*"/let version = "$(VERSION)"/' bin/main.ml
@grep -q '^(version $(VERSION))$$' dune-project || { echo "dune-project version bump failed" >&2; exit 2; }
@grep -q '^let version = "$(VERSION)"' bin/main.ml || { echo "bin/main.ml version bump failed" >&2; exit 2; }
$(MAKE) check
@test "$$($(DUNE) dune exec --no-build colitur -- --version)" = "$(VERSION)" || \
{ echo "the built binary does not report $(VERSION)" >&2; exit 2; }
@git add dune-project colitur.opam bin/main.ml CHANGELOG.md
@# Only commit if the bump actually changed something. Re-running release
@# after a failed gate -- or cutting a version whose files are already
@# correct, which is exactly how the first tag went -- leaves nothing
@# staged, and `git commit` would abort the whole target on "nothing to
@# commit" despite everything being in order.
@git diff --cached --quiet || git commit -m "release: v$(VERSION)"
@git rev-parse -q --verify "refs/tags/v$(VERSION)" >/dev/null && \
{ echo "tag v$(VERSION) already exists; delete it first to re-cut" >&2; exit 2; } || true
git tag -a "v$(VERSION)" -m "colitur $(VERSION)"
@echo "tagged v$(VERSION). publish with: git push origin main v$(VERSION)"
|