Repository navigation
Expand file tree
/
Copy pathinstall.sh
More file actions
163 lines (158 loc) · 7.42 KB
/
Copy pathinstall.sh
File metadata and controls
163 lines (158 loc) · 7.42 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
#!/bin/sh
# Keep the complete program in a function so curl | sh reads it before starting.
main() (
set -eu
KIT_USER=${KIT_USER:-viftode4}
# hq owns any server-specific behavior.
KIT_SERVER=${KIT_SERVER:-}
export KIT_USER KIT_SERVER
PATH="$HOME/.local/bin:$PATH"
export PATH
die() { printf 'kit: %s\n' "$*" >&2; exit 1; }
have() { command -v "$1" >/dev/null 2>&1; }
case "$KIT_USER" in
*[!a-zA-Z0-9-]*|-*) die 'KIT_USER must be a GitHub username.' ;;
esac
[ "${#KIT_USER}" -le 39 ] || die 'KIT_USER must be a GitHub username.'
# Check before installing anything. SSH sessions need a terminal (ssh -t).
if ! ( : </dev/tty ) 2>/dev/null; then
die 'Run from a terminal (use ssh -t for SSH) so login and vault prompts can read /dev/tty.'
fi
as_root() {
if [ "$(id -u)" -eq 0 ]; then
"$@"
else
have sudo || die 'sudo is required to install system packages.'
sudo "$@" </dev/tty
fi
}
apt_ready=0
apt_install() {
if [ "$apt_ready" -eq 0 ]; then
as_root apt-get update
apt_ready=1
fi
as_root env DEBIAN_FRONTEND=noninteractive apt-get install -y "$@"
}
node_ok() {
have node && node -e 'process.exit(Number(process.versions.node.split(".")[0]) >= 20 ? 0 : 1)' >/dev/null 2>&1
}
temp_dir=$(mktemp -d)
trap 'rm -rf "$temp_dir"' 0
trap 'exit 1' HUP INT TERM
case "$(uname -s)" in
Darwin)
[ "$(id -u)" -ne 0 ] || die 'Run as your regular macOS user; Homebrew cannot install as root.'
if ! have brew; then
for brew_bin in /opt/homebrew/bin/brew /usr/local/bin/brew; do
if [ -x "$brew_bin" ]; then
eval "$("$brew_bin" shellenv)"
break
fi
done
fi
if ! have brew; then
# Authenticate sudo first; the Homebrew installer itself stays non-interactive.
sudo -v </dev/tty
curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh -o "$temp_dir/brew.sh"
NONINTERACTIVE=1 /bin/bash "$temp_dir/brew.sh"
for brew_bin in /opt/homebrew/bin/brew /usr/local/bin/brew; do
if [ -x "$brew_bin" ]; then
eval "$("$brew_bin" shellenv)"
break
fi
done
fi
have brew || die 'Homebrew is not on PATH after installation.'
# /usr/bin/git may only be a Command Line Tools stub on a fresh Mac.
if ! have git || ! git --version >/dev/null 2>&1; then brew install git; fi
have curl || brew install curl
have gh || brew install gh
if ! node_ok || ! have npm; then
brew install node@24
# The versioned LTS formula is keg-only; expose it to future shells too.
brew link --overwrite --force node@24
PATH="$(brew --prefix node@24)/bin:$PATH"
export PATH
fi
;;
Linux)
if have apt-get; then
if ! have curl || [ ! -s /etc/ssl/certs/ca-certificates.crt ]; then
apt_install ca-certificates curl
fi
have git || apt_install git
if ! have gh; then
if [ "$apt_ready" -eq 0 ]; then
as_root apt-get update
apt_ready=1
fi
gh_candidate=$(apt-cache policy gh | sed -n 's/^[[:space:]]*Candidate: //p')
if [ -z "$gh_candidate" ] || [ "$gh_candidate" = '(none)' ]; then
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg -o "$temp_dir/githubcli.gpg"
as_root install -d -m 755 /etc/apt/keyrings /etc/apt/sources.list.d
as_root install -m 644 "$temp_dir/githubcli.gpg" /etc/apt/keyrings/githubcli-archive-keyring.gpg
printf 'deb [arch=%s signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main\n' "$(dpkg --print-architecture)" >"$temp_dir/github-cli.list"
as_root install -m 644 "$temp_dir/github-cli.list" /etc/apt/sources.list.d/github-cli.list
as_root apt-get update
fi
apt_install gh
fi
if ! node_ok; then
curl -fsSL https://deb.nodesource.com/setup_22.x -o "$temp_dir/node.sh"
as_root bash "$temp_dir/node.sh"
apt_install nodejs
fi
# NodeSource bundles npm; distro Node packages may split it out.
have npm || apt_install npm
elif have dnf; then
if ! have curl; then as_root dnf install -y curl ca-certificates; fi
have git || as_root dnf install -y git
if ! have gh; then
if ! as_root dnf install -y gh; then
curl -fsSL https://cli.github.com/packages/rpm/gh-cli.repo -o "$temp_dir/gh-cli.repo"
as_root install -m 644 "$temp_dir/gh-cli.repo" /etc/yum.repos.d/gh-cli.repo
as_root dnf install -y gh
fi
fi
if ! node_ok; then
as_root dnf install -y nodejs npm
if ! node_ok; then as_root dnf upgrade -y nodejs npm; fi
fi
have npm || as_root dnf install -y npm
else
die 'Supported Linux package managers: apt-get (Debian/Ubuntu) and dnf (Fedora, best effort).'
fi
;;
*) die 'Supported systems: macOS and Linux. Use install.ps1 on Windows.' ;;
esac
node_ok || die 'Node.js 20+ is required; upgrade Node.js or remove an older version shadowing it on PATH.'
if ! have chezmoi; then
mkdir -p "$HOME/.local/bin"
chezmoi_installer=$(curl -fsLS https://get.chezmoi.io)
sh -c "$chezmoi_installer" -- -b "$HOME/.local/bin"
fi
if ! have uv; then
curl -fsSL https://astral.sh/uv/install.sh -o "$temp_dir/uv.sh"
UV_INSTALL_DIR="$HOME/.local/bin" sh "$temp_dir/uv.sh"
fi
for tool in git gh chezmoi uv node npm; do
have "$tool" || die "$tool is unavailable after installation. Check PATH and rerun."
done
if ! gh auth status --hostname github.com; then
gh auth login --web --git-protocol https --hostname github.com </dev/tty
fi
gh auth setup-git --hostname github.com </dev/tty
if [ -d "$HOME/.local/share/chezmoi" ]; then
# Re-run = fresh, clean copy of hq (old one kept aside); never merges a stale or stuck copy.
mv "$HOME/.local/share/chezmoi" "$HOME/.local/share/chezmoi.old-$(date +%Y%m%d%H%M%S)"
fi
# Lean clone: only essentials (~2 MB); sessions and backups download per project, on demand.
hq="$HOME/.local/share/chezmoi"
git clone -q --filter=blob:none --sparse "https://github.com/$KIT_USER/hq.git" "$hq"
git -C "$hq" sparse-checkout set --cone kit shared dot_config registry vault/env
chezmoi init --apply --force </dev/tty
printf '%s\n' 'kit setup complete.'
)
# No child process may accidentally consume the streamed script as stdin.
main </dev/null