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
|
#!/usr/bin/env bash
#
# brew-release.sh <repo> <version> [go-package]
#
# Release one of your Soft Serve repos to your self-hosted Homebrew tap — no
# GitHub. It archives the tag straight from the server's bare repo into a source
# tarball under /dl, then writes/updates a source-build formula in the
# `homebrew-tap` repo and pushes it.
#
# scripts/brew-release.sh sportsball v0.1.0 # main package at repo root
# scripts/brew-release.sh sportsball v0.1.0 ./cmd/sportsball
#
# Prereqs: the tag exists in the repo on the server; deploy/deploy.env is filled
# (REMOTE, DOMAIN, REPOS_PATH); the `homebrew-tap` repo exists on the server.
# Users then: brew tap you/tap https://DOMAIN/git/homebrew-tap.git && brew install <repo>
#
set -euo pipefail
cd "$(dirname "$0")/.."
REPO="${1:?usage: brew-release.sh <repo> <version> [go-package]}"
VERSION="${2:?usage: brew-release.sh <repo> <version> [go-package]}"
PKG="${3:-.}"
VER="${VERSION#v}" # strip leading v for tarball/version string
[ -f deploy/deploy.env ] || { echo "missing deploy/deploy.env" >&2; exit 1; }
set -a; . deploy/deploy.env; set +a
: "${REMOTE:?}"; : "${DOMAIN:?}"; : "${REPOS_PATH:?}"; : "${RUN_USER:?}"
TARBALL="${REPO}-${VER}.tar.gz"
URL="https://${DOMAIN}/dl/${TARBALL}"
HOMEPAGE="https://${DOMAIN}/r/${REPO}"
CLASS="$(echo "$REPO" | perl -pe 's/(^|[-_])(\w)/\U$2/g')" # sportsball → Sportsball, foo-bar → FooBar
# Description from the repo's Soft Serve metadata (brew audit: must be capitalized
# and not start with the formula name).
DESC="$(ssh soft repo description "$REPO" 2>/dev/null | head -1)"
[ -z "$DESC" ] && DESC="Command-line application"
DESC="${DESC//\"/}" # no double quotes inside the ruby string
shopt -s nocasematch
if [[ "$DESC" == "$REPO"* ]]; then DESC="${DESC#"$REPO"}"; DESC="${DESC#"${DESC%%[![:punct:][:space:]]*}"}"; fi
shopt -u nocasematch
DESC="$(printf '%s' "$DESC" | perl -pe 's/^\s*(\w)/\U$1/')"
# brew audit: no trailing period, < 80 chars. Trim a parenthetical / em-dash
# clause to fit before hard-truncating at a word boundary.
DESC="${DESC%.}"
[ ${#DESC} -gt 78 ] && DESC="$(printf '%s' "$DESC" | perl -pe 's/\s*\([^)]*\)\s*$//')"
[ ${#DESC} -gt 78 ] && DESC="${DESC%% — *}"
if [ ${#DESC} -gt 78 ]; then DESC="${DESC:0:78}"; DESC="${DESC% *}"; fi
DESC="$(printf '%s' "$DESC" | perl -pe 's/[[:punct:][:space:]]+$//')"
echo "==> archiving ${REPO}@${VERSION} from the server"
# Run as the repo owner so git doesn't reject "dubious ownership".
ssh "$REMOTE" "sudo -u ${RUN_USER} git -C '${REPOS_PATH}/${REPO}.git' archive --format=tar.gz --prefix='${REPO}-${VER}/' '${VERSION}'" > "/tmp/${TARBALL}"
SHA="$(shasum -a 256 "/tmp/${TARBALL}" | awk '{print $1}')"
echo " ${TARBALL} sha256=${SHA}"
echo "==> publishing tarball to /dl"
ssh "$REMOTE" "install -d -o caddy -g caddy /var/lib/custard/dl"
scp -q "/tmp/${TARBALL}" "$REMOTE:/var/lib/custard/dl/${TARBALL}"
echo "==> updating the tap formula"
TAP="$(mktemp -d)"
git clone -q "soft:homebrew-tap" "$TAP"
mkdir -p "$TAP/Formula"
cat > "$TAP/Formula/${REPO}.rb" <<EOF
# Generated by custard brew-release.sh — do not edit by hand.
class ${CLASS} < Formula
desc "${DESC}"
homepage "${HOMEPAGE}"
url "${URL}"
sha256 "${SHA}"
license "AGPL-3.0-or-later"
depends_on "go" => :build
def install
system "go", "build", *std_go_args(ldflags: "-s -w -X main.version=#{version}"), "${PKG}"
end
test do
assert_path_exists bin/"${REPO}"
end
end
EOF
git -C "$TAP" add "Formula/${REPO}.rb"
git -C "$TAP" -c user.name="custard" -c user.email="custard@${DOMAIN}" \
commit -q -m "${REPO} ${VERSION}"
git -C "$TAP" push -q origin HEAD
rm -rf "$TAP"
echo "==> done"
echo " brew tap humdrum/tap https://${DOMAIN}/git/homebrew-tap.git"
echo " brew trust humdrum/tap"
echo " brew install ${REPO}"
|