Repository navigation
Expand file tree
/
Copy pathinstall
More file actions
executable file
·196 lines (171 loc) · 7.2 KB
/
Copy pathinstall
File metadata and controls
executable file
·196 lines (171 loc) · 7.2 KB
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
#!/usr/bin/env bash
#
# install -- installer for the amber toolkit. curl|bash-able from GitHub raw.
# curl -fsSL https://raw.githubusercontent.com/purpleempress/amber-cli/main/install | bash
# Piping into `sh` works too -- the POSIX preamble below re-execs under bash.
#
# Resolves LIB_DIR/BIN_DIR, clones-or-refreshes the checkout,
# relinks via `amber link`, ensures deps, and offers a key prompt. Re-runnable.
# MIT licensed.
# --- re-exec under bash (POSIX-sh compatible; runs before any bashism) --------
# The installer needs bash (it sources the bash lib). If a POSIX sh started us
# (e.g. `curl ... | sh`), hand off transparently: re-run the file if we have
# one, else re-fetch from the canonical URL and run that under bash.
AMBERCLI_INSTALL_URL="https://raw.githubusercontent.com/purpleempress/amber-cli/main/install"
if [ -z "${BASH_VERSION:-}" ]; then
if [ -f "$0" ]; then
exec bash "$0" "$@"
elif command -v curl >/dev/null 2>&1; then
exec bash -c "$(curl -fsSL "$AMBERCLI_INSTALL_URL")" install "$@"
else
echo "amber: the installer needs bash, and curl isn't available to re-fetch." >&2
echo "Re-run with: curl -fsSL $AMBERCLI_INSTALL_URL | bash" >&2
exit 1
fi
fi
set -euo pipefail
AMBERCLI_REPO_URL="https://github.com/purpleempress/amber-cli.git"
# --- pinned trust anchor -----------------------------------------------------
# This is what you (the human running `curl ... | bash`) inspect over https.
# Releases are trusted ONLY if signed by this key. MUST match the copy in lib
# (we assert that below). Replace the placeholder with the real release-key
# fingerprint before real use; until then, verification HARD-FAILS unless
# --no-verify is passed.
INSTALL_SIGNING_FPR="00FC77A24586FC735DA4AB26BE7CF33811ED73D4"
AMBERCLI_PROG=install
export AMBERCLI_PROG
# --- arg parse ---------------------------------------------------------------
WANT_SYSTEM=0
for arg in "$@"; do
case "$arg" in
--system) WANT_SYSTEM=1 ;;
--no-verify) export AMBERCLI_NO_VERIFY=1 ;;
-h | --help)
cat <<'EOF'
amber installer
Usage:
install [--system] [--no-verify]
(default) per-user install into ~/.local/share/amber, links into ~/.local/bin
--system system install into /usr/local/lib/amber, links into /usr/local/bin (sudo)
--no-verify skip GPG signature verification (DISCOURAGED -- dev/bootstrap only)
Honours $AMBERCLI_PREFIX (highest precedence): LIB=$AMBERCLI_PREFIX/lib/amber, BIN=$AMBERCLI_PREFIX/bin
EOF
exit 0
;;
*) printf 'install: unknown option: %s\n' "$arg" >&2; exit 1 ;;
esac
done
# --- path resolution ----------------------------------------
if [ -n "${AMBERCLI_PREFIX:-}" ]; then
LIB_DIR="$AMBERCLI_PREFIX/lib/amber"
BIN_DIR="$AMBERCLI_PREFIX/bin"
elif [ "$WANT_SYSTEM" = 1 ]; then
LIB_DIR="/usr/local/lib/amber"
BIN_DIR="/usr/local/bin"
else
LIB_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/amber"
BIN_DIR="$HOME/.local/bin"
fi
# --- clone or fetch ----------------------------------------------------------
# Idempotent and SAFE: a fresh clone just copies files; an existing checkout is
# only FETCHED (no merge) so unverified upstream code never enters the working
# tree before it is verified. Sets WAS_CLONE.
WAS_CLONE=0
clone_or_fetch() {
if ! command -v git >/dev/null 2>&1; then
printf 'install: git is required but not found; install it and retry\n' >&2
exit 1
fi
if [ -d "$LIB_DIR/.git" ]; then
printf 'install: fetching updates in %s\n' "$LIB_DIR" >&2
git -C "$LIB_DIR" fetch --tags --quiet origin || {
printf 'install: git fetch failed in %s\n' "$LIB_DIR" >&2
exit 1
}
else
printf 'install: cloning amber into %s\n' "$LIB_DIR" >&2
mkdir -p "$(dirname "$LIB_DIR")"
git clone --quiet "$AMBERCLI_REPO_URL" "$LIB_DIR"
WAS_CLONE=1
fi
}
relink() {
# Canonical relink: amber + all tools symlinked into BIN_DIR (dynamic).
if [ "$WANT_SYSTEM" = 1 ]; then
"$LIB_DIR/amber" link --system
else
"$LIB_DIR/amber" link
fi
}
# --- run ---------------------------------------------------------------------
clone_or_fetch
# Source the freshly-checked-out lib for the helpers (defs + config only -- this
# is NOT yet running the toolkit). lib is `set -e` safe to source.
# shellcheck source=lib
. "$LIB_DIR/lib"
# Detect drift between the fingerprint the human read here and the one lib
# actually enforces.
if [ "$INSTALL_SIGNING_FPR" != "$AMBERCLI_SIGNING_FPR" ]; then
printf 'install: AMBERCLI_SIGNING_FPR in install and lib disagree -- out of sync; aborting.\n' >&2
exit 1
fi
# --- VERIFY before symlinking or running anything ----------------------------
# Resolve the target ref: latest signed release tag if any; else the freshly
# fetched tip (FETCH_HEAD) for a refresh, or HEAD for a fresh clone.
TARGET="$(git -C "$LIB_DIR" tag -l 'v[0-9]*' | sort -V | tail -n1)"
if [ -z "$TARGET" ]; then
if [ "$WAS_CLONE" = 1 ]; then TARGET="HEAD"; else TARGET="FETCH_HEAD"; fi
fi
# ambercli_verify_ref hard-fails (refuses) on a bad/unsigned/wrong-key ref, leaving
# nothing on PATH; it self-bypasses LOUDLY when --no-verify / $AMBERCLI_NO_VERIFY=1.
ambercli_verify_ref "$TARGET"
# Only now (verified) move the working tree onto the target.
if git -C "$LIB_DIR" rev-parse -q --verify "refs/tags/$TARGET" >/dev/null 2>&1; then
git -C "$LIB_DIR" checkout --quiet "$TARGET"
elif [ "$WAS_CLONE" != 1 ]; then
git -C "$LIB_DIR" merge --ff-only --quiet FETCH_HEAD || {
printf 'install: refusing non-fast-forward update of %s; resolve manually\n' "$LIB_DIR" >&2
exit 1
}
fi
ambercli_need curl
ambercli_ensure_jq
# Optional tools -- note only.
for opt in sd glow; do
command -v "$opt" >/dev/null 2>&1 || \
printf 'install: note -- optional tool "%s" not found (nicer rendering when present)\n' "$opt" >&2
done
relink
mkdir -p "$AMBERCLI_CONFIG_DIR"
# Offer (don't force) a key prompt when interactive and no key set.
if [ -z "$(ambercli_config_get geminikey 2>/dev/null)" ] && [ -t 0 ]; then
printf '\nNo Gemini API key configured. Set one now? [y/N] ' >&2
read -r reply </dev/tty 2>/dev/null || reply=""
case "$reply" in
y | Y | yes | YES | Yes) ambercli_config_set geminikey ;;
*) printf 'install: skipped -- set it later with: amber set geminikey\n' >&2 ;;
esac
fi
# --- PATH check (instruct, don't silently edit) ------------------------------
path_line=""
case ":$PATH:" in
*":$BIN_DIR:"*) : ;; # already present
*)
case "${SHELL:-}" in
*/fish) path_line="fish_add_path $BIN_DIR" ;;
*) path_line="export PATH=\"$BIN_DIR:\$PATH\"" ;;
esac
;;
esac
# --- change summary ----------------------------------------------------------
printf '\n%s\n' "amber: install complete."
printf ' library: %s\n' "$LIB_DIR"
printf ' bindir: %s\n' "$BIN_DIR"
printf ' config: %s\n' "$AMBERCLI_CONFIG_DIR"
if [ -n "$path_line" ]; then
printf '\n %s is not on your PATH. Add this to your shell config:\n' "$BIN_DIR"
printf ' %s\n' "$path_line"
else
printf ' PATH: ok (%s already on PATH)\n' "$BIN_DIR"
fi
printf '\nRun "amber" to get started, or "amber doctor" to verify.\n'