Repository navigation
Expand file tree
/
Copy pathinstall.sh
More file actions
executable file
·134 lines (115 loc) · 5.04 KB
/
Copy pathinstall.sh
File metadata and controls
executable file
·134 lines (115 loc) · 5.04 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
#!/bin/sh
# lich installer — detects the distro, downloads the matching package from the
# latest GitHub release, verifies its checksum and installs it through the
# native package manager (which also resolves the runtime dependencies).
#
# curl -fsSL https://raw.githubusercontent.com/lichdotdev/lich/main/install.sh | sh
#
# POSIX sh, no bashisms; everything runs inside main() so a truncated
# download executes nothing.
set -eu
REPO="lichdotdev/lich"
API="https://api.github.com/repos/${REPO}/releases/latest"
info() { printf '\033[1;34m==>\033[0m %s\n' "$*"; }
fail() { printf '\033[1;31merror:\033[0m %s\n' "$*" >&2; exit 1; }
# detect_family prints deb, rpm or arch by reading /etc/os-release
# (ID first, then ID_LIKE so derivatives map to their parent).
detect_family() {
[ -r /etc/os-release ] || fail "cannot read /etc/os-release — unsupported system"
# shellcheck disable=SC1091
. /etc/os-release
for id in ${ID:-} ${ID_LIKE:-}; do
case "$id" in
debian | ubuntu) echo deb; return ;;
fedora | rhel | centos) echo rpm; return ;;
arch) echo arch; return ;;
esac
done
fail "unsupported distro '${ID:-unknown}': grab a package or the tarball from https://github.com/${REPO}/releases"
}
# latest_tag prints the tag name of the latest release, without jq. The JSON
# is captured before parsing so grep closing the pipe never trips curl.
latest_tag() {
json="$(curl -fsSL "$API")" || return 1
printf '%s\n' "$json" | grep -m1 '"tag_name"' | sed 's/.*"tag_name": *"\([^"]*\)".*/\1/'
}
# have reports whether a command exists on PATH.
have() { command -v "$1" >/dev/null 2>&1; }
# as_root runs a command with sudo unless already root.
as_root() {
if [ "$(id -u)" -eq 0 ]; then "$@"; else sudo "$@"; fi
}
# The window ships inside the package (lich's own Chromium); zenity, the
# folder picker, is the one runtime dependency left to check for.
check_runtime_deps() {
if have zenity; then
info "runtime dependencies present (zenity)"
else
info "still missing: zenity (the folder picker)"
info "install through your package manager, e.g.: $1"
fi
}
# restart_running_lich asks a running lich to relaunch into the freshly
# installed binary, so the user does not have to close and reopen it. It is
# best-effort: the loopback port and token come from the lich session env (when
# this runs inside a lich terminal) or from lich's runtime file; if lich is not
# running, or the token no longer matches, the POST simply fails and is ignored.
restart_running_lich() {
port="${LICH_PORT:-}"
token="${LICH_TOKEN:-}"
if [ -z "$port" ] || [ -z "$token" ]; then
rt="${XDG_CONFIG_HOME:-$HOME/.config}/lich/runtime.json"
[ -r "$rt" ] || return 0
# Parsing assumes lich's own compact json.Marshal output (no spaces); it is
# lich's file, written that way, so the greps below are safe.
pid="$(grep -o '"pid":[0-9]*' "$rt" | head -n1 | sed 's/.*://')"
# Skip a stale file left by a crashed lich: no live process, no restart.
[ -n "$pid" ] && kill -0 "$pid" 2>/dev/null || return 0
port="$(grep -o '"port":[0-9]*' "$rt" | head -n1 | sed 's/.*://')"
token="$(sed -n 's/.*"token":"\([^"]*\)".*/\1/p' "$rt")"
fi
[ -n "$port" ] && [ -n "$token" ] || return 0
info "restarting lich"
# --max-time so a wedged old process never blocks the installer; the handler
# answers 204 before it tears down, so this returns immediately in practice.
curl -fsS --max-time 5 -X POST "http://127.0.0.1:${port}/restart?token=${token}" >/dev/null 2>&1 || true
}
main() {
[ "$(uname -s)" = "Linux" ] || fail "lich is Linux-only"
[ "$(uname -m)" = "x86_64" ] || fail "releases ship x86_64 only — build from source: https://github.com/${REPO}"
have curl || fail "curl is required"
have sha256sum || fail "sha256sum is required"
family="$(detect_family)"
tag="$(latest_tag)"
[ -n "$tag" ] || fail "could not resolve the latest release from ${API}"
case "$family" in
deb) asset="lich-${tag}-amd64.deb" ;;
rpm) asset="lich-${tag}-x86_64.rpm" ;;
arch) asset="lich-${tag}-x86_64.pkg.tar.zst" ;;
esac
base="https://github.com/${REPO}/releases/download/${tag}"
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
info "downloading ${asset} (${tag})"
curl -fsSL -o "${tmp}/${asset}" "${base}/${asset}"
curl -fsSL -o "${tmp}/checksums.txt" "${base}/checksums.txt"
info "verifying checksum"
(cd "$tmp" && grep " ${asset}\$" checksums.txt | sha256sum -c -) \
|| fail "checksum mismatch for ${asset} — aborting"
info "installing ${asset}"
case "$family" in
# apt/dnf resolve the Recommends (zenity) on their own; pacman has no
# Recommends, so arch relies on the check below.
deb) as_root apt-get install -y "${tmp}/${asset}" ;;
rpm) as_root dnf install -y "${tmp}/${asset}" ;;
arch) as_root pacman -U --noconfirm "${tmp}/${asset}" ;;
esac
case "$family" in
deb) check_runtime_deps "sudo apt-get install zenity" ;;
rpm) check_runtime_deps "sudo dnf install zenity" ;;
arch) check_runtime_deps "sudo pacman -S zenity" ;;
esac
restart_running_lich
info "done — run 'lich'"
}
main "$@"