Skip to content

Commit 6702cd0

Browse files
authored
Merge pull request #8 from reoring/chore/install-script
Add install.sh installer script
2 parents 24b586b + 4659d0b commit 6702cd0

3 files changed

Lines changed: 276 additions & 0 deletions

File tree

‎README.ja.md‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,21 @@ Supervisor / Runner(policy, 親プロセス)
7272

7373
## インストール
7474

75+
### ビルド済みバイナリ(推奨)
76+
77+
最新リリースを `/usr/local/bin` にインストールします(`/usr/local/bin` が書き込めない場合は `~/.local/bin`)。
78+
79+
```bash
80+
curl -fsSL https://raw.githubusercontent.com/reoring/roboppi/main/install.sh | bash
81+
roboppi --help
82+
```
83+
84+
特定バージョンを入れる場合:
85+
86+
```bash
87+
curl -fsSL https://raw.githubusercontent.com/reoring/roboppi/main/install.sh | bash -s -- --tag v0.1.0
88+
```
89+
7590
前提:
7691

7792
- Bun(CI は Bun 1.3.8)

‎README.md‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,21 @@ Design docs:
7676

7777
## Install
7878

79+
### Prebuilt binary (recommended)
80+
81+
Install the latest release to `/usr/local/bin` (or `~/.local/bin` if `/usr/local/bin` is not writable):
82+
83+
```bash
84+
curl -fsSL https://raw.githubusercontent.com/reoring/roboppi/main/install.sh | bash
85+
roboppi --help
86+
```
87+
88+
Install a specific version:
89+
90+
```bash
91+
curl -fsSL https://raw.githubusercontent.com/reoring/roboppi/main/install.sh | bash -s -- --tag v0.1.0
92+
```
93+
7994
Prerequisites:
8095

8196
- Bun (CI uses Bun 1.3.8)

