install.sh: an interactive installer — user, address, HTTPS, firewall, password — that still runs unattended; make publish

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Mitchell-Johnson
2026-09-19 10:56:42 -07:00
co-authored by Claude Fable 5.1
parent a838adcb27
commit e75fa0d759
2 changed files with 338 additions and 43 deletions
+13 -1
View File
@@ -9,7 +9,7 @@ LDFLAGS = -s -w -X main.version=$(VERSION)
# static, no cgo: the same file runs on glibc, musl (Alpine) and anything else with a Linux kernel # static, no cgo: the same file runs on glibc, musl (Alpine) and anything else with a Linux kernel
GOBUILD = CGO_ENABLED=0 GOOS=linux GOARM=6 $(GO) build -trimpath -ldflags "$(LDFLAGS)" GOBUILD = CGO_ENABLED=0 GOOS=linux GOARM=6 $(GO) build -trimpath -ldflags "$(LDFLAGS)"
.PHONY: all web build go dev cross release deploy push-nodes push-nodes-force test clean .PHONY: all web build go dev cross release publish deploy push-nodes push-nodes-force test clean
all: build all: build
@@ -42,6 +42,7 @@ release: web
@for a in $(ARCHES); do \ @for a in $(ARCHES); do \
echo "build linux/$$a"; GOARCH=$$a $(GOBUILD) -o dist/hamlab-linux-$$a ./cmd/hamlab || exit 1; done echo "build linux/$$a"; GOARCH=$$a $(GOBUILD) -o dist/hamlab-linux-$$a ./cmd/hamlab || exit 1; done
sed 's|@VERSION@|$(VERSION)|' install.sh > dist/install.sh && chmod +x dist/install.sh sed 's|@VERSION@|$(VERSION)|' install.sh > dist/install.sh && chmod +x dist/install.sh
echo $(VERSION) > dist/VERSION
cd dist && sha256sum hamlab-linux-* install.sh > SHA256SUMS cd dist && sha256sum hamlab-linux-* install.sh > SHA256SUMS
test: test:
@@ -63,3 +64,14 @@ push-nodes-force:
clean: clean:
rm -rf bin dist internal/web/dist web/dist rm -rf bin dist internal/web/dist web/dist
# Put the release where `curl -fsSL https://hamlab-demo.bigham.dev/install.sh | sh` finds it:
# the static site beside the demo page (nginx, public through NPM). Binaries first, VERSION
# last, so nobody is ever pointed at files that aren't there yet.
PUBLISH ?= /home/core/apps/hamlab-demo/site
publish: release
mkdir -p $(PUBLISH)/dl
cp dist/hamlab-linux-* dist/SHA256SUMS $(PUBLISH)/dl/
cp dist/install.sh $(PUBLISH)/dl/install.sh && cp dist/install.sh $(PUBLISH)/install.sh
cp dist/VERSION $(PUBLISH)/dl/VERSION
@echo "published $(VERSION): curl -fsSL https://hamlab-demo.bigham.dev/install.sh | sh"
+324 -41
View File
@@ -1,77 +1,360 @@
#!/bin/sh #!/bin/sh
# Ham Lab installer: fetches the build for this machine and hands over to `hamlab install`, # Ham Lab installer.
# which sets up the binary, config, login password and a boot-time service.
# #
# curl -fsSL "$HAMLAB_URL/install.sh" | sh # curl -fsSL https://hamlab-demo.bigham.dev/install.sh | sh
# curl -fsSL "$HAMLAB_URL/install.sh" | sh -s -- --listen 0.0.0.0:8100 --tls auto #
# With a terminal it walks you through it: who the console runs as, where it listens,
# HTTPS, the firewall, the password — then downloads the build for this machine, checks
# it against SHA256SUMS and hands over to `hamlab install`, which sets up the binary,
# the config and a service that starts at boot. Re-running it upgrades in place.
#
# Without a terminal, with --yes, or with flags after `--`, it asks nothing:
#
# curl -fsSL …/install.sh | sh -s -- --yes
# curl -fsSL …/install.sh | sh -s -- --listen 0.0.0.0:8100 --tls auto --password-stdin <pw
# ./install.sh # beside the hamlab-linux-* files: installs offline # ./install.sh # beside the hamlab-linux-* files: installs offline
# #
# Everything after `--` goes to `hamlab install` (see `hamlab install -h`). # HAMLAB_URL where hamlab-linux-<arch>, SHA256SUMS and VERSION are served from —
# # any static file host, or a Gitea/Forgejo release's download URL
# HAMLAB_URL where hamlab-linux-<arch> and SHA256SUMS are served from
# HAMLAB_TOKEN access token, when that place is a private Gitea/Forgejo repo # HAMLAB_TOKEN access token, when that place is a private Gitea/Forgejo repo
# NO_COLOR plain output
#
# POSIX sh: runs under dash, busybox ash and bash alike.
set -eu set -eu
HAMLAB_URL="${HAMLAB_URL:-https://git.bigham.dev/mitchell/hamlab/releases/download/@VERSION@}" HAMLAB_URL="${HAMLAB_URL:-https://hamlab-demo.bigham.dev/dl}"
BUILT_FOR="@VERSION@" # filled in by `make release`
die() { echo "install.sh: $*" >&2; exit 1; } # ─────────────────────────────────────────────────────────────── looks ──
if [ -t 2 ] && [ -z "${NO_COLOR:-}" ] && [ "${TERM:-dumb}" != dumb ]; then
[ "$(uname -s)" = Linux ] || die "Ham Lab runs on Linux; this is $(uname -s)" B=$(printf '\033[1m'); D=$(printf '\033[2m'); R=$(printf '\033[0m')
case "$(uname -m)" in AMBER=$(printf '\033[38;5;214m'); GREEN=$(printf '\033[32m'); RED=$(printf '\033[31m'); CYAN=$(printf '\033[36m')
x86_64|amd64) arch=amd64 ;; else
aarch64|arm64) arch=arm64 ;; B=; D=; R=; AMBER=; GREEN=; RED=; CYAN=
armv6l|armv7l|armv8l|arm) arch=arm ;; fi
i386|i486|i586|i686) arch=386 ;; case "${LC_ALL:-${LC_CTYPE:-${LANG:-}}}" in
riscv64) arch=riscv64 ;; *UTF-8*|*utf8*|*UTF8*|*utf-8*) OK='✓'; NO='✗'; DOT='•'; ARROW='›'; HR='────────────────────────────────────────────────────────────' ;;
*) die "no build for $(uname -m) (have: amd64, arm64, arm, 386, riscv64)" ;; *) OK='ok'; NO='x'; DOT='*'; ARROW='>'; HR='------------------------------------------------------------' ;;
esac esac
file="hamlab-linux-$arch"
tmp=$(mktemp -d 2>/dev/null || mktemp -d -t hamlab) out() { printf '%s\n' "$*" >&2; }
trap 'rm -rf "$tmp"' EXIT INT TERM blank() { printf '\n' >&2; }
good() { out " ${GREEN}${OK}${R} $*"; }
note() { out " ${D}$*${R}"; }
warn() { out " ${AMBER}!${R} $*"; }
die() { blank; out " ${RED}${NO}${R} ${B}$*${R}"; blank; exit 1; }
rule() { out "${D}${HR}${R}"; }
step() { blank; out "${AMBER}${B}$1${R} ${B}$2${R}"; [ -z "${3:-}" ] || note "$3"; blank; }
banner() {
blank
out " ${AMBER}${B}Ham Lab${R} ${D}a web console for the machines you run${R}"
out " ${D}terminals ${DOT} monitors ${DOT} services ${DOT} files ${DOT} updates ${DOT} disks — in one tab${R}"
rule
}
# ─────────────────────────────────────────────────────────── questions ──
# Piped from curl, stdin is this script, so every answer comes from the terminal itself.
TTY=/dev/tty
have_tty() { [ -r "$TTY" ] && [ -w "$TTY" ] && (: <"$TTY") 2>/dev/null; }
ask() { # ask "Question" "default" → $REPLY
if [ -n "${2:-}" ]; then printf ' %s %s[%s]%s ' "$1" "$D" "$2" "$R" >&2; else printf ' %s ' "$1" >&2; fi
IFS= read -r REPLY <"$TTY" || REPLY=
[ -n "$REPLY" ] || REPLY="${2:-}"
}
confirm() { # confirm "Question" y|n
if [ "$2" = y ]; then hint="Y/n"; else hint="y/N"; fi
while :; do
ask "$1" "$hint"
case "$REPLY" in
"$hint") [ "$2" = y ]; return ;;
y|Y|yes|Yes|YES) return 0 ;;
n|N|no|No|NO) return 1 ;;
*) warn "y or n, please" ;;
esac
done
}
secret() { # secret "Prompt" → $REPLY, typed unseen
printf ' %s ' "$1" >&2
saved=$(stty -g <"$TTY" 2>/dev/null || true)
stty -echo <"$TTY" 2>/dev/null || true
IFS= read -r REPLY <"$TTY" || REPLY=
[ -z "$saved" ] || stty "$saved" <"$TTY" 2>/dev/null || true
printf '\n' >&2
}
choose() { # choose "default-number" "label 1" "label 2" … → $REPLY = the number picked
def=$1; shift; n=0
for label in "$@"; do n=$((n + 1)); if [ "$n" = "$def" ]; then out " ${AMBER}${B}$n${R} $label"; else out " ${B}$n${R} $label"; fi; done
blank
while :; do
ask "Choose 1-$n" "$def"
case "$REPLY" in *[!0-9]*|'') ;; *) if [ "$REPLY" -ge 1 ] && [ "$REPLY" -le "$n" ]; then return; fi ;; esac
warn "a number from 1 to $n, please"
done
}
restore_tty() { [ -z "${saved:-}" ] || stty "$saved" <"$TTY" 2>/dev/null || true; }
# ──────────────────────────────────────────────────────────── plumbing ──
fetch() { # url dest fetch() { # url dest
if command -v curl >/dev/null 2>&1; then if command -v curl >/dev/null 2>&1; then
curl -fsSL ${HAMLAB_TOKEN:+-H "Authorization: token $HAMLAB_TOKEN"} -o "$2" "$1" curl -fsSL ${HAMLAB_TOKEN:+-H "Authorization: token $HAMLAB_TOKEN"} -o "$2" "$1"
elif command -v wget >/dev/null 2>&1; then elif command -v wget >/dev/null 2>&1; then
wget -q ${HAMLAB_TOKEN:+--header="Authorization: token $HAMLAB_TOKEN"} -O "$2" "$1" wget -q ${HAMLAB_TOKEN:+--header="Authorization: token $HAMLAB_TOKEN"} -O "$2" "$1"
else else
die "need curl or wget" die "This needs curl or wget, and the machine has neither."
fi
}
port_busy() { # is something already listening on TCP port $1?
hex=$(printf '%04X' "$1")
cat /proc/net/tcp /proc/net/tcp6 2>/dev/null | awk -v p=":$hex" '$4 == "0A" && substr($2, length($2) - 4) == p { found = 1 } END { exit !found }'
}
lan_addresses() { # this machine's IPv4 addresses, one per line, most useful first
if command -v ip >/dev/null 2>&1; then
ip -4 -o addr show scope global 2>/dev/null | awk '$2 !~ /^(docker|br-|veth|virbr|cni|flannel|tailscale|wg|tun|tap)/ { split($4, a, "/"); print a[1] " " $2 }'
else
hostname -I 2>/dev/null | tr ' ' '\n' | awk 'NF && $1 !~ /:/ { print $1 " -" }'
fi fi
} }
# ────────────────────────────────────────────────────────── arguments ──
YES=0; PASS=
while [ $# -gt 0 ]; do
case "$1" in
-y|--yes) YES=1; shift ;;
-h|--help) sed -n '2,20p' "$0" 2>/dev/null | sed 's/^# \{0,1\}//' >&2; exit 0 ;;
--) shift; PASS="$*"; break ;;
*) PASS="$*"; break ;; # flags given straight: they belong to `hamlab install`
esac
done
INTERACTIVE=1
{ [ "$YES" = 1 ] || [ -n "$PASS" ] || ! have_tty; } && INTERACTIVE=0
# ─────────────────────────────────────────────────────────── preflight ──
banner
[ "$(uname -s)" = Linux ] || die "Ham Lab runs on Linux; this is $(uname -s)."
case "$(uname -m)" in
x86_64|amd64) arch=amd64 ;;
aarch64|arm64) arch=arm64 ;;
armv6l|armv7l|armv8l|arm) arch=arm ;;
i386|i486|i586|i686) arch=386 ;;
riscv64) arch=riscv64 ;;
*) die "There is no build for $(uname -m). (There are: amd64, arm64, arm, 386, riscv64.)" ;;
esac
file="hamlab-linux-$arch"
me=$(id -un 2>/dev/null || echo root)
if [ "$(id -u)" = 0 ]; then how=root
elif command -v sudo >/dev/null 2>&1; then how=sudo
elif command -v doas >/dev/null 2>&1; then how=doas
else die "Installing a service needs root, and there is no sudo or doas here. Run this as root."
fi
if [ -d /run/systemd/system ]; then init=systemd
elif command -v rc-service >/dev/null 2>&1; then init=OpenRC
else init=none
fi
os=$(. /etc/os-release 2>/dev/null && printf '%s' "${PRETTY_NAME:-}"); [ -n "$os" ] || os=Linux
existing=$(command -v hamlab 2>/dev/null || true); [ -n "$existing" ] || { [ -x /usr/local/bin/hamlab ] && existing=/usr/local/bin/hamlab; } || true
have=; [ -z "$existing" ] || have=$("$existing" version 2>/dev/null | awk '{ print $2 }') || true
good "$os ${D}${DOT}${R} $(uname -m) ${D}${DOT}${R} $init"
case "$how" in root) good "running as root" ;; *) good "running as ${B}$me${R}; $how will ask for root when it is needed" ;; esac
[ "$init" != none ] || warn "no systemd or OpenRC here: Ham Lab will be installed, but nothing will start it at boot"
# ───────────────────────────────────────────────────── which version ──
tmp=$(mktemp -d 2>/dev/null || mktemp -d -t hamlab)
alt=
cleanup() { restore_tty; rm -rf "$tmp"; [ -z "$alt" ] || rm -f "$alt"; }
trap cleanup EXIT
trap 'blank; out " cancelled — nothing was changed"; exit 130' INT TERM
here=$(cd "$(dirname "$0")" 2>/dev/null && pwd || echo .) here=$(cd "$(dirname "$0")" 2>/dev/null && pwd || echo .)
if [ -f "$here/$file" ]; then offline=0; [ -f "$here/$file" ] && offline=1
cp "$here/$file" "$tmp/hamlab" if [ "$offline" = 1 ]; then
[ -f "$here/SHA256SUMS" ] && cp "$here/SHA256SUMS" "$tmp/SHA256SUMS" ver=$BUILT_FOR; case "$ver" in @*) ver="(local files)" ;; esac
else else
echo "Downloading $file" >&2 # What is published right now — which may be newer than the copy of this script being run.
fetch "$HAMLAB_URL/$file" "$tmp/hamlab" || die "download failed: $HAMLAB_URL/$file" ver=$(fetch "$HAMLAB_URL/VERSION" "$tmp/VERSION" 2>/dev/null && head -n 1 "$tmp/VERSION" | tr -cd 'A-Za-z0-9._+-' || true)
fetch "$HAMLAB_URL/SHA256SUMS" "$tmp/SHA256SUMS" 2>/dev/null || rm -f "$tmp/SHA256SUMS" [ -n "$ver" ] || { ver=$BUILT_FOR; case "$ver" in @*) ver=latest ;; esac; }
fi
if [ -n "$have" ] && [ "$have" = "$ver" ]; then good "Ham Lab ${B}$have${R} is already installed here ${D}${ARROW}${R} this will reinstall it, keeping its config, user and password"
elif [ -n "$have" ]; then good "Ham Lab ${B}$have${R} is installed here ${D}${ARROW}${R} this will upgrade it to ${B}$ver${R}, keeping its config, user and password"
else good "installing Ham Lab ${B}$ver${R}"; fi
# ─────────────────────────────────────────────────────────── the wizard ──
flags=; password=; listen=; url_host=
if [ "$INTERACTIVE" = 1 ] && [ -n "$have" ]; then
blank
confirm "$([ "$have" = "$ver" ] && echo Reinstall || echo Upgrade) now?" y || { blank; out " nothing was changed"; exit 0; }
elif [ "$INTERACTIVE" = 1 ]; then
# 1 ─ who
default_user=${SUDO_USER:-${DOAS_USER:-$me}}
step "1/5" "Who should it run as?" "Its terminals are that user's login shell, and its files are that user's files."
while :; do
ask "User" "$default_user"; run_as=$REPLY
id "$run_as" >/dev/null 2>&1 && break
warn "there is no user called \"$run_as\" on this machine"
done
[ "$run_as" != root ] || warn "as root, every terminal it opens is a root shell"
# 2 ─ where
step "2/5" "Where should it listen?" "Who can reach the console at all. The password still guards it either way."
addrs=$(lan_addresses || true); first=$(printf '%s\n' "$addrs" | awk 'NR == 1 { print $1 }')
if [ -n "$first" ]; then
first_if=$(printf '%s\n' "$addrs" | awk 'NR == 1 { print $2 }')
choose 2 "This machine only ${D}127.0.0.1 — reach it over an SSH tunnel or a reverse proxy${R}" \
"This network ${D}$first on $first_if — other machines on the LAN can open it${R}" \
"Every interface ${D}0.0.0.0 — all addresses this machine has or gets${R}" \
"Another address"
else
choose 1 "This machine only ${D}127.0.0.1${R}" "Every interface ${D}0.0.0.0${R}" "Another address"
[ "$REPLY" = 1 ] || REPLY=$((REPLY + 1))
fi
case "$REPLY" in
1) host=127.0.0.1 ;;
2) host=$first ;;
3) host=0.0.0.0 ;;
4) others=$(printf '%s\n' "$addrs" | awk 'NR > 1 { printf "%s%s (%s)", sep, $1, $2; sep = ", " }'); [ -z "$others" ] || note "also on this machine: $others"
while :; do ask "Address" ""; host=$REPLY; case "$host" in ''|*[!0-9a-fA-F.:]*) warn "an IPv4 or IPv6 address, please" ;; *) break ;; esac; done ;;
esac
while :; do
ask "Port" "8100"; port=$REPLY
case "$port" in ''|*[!0-9]*) warn "a number, please"; continue ;; esac
[ "$port" -ge 1 ] && [ "$port" -le 65535 ] || { warn "a port is between 1 and 65535"; continue; }
[ "$port" -ge 1024 ] || [ "$run_as" = root ] || { warn "ports under 1024 need root, and it will run as $run_as"; continue; }
if port_busy "$port"; then warn "something is already listening on port $port"; continue; fi
break
done
case "$host" in *:*) listen="[$host]:$port" ;; *) listen="$host:$port" ;; esac
# 3 ─ https
step "3/5" "HTTPS?" "A self-signed certificate is made here; browsers warn once, a hub pins its fingerprint."
if [ "$host" = 127.0.0.1 ]; then
choose 2 "HTTPS with a self-signed certificate" "Plain HTTP ${D}— fine here: nothing leaves this machine unencrypted${R}"
else
choose 1 "HTTPS with a self-signed certificate ${D}— recommended: the password crosses the network${R}" "Plain HTTP ${D}— only behind a reverse proxy that adds HTTPS itself${R}"
fi
if [ "$REPLY" = 1 ]; then tls=auto; scheme=https; else tls=off; scheme=http; fi
# 4 ─ firewall
open_fw=0; fw=
if [ "$host" != 127.0.0.1 ]; then
if command -v firewall-cmd >/dev/null 2>&1 && firewall-cmd --state >/dev/null 2>&1; then fw=firewalld
elif command -v ufw >/dev/null 2>&1 && ufw status 2>/dev/null | grep -q "^Status: active"; then fw=ufw
elif [ "$how" != root ] && command -v ufw >/dev/null 2>&1 && systemctl is-active -q ufw 2>/dev/null; then fw=ufw
fi
fi
step "4/5" "Firewall"
if [ -n "$fw" ]; then
note "$fw is active and will block port $port until it is opened."
blank
if confirm "Open $port/tcp in $fw?" y; then open_fw=1; fi
elif [ "$host" = 127.0.0.1 ]; then good "nothing to open: it only listens on this machine"
else good "no active firewalld or ufw found; nothing to open"
fi
# 5 ─ password
step "5/5" "The password" "One password opens the console — and the console is a shell on this machine."
choose 1 "Choose one now" "Generate a strong one ${D}— shown once at the end${R}"
if [ "$REPLY" = 1 ]; then
while :; do
secret "Password:"; password=$REPLY
[ ${#password} -ge 12 ] || { warn "at least 12 characters, please (it guards a shell)"; continue; }
secret "Once more:"
[ "$REPLY" = "$password" ] && break
warn "those didn't match; try again"
done
fi
# summary
if [ "$host" = 0.0.0.0 ] || [ "$host" = "::" ]; then url_host=${first:-this-machine}; else url_host=$host; fi
blank; rule
out " ${B}Ready to install${R}"
blank
out " version ${B}$ver${R} ${D}($file)${R}"
out " runs as ${B}$run_as${R}"
out " address ${B}$scheme://$listen${R}"
if [ "$open_fw" = 1 ]; then out " firewall open $port/tcp in $fw"; fi
if [ -n "$password" ]; then out " password the one you typed"; else out " password generated, shown once"; fi
case "$init" in none) out " service ${AMBER}none — no systemd or OpenRC${R}" ;; *) out " service $init, starts at boot" ;; esac
rule; blank
confirm "Install?" y || { blank; out " nothing was changed"; exit 0; }
flags="--user $run_as --listen $listen --tls $tls"
[ "$open_fw" = 0 ] || flags="$flags --open-firewall"
[ -z "$password" ] || flags="$flags --password-stdin"
fi fi
# ──────────────────────────────────────────────── download and verify ──
blank
if [ "$offline" = 1 ]; then
cp "$here/$file" "$tmp/hamlab"; [ ! -f "$here/SHA256SUMS" ] || cp "$here/SHA256SUMS" "$tmp/SHA256SUMS"
good "using $file from $here"
else
printf ' %s downloading %s …' "$DOT" "$file" >&2
fetch "$HAMLAB_URL/$file" "$tmp/hamlab" || { printf '\n' >&2; die "Download failed: $HAMLAB_URL/$file"; }
size=$(wc -c <"$tmp/hamlab" | awk '{ printf "%.1f MB", $1 / 1048576 }')
if [ -t 2 ]; then printf '\r\033[K' >&2; else printf '\n' >&2; fi
good "downloaded $file ${D}($size)${R}"
fetch "$HAMLAB_URL/SHA256SUMS" "$tmp/SHA256SUMS" 2>/dev/null || rm -f "$tmp/SHA256SUMS"
fi
if [ -f "$tmp/SHA256SUMS" ] && command -v sha256sum >/dev/null 2>&1; then if [ -f "$tmp/SHA256SUMS" ] && command -v sha256sum >/dev/null 2>&1; then
want=$(awk -v f="$file" '$2 == f || $2 == "*" f { print $1 }' "$tmp/SHA256SUMS") want=$(awk -v f="$file" '$2 == f || $2 == "*" f { print $1 }' "$tmp/SHA256SUMS")
got=$(sha256sum "$tmp/hamlab" | awk '{ print $1 }') got=$(sha256sum "$tmp/hamlab" | awk '{ print $1 }')
[ -n "$want" ] || die "SHA256SUMS has no entry for $file" [ -n "$want" ] || die "SHA256SUMS has no entry for $file."
[ "$want" = "$got" ] || die "checksum mismatch for $file" [ "$want" = "$got" ] || die "Checksum mismatch for $file — the download is not what was published. Nothing was installed."
good "checksum matches SHA256SUMS"
else
warn "no SHA256SUMS (or no sha256sum here): the download was not verified"
fi fi
chmod 0755 "$tmp/hamlab" chmod 0755 "$tmp/hamlab"; bin="$tmp/hamlab"
bin="$tmp/hamlab"
if ! "$bin" version >/dev/null 2>&1; then if ! "$bin" version >/dev/null 2>&1; then
# a noexec /tmp is the usual reason: try from the home directory alt="${HOME:-/root}/.hamlab-install.$$" # a noexec /tmp is the usual reason: try from the home directory
alt="${HOME:-/root}/.hamlab-install.$$"
trap 'rm -rf "$tmp" "$alt"' EXIT INT TERM
cp "$bin" "$alt" 2>/dev/null && chmod 0755 "$alt" || true cp "$bin" "$alt" 2>/dev/null && chmod 0755 "$alt" || true
"$alt" version >/dev/null 2>&1 || die "the $arch build doesn't run on this machine" "$alt" version >/dev/null 2>&1 || die "The $arch build doesn't run on this machine."
bin="$alt" bin="$alt"
fi fi
# Piped from curl, stdin is this script: take the password prompt from the terminal. # ───────────────────────────────────────────────────────────── install ──
case " $* " in *password-stdin*) piped=0 ;; *) piped=1 ;; esac blank; out " ${B}Installing${R}"; blank
if [ "$piped" = 1 ] && [ ! -t 0 ] && [ -r /dev/tty ] && (: </dev/tty) 2>/dev/null; then log="$tmp/install.log"
"$bin" install "$@" </dev/tty set +e
# shellcheck disable=SC2086 # $flags and $PASS are lists of words on purpose
if [ -n "$password" ]; then
printf '%s\n' "$password" | "$bin" install $flags >"$log" 2>&1; rc=$?
password=
elif [ "$INTERACTIVE" = 0 ] && [ -n "$PASS" ]; then
log=
case " $PASS " in
*password-stdin*) "$bin" install $PASS; rc=$? ;;
*) if [ ! -t 0 ] && have_tty; then "$bin" install $PASS <"$TTY"; rc=$?; else "$bin" install $PASS; rc=$?; fi ;;
esac
else else
"$bin" install "$@" "$bin" install $flags </dev/null >"$log" 2>&1; rc=$? # no typed password and no terminal on stdin: it generates one and prints it
fi fi
set -e
[ -z "$log" ] || sed 's/^/ /' "$log" >&2
hamlab_bin=$(command -v hamlab 2>/dev/null || echo /usr/local/bin/hamlab)
[ "$rc" = 0 ] && [ -x "$hamlab_bin" ] || die "The install did not finish. Nothing above this line is hidden: the reason is in it."
# ──────────────────────────────────────────────────────────────── done ──
blank; rule
out " ${GREEN}${B}${OK} Ham Lab $("$hamlab_bin" version 2>/dev/null | awk '{ print $2 }') is installed${R}"
blank
if [ "$init" = none ]; then
out " start it ${B}hamlab serve${R} ${D}as $([ -n "${run_as:-}" ] && echo "$run_as" || echo "its user") — nothing here starts it at boot, so put that under your supervisor${R}"
fi
if [ -n "$listen" ]; then
out " open ${CYAN}${B}$scheme://$(printf '%s' "$listen" | sed "s/^0\.0\.0\.0/$url_host/")${R}"
[ "$tls" != auto ] || out " ${D}your browser will warn about the self-signed certificate once; that is expected${R}"
[ "$host" != 127.0.0.1 ] || out " ${D}from another machine: ssh -L $port:127.0.0.1:$port $run_as@<this machine>, then http://127.0.0.1:$port${R}"
fi
out " manage ${B}hamlab install --help${R} ${D}change the address, HTTPS, the user — it keeps everything else${R}"
case "$init" in
systemd) out " logs ${B}journalctl -u hamlab -f${R}" ;;
OpenRC) out " logs ${B}tail -f /var/log/hamlab.log${R}" ;;
esac
out " add to hub ${D}on your main Ham Lab: Machines ${ARROW} Add a machine, with this address and password${R}"
out " remove ${B}hamlab uninstall${R} ${D}(--purge deletes its config too)${R}"
rule; blank