~bigbes/sr-ht-compare

ref: f8283861787a361d6fa8bc6467ef15c9495b8261 sr-ht-compare/Makefile -rw-r--r-- 7.0 KiB
f8283861 — bigbes ci: a test task, and the truth about !check 9 days ago
                                                                                
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# compare.sr.ht — build scaffolding (git.sr.ht / sourcehut-dolt style).
#
# Go binary + Go-template SSR live under cmd/ and web/. The CSS is built from
# the shared sourcehut scss partials with sassc; the frontend diff bundle is
# built once with esbuild and vendored into web/static/. Node is a build-time
# dependency only.

SERVICE=compare.sr.ht
BIN=comparesrht

PREFIX?=/usr/local
BINDIR?=$(PREFIX)/bin
SHAREDIR?=$(PREFIX)/share
ASSETS?=/usr/share/sourcehut
STATICDIR?=$(ASSETS)/$(SERVICE)/static

SASSC?=sassc
SASSC_INCLUDE=-I$(ASSETS)/scss
MINIFY?=minify

# The glob web/templates.go resolves at startup (cssGlob). Named once so that
# `css`, which removes the previous build's file, and `check-css`, which counts
# what is left, cannot drift apart.
CSS=web/static/main.min.*.css

all: build

# Compile the service into ./comparesrht.
build:
	go build -o $(BIN) ./cmd/$(BIN)

test:
	go test ./...

# CSS pipeline: sassc -> minify -> content-hashed filename. The running
# service globs web/static/main.min.*.css at startup, so the hash in the name
# is the cache-busting version. Requires the shared scss partials to be
# installed at $(ASSETS)/scss (core.sr.ht `make install`, which installs both
# base.scss and bootstrap/scss there) and scss/main.scss to exist (phase 2b).
# Produces exactly ONE web/static/main.min.<sha256[:8]>.css (old ones and the
# intermediate main.css are removed).
#
# The three preflight checks are here because each of their failures is
# otherwise illegible. A missing minifier stops the pipeline after sassc has
# already written main.css, and the shell's "command not found" names a binary
# rather than a package; a missing $(ASSETS)/scss/base.scss is the family's
# standing rake — NO PACKAGE MANAGER SHIPS THAT PARTIAL, it is materialized by
# core.sr.ht's own `make install` locally and by the `scss` task of .build.yml
# in CI, and sassc's report of it is one line about an import.
css:
	@command -v $(SASSC) >/dev/null 2>&1 || { \
		echo "error: $(SASSC) not found — install sassc (apk add sassc, brew install sassc)"; \
		exit 1; }
	@command -v $(MINIFY) >/dev/null 2>&1 || { \
		echo "error: $(MINIFY) not found — install tdewolff/minify (apk add minify," \
			"go install github.com/tdewolff/minify/v2/cmd/minify@latest)"; \
		exit 1; }
	@[ -f $(ASSETS)/scss/base.scss ] || { \
		echo "error: no $(ASSETS)/scss/base.scss — the shared partial is not packaged;" \
			"materialize it with core.sr.ht's 'make install' (or the scss task of .build.yml)"; \
		exit 1; }
	mkdir -p web/static
	rm -f web/static/main.css $(CSS)
	$(SASSC) $(SASSC_INCLUDE) scss/main.scss web/static/main.css
	$(MINIFY) -o web/static/main.min.css web/static/main.css
	mv web/static/main.min.css \
		web/static/main.min.$$(sha256sum web/static/main.min.css | cut -c1-8).css
	rm -f web/static/main.css