‎install.sh‎

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
REPO="reoring/roboppi"
5+
GITHUB="https://github.com/${REPO}"
6+
API="https://api.github.com/repos/${REPO}"
7+
8+
log() {
9+
printf '%s\n' "$*" >&2
10+
}
11+
12+
die() {
13+
log "roboppi install: $*"
14+
exit 1
15+
}
16+
17+
need_cmd() {
18+
command -v "$1" >/dev/null 2>&1
19+
}
20+
21+
usage() {
22+
cat >&2 <<'EOF'
23+
Install Roboppi from GitHub Releases.
24+
25+
USAGE
26+
curl -fsSL https://raw.githubusercontent.com/reoring/roboppi/main/install.sh | bash
27+
28+
OPTIONS
29+
--tag <vX.Y.Z> Install a specific release tag (default: latest)
30+
--version <X.Y.Z> Shorthand for --tag vX.Y.Z
31+
--install-dir <dir> Install directory for the roboppi binary
32+
--prefix <dir> Install to <dir>/bin
33+
--no-verify Skip sha256 verification
34+
--dry-run Print actions without installing
35+
--help Show this help
36+
37+
ENV
38+
ROBOPPI_INSTALL_DIR Same as --install-dir
39+
40+
NOTES
41+
- Supported: macOS (x64/arm64), Linux (x64/arm64)
42+
- This script downloads the prebuilt binary from GitHub Releases.
43+
EOF
44+
}
45+
46+
fetch() {
47+
local url="$1"
48+
if need_cmd curl; then
49+
curl -fsSL "$url"
50+
return 0
51+
fi
52+
if need_cmd wget; then
53+
wget -qO- "$url"
54+
return 0
55+
fi
56+
die "need curl or wget"
57+
}
58+
59+
download_to() {
60+
local url="$1"
61+
local out="$2"
62+
if need_cmd curl; then
63+
curl -fSL "$url" -o "$out"
64+
return 0
65+
fi
66+
if need_cmd wget; then
67+
wget -qO "$out" "$url"
68+
return 0
69+
fi
70+
die "need curl or wget"
71+
}
72+
73+
sha256_file() {
74+
local file="$1"
75+
if need_cmd sha256sum; then
76+
sha256sum "$file" | awk '{print $1}'
77+
return 0
78+
fi
79+
if need_cmd shasum; then
80+
shasum -a 256 "$file" | awk '{print $1}'
81+
return 0
82+
fi
83+
die "need sha256sum or shasum"
84+
}
85+
86+
resolve_latest_tag() {
87+
# Extract "tag_name" from GitHub API JSON without jq.
88+
fetch "${API}/releases/latest" |
89+
awk -F'"' '/"tag_name"[[:space:]]*:/ {print $4; exit}'
90+
}
91+
92+
map_platform() {
93+
local os arch
94+
os="$(uname -s 2>/dev/null || true)"
95+
arch="$(uname -m 2>/dev/null || true)"
96+
97+
case "$os" in
98+
Linux) os="linux" ;;
99+
Darwin) os="macos" ;;
100+
*) die "unsupported OS: ${os:-unknown}" ;;
101+
esac
102+
103+
case "$arch" in
104+
x86_64|amd64) arch="x64" ;;
105+
arm64|aarch64) arch="arm64" ;;
106+
*) die "unsupported architecture: ${arch:-unknown}" ;;
107+
esac
108+
109+
printf '%s-%s' "$os" "$arch"
110+
}
111+
112+
main() {
113+
local tag=""
114+
local install_dir="${ROBOPPI_INSTALL_DIR:-}"
115+
local verify=1
116+
local dry_run=0
117+
118+
while [[ $# -gt 0 ]]; do
119+
case "$1" in
120+
--tag)
121+
[[ $# -ge 2 ]] || die "--tag requires a value"
122+
tag="$2"
123+
shift 2
124+
;;
125+
--version)
126+
[[ $# -ge 2 ]] || die "--version requires a value"
127+
tag="$2"
128+
if [[ "$tag" != v* ]]; then tag="v${tag}"; fi
129+
shift 2
130+
;;
131+
--install-dir)
132+
[[ $# -ge 2 ]] || die "--install-dir requires a value"
133+
install_dir="$2"
134+
shift 2
135+
;;
136+
--prefix)
137+
[[ $# -ge 2 ]] || die "--prefix requires a value"
138+
install_dir="$2/bin"
139+
shift 2
140+
;;
141+
--no-verify)
142+
verify=0
143+
shift
144+
;;
145+
--dry-run)
146+
dry_run=1
147+
shift
148+
;;
149+
--help|-h)
150+
usage
151+
exit 0
152+
;;
153+
*)
154+
die "unknown argument: $1 (try --help)"
155+
;;
156+
esac
157+
done
158+
159+
if [[ -z "$tag" ]]; then
160+
tag="$(resolve_latest_tag || true)"
161+
[[ -n "$tag" ]] || die "failed to resolve latest release tag; use --tag vX.Y.Z"
162+
else
163+
if [[ "$tag" != v* ]]; then tag="v${tag}"; fi
164+
fi
165+
166+
local platform asset base_url
167+
platform="$(map_platform)"
168+
asset="roboppi-${tag}-${platform}.tar.gz"
169+
base_url="${GITHUB}/releases/download/${tag}"
170+
171+
if [[ -z "$install_dir" ]]; then
172+
if [[ -w "/usr/local/bin" ]]; then
173+
install_dir="/usr/local/bin"
174+
else
175+
install_dir="${HOME}/.local/bin"
176+
fi
177+
fi
178+
179+
local tmp
180+
tmp="$(mktemp -d 2>/dev/null || mktemp -d -t roboppi)"
181+
trap 'rm -rf "$tmp"' EXIT
182+
183+
log "roboppi install: tag=${tag} platform=${platform}"
184+
log "roboppi install: downloading ${asset}"
185+
186+
if [[ "$dry_run" -eq 1 ]]; then
187+
log "dry-run: would download ${base_url}/${asset}"
188+
log "dry-run: would install to ${install_dir}/roboppi"
189+
return 0
190+
fi
191+
192+
download_to "${base_url}/${asset}" "${tmp}/${asset}" || die "download failed: ${base_url}/${asset}"
193+
194+
if [[ "$verify" -eq 1 ]]; then
195+
local sha_url sha_file expected got
196+
sha_url="${base_url}/${asset}.sha256"
197+
sha_file="${tmp}/${asset}.sha256"
198+
download_to "$sha_url" "$sha_file" || die "download failed: ${sha_url}"
199+
expected="$(awk 'NR==1 {print $1; exit}' "$sha_file")"
200+
[[ -n "$expected" ]] || die "could not read expected sha256"
201+
got="$(sha256_file "${tmp}/${asset}")"
202+
if [[ "$got" != "$expected" ]]; then
203+
die "sha256 mismatch for ${asset} (expected ${expected}, got ${got})"
204+
fi
205+
fi
206+
207+
mkdir -p "${tmp}/stage"
208+
tar -xzf "${tmp}/${asset}" -C "${tmp}/stage"
209+
210+
local src_bin
211+
src_bin="${tmp}/stage/roboppi"
212+
[[ -f "$src_bin" ]] || die "archive did not contain roboppi binary"
213+
214+
if [[ -w "$install_dir" ]]; then
215+
mkdir -p "$install_dir"
216+
if need_cmd install; then
217+
install -m 755 "$src_bin" "${install_dir}/roboppi"
218+
else
219+
cp "$src_bin" "${install_dir}/roboppi"
220+
chmod 755 "${install_dir}/roboppi"
221+
fi
222+
else
223+
if need_cmd sudo; then
224+
sudo mkdir -p "$install_dir"
225+
if need_cmd install; then
226+
sudo install -m 755 "$src_bin" "${install_dir}/roboppi"
227+
else
228+
sudo cp "$src_bin" "${install_dir}/roboppi"
229+
sudo chmod 755 "${install_dir}/roboppi"
230+
fi
231+
else
232+
die "install dir not writable (${install_dir}); set --install-dir or install sudo"
233+
fi
234+
fi
235+
236+
log "roboppi install: installed to ${install_dir}/roboppi"
237+
238+
if command -v roboppi >/dev/null 2>&1; then
239+
roboppi --version || true
240+
elif [[ -x "${install_dir}/roboppi" ]]; then
241+
"${install_dir}/roboppi" --version || true
242+
log "roboppi install: ${install_dir} is not on PATH"
243+
fi
244+
}
245+
246+
main "$@"

0 commit comments

Comments
 (0)