|
1 | 1 | #!/usr/bin/env bash |
2 | | -# Builds a native Burrito release of `lc` for the current machine and |
3 | | -# installs it, plus the bin/ wrapper scripts (lcreate, lcls, lclose, |
4 | | -# lcomment, lproj), onto a directory already on $PATH. Fallback path for |
5 | | -# machines without Homebrew - see rubyists/homebrew-tap once it exists. |
| 2 | +# Downloads a precompiled Burrito release of `lc` for the current machine |
| 3 | +# and installs it, plus the bin/ wrapper scripts (lcreate, lcls, lclose, |
| 4 | +# lcomment, lproj) already bundled in the same release tarball, onto a |
| 5 | +# directory already on $PATH. Fallback path for machines without |
| 6 | +# Homebrew - see rubyists/homebrew-tap for that. |
| 7 | +# |
| 8 | +# LC_VERSION pins a specific release tag (e.g. "v1.0.0") instead of the |
| 9 | +# latest one. LC_INSTALL_DIR pins a specific install directory instead of |
| 10 | +# the first writable $PATH entry found. |
6 | 11 | # |
7 | 12 | # Records exactly what it installed and where in a manifest file, so |
8 | 13 | # uninstall.sh can remove precisely those files even if $PATH changes |
9 | 14 | # between install and uninstall. |
10 | 15 |
|
11 | | -repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" |
12 | | -app_dir="$repo_root/app" |
| 16 | +repo=rubyists/linear-cli-ex |
| 17 | +version=${LC_VERSION:-latest} |
13 | 18 | state_dir="${XDG_STATE_HOME:-$HOME/.local/state}/linear-cli-ex" |
14 | 19 | manifest="$state_dir/manifest" |
15 | 20 |
|
@@ -64,44 +69,85 @@ pick_install_dir() { |
64 | 69 | printf '%s\n' "$HOME/.local/bin" |
65 | 70 | } |
66 | 71 |
|
67 | | -build_lc() { |
68 | | - local target="$1" |
69 | | - |
70 | | - if ! cd "$app_dir" |
| 72 | +# GNU coreutils' sha256sum vs. macOS's shasum -a 256 - both read the same |
| 73 | +# "<hash> <filename>" format via `-c -` on stdin. |
| 74 | +checksum_cmd() { |
| 75 | + if command -v sha256sum >/dev/null 2>&1 |
71 | 76 | then |
72 | | - printf 'error: could not cd into %s\n' "$app_dir" >&2 |
| 77 | + printf 'sha256sum\n' |
| 78 | + elif command -v shasum >/dev/null 2>&1 |
| 79 | + then |
| 80 | + printf 'shasum -a 256\n' |
| 81 | + else |
| 82 | + printf 'error: need sha256sum or shasum on $PATH to verify the download\n' >&2 |
73 | 83 | exit 1 |
74 | 84 | fi |
| 85 | +} |
75 | 86 |
|
76 | | - rm -rf _build/prod |
77 | | - |
78 | | - have_mise=0 |
79 | | - if command -v mise >/dev/null 2>&1 |
| 87 | +release_url() { |
| 88 | + local asset="$1" |
| 89 | + if [ "$version" = "latest" ] |
80 | 90 | then |
81 | | - have_mise=1 |
| 91 | + printf 'https://github.com/%s/releases/latest/download/%s\n' "$repo" "$asset" |
82 | 92 | else |
83 | | - printf 'warning: mise not found on PATH; building with whatever Erlang/Elixir are active\n' >&2 |
| 93 | + printf 'https://github.com/%s/releases/download/%s/%s\n' "$repo" "$version" "$asset" |
| 94 | + fi |
| 95 | +} |
| 96 | + |
| 97 | +# Downloads lc_<target>.tar.gz + SHA256SUMS, verifies the tarball's |
| 98 | +# checksum against just its own line (SHA256SUMS covers every target, |
| 99 | +# not only the one being installed here), and extracts it. Prints the |
| 100 | +# directory it extracted into. |
| 101 | +fetch_lc() { |
| 102 | + local target="$1" tarball tmp_dir sum_tool |
| 103 | + tarball="lc_${target}.tar.gz" |
| 104 | + |
| 105 | + tmp_dir=$(mktemp -d) || { |
| 106 | + printf 'error: could not create a temp directory\n' >&2 |
| 107 | + exit 1 |
| 108 | + } |
| 109 | + trap 'rm -rf "$tmp_dir"' EXIT |
| 110 | + |
| 111 | + printf 'Downloading %s (%s)...\n' "$tarball" "$version" >&2 |
| 112 | + |
| 113 | + if ! curl -fsSL "$(release_url "$tarball")" -o "$tmp_dir/$tarball" |
| 114 | + then |
| 115 | + printf 'error: failed to download %s\n' "$tarball" >&2 |
| 116 | + exit 1 |
84 | 117 | fi |
85 | 118 |
|
86 | | - if [ "$have_mise" -eq 1 ] |
| 119 | + if ! curl -fsSL "$(release_url "SHA256SUMS")" -o "$tmp_dir/SHA256SUMS" |
87 | 120 | then |
88 | | - MIX_ENV=prod BURRITO_TARGET="$target" mise exec -- mix release lc --overwrite |
89 | | - else |
90 | | - MIX_ENV=prod BURRITO_TARGET="$target" mix release lc --overwrite |
| 121 | + printf 'error: failed to download SHA256SUMS\n' >&2 |
| 122 | + exit 1 |
| 123 | + fi |
| 124 | + |
| 125 | + sum_tool=$(checksum_cmd) |
| 126 | + |
| 127 | + if ! grep -- " $tarball\$" "$tmp_dir/SHA256SUMS" | (cd "$tmp_dir" && $sum_tool -c -) >/dev/null |
| 128 | + then |
| 129 | + printf 'error: checksum verification failed for %s\n' "$tarball" >&2 |
| 130 | + exit 1 |
91 | 131 | fi |
92 | 132 |
|
93 | | - if [ "$?" -ne 0 ] |
| 133 | + if ! tar -xzf "$tmp_dir/$tarball" -C "$tmp_dir" |
94 | 134 | then |
95 | | - printf 'error: build failed (mix release lc, target %s)\n' "$target" >&2 |
| 135 | + printf 'error: failed to extract %s\n' "$tarball" >&2 |
96 | 136 | exit 1 |
97 | 137 | fi |
| 138 | + |
| 139 | + printf '%s\n' "$tmp_dir" |
98 | 140 | } |
99 | 141 |
|
| 142 | +if ! command -v curl >/dev/null 2>&1 |
| 143 | +then |
| 144 | + printf 'error: curl is required\n' >&2 |
| 145 | + exit 1 |
| 146 | +fi |
| 147 | + |
100 | 148 | target=$(detect_target) || exit 1 |
101 | 149 | install_dir=$(pick_install_dir) |
102 | | - |
103 | | -printf 'Building lc (%s)...\n' "$target" |
104 | | -build_lc "$target" |
| 150 | +extracted_dir=$(fetch_lc "$target") || exit 1 |
105 | 151 |
|
106 | 152 | if ! mkdir -p "$install_dir" |
107 | 153 | then |
|
118 | 164 | : > "$manifest" |
119 | 165 | for name in lc lcreate lcls lclose lcomment lproj |
120 | 166 | do |
121 | | - src="$app_dir/burrito_out/lc_${target}" |
122 | | - [ "$name" = lc ] || src="$repo_root/bin/$name" |
123 | | - |
124 | | - if ! install -m 755 "$src" "$install_dir/$name" |
| 167 | + if ! install -m 755 "$extracted_dir/$name" "$install_dir/$name" |
125 | 168 | then |
126 | 169 | printf 'error: failed to install %s to %s\n' "$name" "$install_dir" >&2 |
127 | 170 | exit 1 |
|
130 | 173 | printf '%s\n' "$install_dir/$name" >> "$manifest" |
131 | 174 | done |
132 | 175 |
|
| 176 | +# Gatekeeper blocks lc itself (a real Mach-O binary) on macOS since it |
| 177 | +# isn't signed/notarized - the wrapper scripts are plain shell, so they're |
| 178 | +# unaffected. Best-effort: xattr not existing/failing shouldn't fail the |
| 179 | +# install, since the user can still do this by hand (see the README). |
| 180 | +if [ "$(uname -s)" = Darwin ] |
| 181 | +then |
| 182 | + xattr -d com.apple.quarantine "$install_dir/lc" 2>/dev/null || true |
| 183 | +fi |
| 184 | + |
133 | 185 | printf 'Installed lc, lcreate, lcls, lclose, lcomment, lproj to %s\n' "$install_dir" |
134 | 186 | printf '(uninstall.sh will remove exactly these files - manifest at %s)\n' "$manifest" |
135 | 187 |
|
|
0 commit comments