# check-css is the packaging gate: no stylesheet, no release. It exists because
# the failure it catches is invisible at build time — `go build` succeeds
# perfectly well with an unstyled web/static (//go:embed takes the directory,
# not the file), and the first sign of trouble is an unstyled page in
# production.
#
# It answers about the DISK, and that is the limit of it: nothing here says the
# file it counted is the file a binary embedded.
#
# It COUNTS the matches rather than merely asking whether there are any, because
# two stylesheets are as wrong as none and quieter: web/templates.go resolves
# cssGlob and takes the first match, so a second file makes the served
# stylesheet depend on readdir order. `css` removes the previous build for that
# reason, which is exactly why this gate must not assume it did — a gate that
# promises "exactly one" and checks "at least one" is a promise the next person
# builds on.
#
# `set --` puts the matches in the positional parameters, so the count is $$#
# and no `wc` output has to be parsed. It is fine that this splits on
# whitespace: every name it can see was produced by the recipe above, out of a
# hex digest.
check-css:
	@set -- $$(ls $(CSS) 2>/dev/null); \
	if [ $$# -eq 0 ]; then \
		echo "error: no $(CSS) — run 'make css' before 'go build' (the CSS is embedded)"; \
		exit 1; \
	elif [ $$# -gt 1 ]; then \
		echo "error: $$# files match $(CSS) — web/ takes the first, so the choice is arbitrary."; \
		echo "       run 'make css' to get back to one:"; \
		for f in "$$@"; do echo "         $$f"; done; \
		exit 1; \
	fi

# Frontend diff/tree bundle: built once, output committed to web/static. The
# filename carries a content hash (like the CSS) so a deploy busts the browser
# cache — a stale bundle.js is otherwise served for up to max-age and can leave
# the file tree rendering blank after an upgrade. Produces exactly ONE
# web/static/bundle.<sha256[:8]>.js (old ones removed).
bundle:
	mkdir -p web/static
	rm -f web/static/bundle.js web/static/bundle.*.js
	cd frontend && npm ci && \
		npx esbuild src/app.ts --bundle --minify --format=esm \
			--outfile=../web/static/bundle.js
	mv web/static/bundle.js \
		web/static/bundle.$$(sha256sum web/static/bundle.js | cut -c1-8).js

# Local development run. Requires a ./config.ini in the working directory (or
# ../config.ini, /etc/sr.ht/config.ini): copy config.example.ini and fill in the
# instance's shared [sr.ht]/[webhooks] keys, plus a [git.sr.ht] repos root and an
# api-origin pointing at a real (or stubbed, see contrib/dev-stub) GraphQL API.
# See the "Development" section of README.md for the full recipe.
run-dev: build
	./$(BIN) -b localhost:5090

install: check-css build
	@$(MAKE) install-files

# The copying half of `install`, with nothing to build in front of it — the
# target a packaging run calls once it has already built and checked the binary,
# so that the files it stages are the very bytes it checked and not a second
# compilation of the same sources.
#
# That distinction is the whole point and it is not theoretical. `build` above is
# .PHONY (Go decides staleness itself, a real file target would never rebuild
# after a source edit), so `install` recompiles; abuild runs package() in a FRESH
# abuild process under fakeroot, which re-sources the APKBUILD and never calls
# build(), so the GOCACHE/GOMODCACHE pins are gone and that recompilation comes
# from a cold cache. The packaged binary would be one nothing had inspected.
#
# It is invoked through a sub-make rather than listed as a third prerequisite of
# `install` on purpose: /usr/share/abuild/default.conf exports
# MAKEFLAGS=-j$(nproc), prerequisites of one target run in parallel under -j, and
# `install: check-css build install-files` would let the copying start beside the
# build it is supposed to follow. A recipe line always runs after the
# prerequisites are done.
#
# There is no check in front of the copies. `install -Dm755 comparesrht` on a
# missing file is already a fatal error naming the file, which is exactly the
# right report for the one way this target can be called too early.
install-files:
	install -Dm755 $(BIN) $(DESTDIR)$(BINDIR)/$(BIN)
	mkdir -p $(DESTDIR)$(STATICDIR)
	install -Dm644 -t $(DESTDIR)$(STATICDIR) web/static/*

.PHONY: all build test css check-css bundle run-dev install install-files