521 lines
14 KiB
Bash
Executable file
521 lines
14 KiB
Bash
Executable file
#!/bin/sh
|
|
|
|
{
|
|
|
|
set -ue
|
|
|
|
if [ -n "${ZSH_VERSION:-}" ]; then
|
|
emulate sh -o err_exit -o no_unset
|
|
fi
|
|
|
|
readonly url_base=https://github.com/romkatv/tmux-bin/releases/download/v3.1.0
|
|
|
|
readonly archives='
|
|
---------------------
|
|
file:tmux-darwin-arm64.tar.gz; md5:2e312f7555a6395f1d81bfa3b083d710; sha256:134a9afc1184269810af9feae41fdc19bad7d5e0ce90ee7376a22946759d5cd7;
|
|
file:tmux-darwin-x86_64.tar.gz; md5:1857c31a650ef7dada3940b3d45b95f1; sha256:a2f359975ac8b471713e82f91700b75049fed82930bf72678d74ea730dbc89e9;
|
|
file:tmux-linux-aarch64.tar.gz; md5:de566f3edf53cd1a94555495618d99ff; sha256:a8d0b937e124d9bd8bb312c026fc55bfaec4d41fb0f729a52c50de5222d86594;
|
|
file:tmux-linux-armv6l.tar.gz; md5:417ce72afb8f2ff823e75429c9bf7065; sha256:9ddc576b39e35b9186936246bc6e632f2e691be27ea52372eee8bdaf2d51de90;
|
|
file:tmux-linux-armv7l.tar.gz; md5:6750b5cb7993c411d88904e6eeaa8c4c; sha256:9fd3918371c48a4795f22b600a646974a312621611a024792d296f69b26aa2af;
|
|
file:tmux-linux-i386.tar.gz; md5:3e8a9286e6f80c6e9abad5eaf1d85eea; sha256:b8f62934b3ea4817a32c915a98dcc415a762ff5169f9aa0ec367796f505fb6bb;
|
|
file:tmux-linux-i586.tar.gz; md5:7bced5f298d8c59c7638e22b1e1ae6ae; sha256:59b53cc3331c84eee46bd79b55b4289a8ac81853f53233e880bc057e45646620;
|
|
file:tmux-linux-i686.tar.gz; md5:2a411bd0737b00326509da8ba4cf26e0; sha256:520898915c5575da0f06abf89cc044f35f428828de2fa6956ce786fb53d983f7;
|
|
file:tmux-linux-x86_64.tar.gz; md5:6aa7a656836540efadaf4b45ac7312fe; sha256:2e16b79a6638c9b450eb7a807696ea21395761f2d9a7ee8036d1a396be3cf643;'
|
|
|
|
readonly lf="
|
|
"
|
|
|
|
if [ -t 1 ]; then
|
|
readonly _0="$(printf '\033[0m')"
|
|
readonly _B="$(printf '\033[1m')"
|
|
readonly _U="$(printf '\033[4m')"
|
|
readonly _R="$(printf '\033[31m')"
|
|
readonly _G="$(printf '\033[32m')"
|
|
readonly _Y="$(printf '\033[33m')"
|
|
else
|
|
readonly _0=
|
|
readonly _B=
|
|
readonly _U=
|
|
readonly _R=
|
|
readonly _G=
|
|
readonly _Y=
|
|
fi
|
|
|
|
usage="$(cat <<END
|
|
Usage: install [OPTIONS] [-a <sha256|md5>]...
|
|
[OPTIONS] -f FILE
|
|
[OPTIONS] -u URL
|
|
|
|
If '-f FILE' is specified, install tmux from the specified *.tar.gz
|
|
file produced by the build script.
|
|
|
|
If '-u URL' is specified, download the file and install as if with
|
|
'-f FILE'.
|
|
|
|
If neither '-f' nor '-u' is specified, download the appopriate file
|
|
from https://github.com/romkatv/tmux-bin/releases and install as if
|
|
with '-f FILE'. If '-a <sha256|md5>' is specified at least once,
|
|
abort installation if integrity of the downloaded package cannot
|
|
be verified with at least one of the listed hashing algorithms.
|
|
|
|
Options:
|
|
|
|
-q
|
|
|
|
Produce no output on success.
|
|
|
|
-d DIR
|
|
|
|
Install to this directory. If specified more than once, present
|
|
an interactive dialog to choose the directory. Empty argument
|
|
means a custom directory (requires manual user input). If '-d'
|
|
is not specified, the effect is idential to this:
|
|
|
|
-d /usr/local -d ~/.local -d ""
|
|
|
|
Except on Termux:
|
|
|
|
-d "\$PREFIX"/local -d ~/.local -d ""
|
|
|
|
-s FD
|
|
|
|
On success, write the path to the installation directory to this
|
|
file descriptor.
|
|
END
|
|
)"
|
|
|
|
absfile() {
|
|
if [ ! -e "$1" ]; then
|
|
>&2 echo "${_R}error${_0}: file not found: ${_U}$1${_0}"
|
|
return 1
|
|
fi
|
|
local dir base
|
|
dir="$(dirname -- "$1")"
|
|
base="$(basename -- "$1")"
|
|
( cd -- "$dir" && dir="$(pwd)" && printf '%s/%s\n' "${dir%/}" "${base}" )
|
|
}
|
|
|
|
check_dir() {
|
|
if [ -z "$1" ]; then
|
|
>&2 echo "${_R}error${_0}: directory cannot be empty string"
|
|
exit 1
|
|
fi
|
|
if [ -z "${1##~*}" ]; then
|
|
>&2 echo "${_R}error${_0}: please expand ${_U}~${_0} in directory name: ${_U}$1${_0}"
|
|
exit 1
|
|
fi
|
|
if [ -z "${1##//*}" ]; then
|
|
>&2 echo "${_R}error${_0}: directory cannot start with ${_U}//${_0}: ${_U}$1${_0}"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
add_dir() {
|
|
num_dirs=$((num_dirs + 1))
|
|
dirs="$dirs${num_dirs}${1}${lf}"
|
|
if [ -n "$1" ]; then
|
|
dirs_c="$dirs_c ${_B}($num_dirs)${_0} ${_U}${1}${_0}${lf}"
|
|
else
|
|
dirs_c="$dirs_c ${_B}($num_dirs)${_0} custom directory (input required)${lf}"
|
|
fi
|
|
}
|
|
|
|
check_sudo() {
|
|
local dir="$1"
|
|
sudo=
|
|
while true; do
|
|
if [ -e "$dir" ]; then
|
|
if [ ! -d "$dir" ]; then
|
|
>&2 echo "${_R}error${_0}: not a directory: ${_U}$dir${_0}"
|
|
return 1
|
|
fi
|
|
if [ ! -w "$dir" ]; then
|
|
if [ "$euid" = 0 ]; then
|
|
>&2 echo "${_R}error${_0}: directory not writable: ${_U}$dir${_0}"
|
|
return 1
|
|
else
|
|
if [ -z "$quiet" ]; then
|
|
echo "${_Y}===>${_0} using ${_U}${_G}sudo${_0} for installation"
|
|
fi
|
|
sudo=sudo
|
|
fi
|
|
fi
|
|
break
|
|
fi
|
|
if [ "$dir" = / ] || [ "$dir" = . ]; then
|
|
break
|
|
fi
|
|
dir="$(dirname -- "$dir")"
|
|
done
|
|
}
|
|
|
|
dirs=
|
|
dirs_c=
|
|
num_dirs=0
|
|
quiet=
|
|
algos=
|
|
url=
|
|
file=
|
|
sudo=
|
|
fd=
|
|
asked=
|
|
|
|
command -v sudo >/dev/null 2>&1 && euid="$(id -u 2>/dev/null)" || euid=0
|
|
|
|
while getopts ':hqd:s:a:f:u:' opt "$@"; do
|
|
case "$opt" in
|
|
h)
|
|
printf '%s\n' "$usage"
|
|
exit
|
|
;;
|
|
q)
|
|
if [ -n "$quiet" ]; then
|
|
>&2 echo "${_R}error${_0} duplicate option: ${_B}-${opt}${_0}"
|
|
exit 1
|
|
fi
|
|
quiet=1
|
|
;;
|
|
d)
|
|
if printf "%s" "$dirs" | cut -b 2- | grep -qxF -- "$OPTARG"; then
|
|
>&2 echo "${_R}error${_0}: duplicate option: ${_B}-${opt} ${OPTARG}${_0}"
|
|
exit 1
|
|
fi
|
|
if [ "$(printf "%s" "$OPTARG" | wc -l | tr -Cd '0-9')" != 0 ]; then
|
|
>&2 echo "${_R}error${_0}: incorrect value of ${_B}-${opt}${_0}: ${_B}${OPTARG}${_0}"
|
|
exit 1
|
|
fi
|
|
if [ "$num_dirs" = 9 ]; then
|
|
>&2 echo "${_R}error${_0}: too many options: ${_B}-${opt}${_0}"
|
|
exit 1
|
|
fi
|
|
if [ -n "$OPTARG" ]; then
|
|
check_dir "$OPTARG"
|
|
fi
|
|
add_dir "$OPTARG"
|
|
;;
|
|
s)
|
|
if [ -n "$fd" ]; then
|
|
>&2 echo "${_R}error${_0} duplicate option: ${_B}-${opt}${_0}"
|
|
exit 1
|
|
fi
|
|
if ! printf '%s' "$OPTARG" | tr '\n' x | grep -qxE '[1-9][0-9]*'; then
|
|
>&2 echo "${_R}error${_0}: incorrect value of ${_B}-${opt}${_0}: ${_B}${OPTARG}${_0}"
|
|
exit 1
|
|
fi
|
|
fd="$OPTARG"
|
|
;;
|
|
a)
|
|
case "$OPTARG" in
|
|
sha256|md5)
|
|
if [ -n "$algos" -a -z "${algos##*<$OPTARG>*}" ]; then
|
|
>&2 echo "${_R}error${_0}: duplicate option: ${_B}-${opt} ${OPTARG}${_0}"
|
|
exit 1
|
|
fi
|
|
algos="$algos<$OPTARG>"
|
|
;;
|
|
*)
|
|
>&2 echo "${_R}error${_0}: incorrect value of ${_B}-${opt}${_0}: ${_B}${OPTARG}${_0}"
|
|
exit 1
|
|
;;
|
|
esac
|
|
;;
|
|
f)
|
|
if [ -n "$file" ]; then
|
|
>&2 echo "${_R}error${_0}: duplicate option: ${_B}-${opt}${_0}"
|
|
exit 1
|
|
fi
|
|
if [ -z "$OPTARG" ]; then
|
|
>&2 echo "${_R}error${_0}: incorrect value of ${_B}-${opt}${_0}: ${_B}${OPTARG}${_0}"
|
|
exit 1
|
|
fi
|
|
file="$(absfile "$OPTARG")"
|
|
;;
|
|
u)
|
|
if [ -n "$url" ]; then
|
|
>&2 echo "${_R}error${_0}: duplicate option: ${_B}-${opt}${_0}"
|
|
exit 1
|
|
fi
|
|
if [ -z "$OPTARG" ]; then
|
|
>&2 echo "${_R}error${_0}: incorrect value of ${_B}-${opt}${_0}: ${_B}${OPTARG}${_0}"
|
|
exit 1
|
|
fi
|
|
url="$OPTARG"
|
|
;;
|
|
\?) >&2 echo "${_R}error${_0}: invalid option: ${_B}-${OPTARG}${_0}" ; exit 1;;
|
|
:) >&2 echo "${_R}error${_0}: missing required argument: ${_B}-${OPTARG}${_0}"; exit 1;;
|
|
*) >&2 echo "${_R}internal error${_0}: unhandled option: ${_B}-${opt}${_0}" ; exit 1;;
|
|
esac
|
|
done
|
|
|
|
if [ "$OPTIND" -le $# ]; then
|
|
>&2 echo "${_R}error${_0}: unexpected positional argument"
|
|
return 1
|
|
fi
|
|
|
|
if [ -n "$algos" ]; then
|
|
if [ -n "$file" ]; then
|
|
>&2 echo "${_R}error${_0}: incompatible options: ${_B}-f${_0} and ${_B}-a${_0}"
|
|
exit 1
|
|
fi
|
|
if [ -n "$url" ]; then
|
|
>&2 echo "${_R}error${_0}: incompatible options: ${_B}-u${_0} and ${_B}-a${_0}"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
if [ "$num_dirs" = 0 ]; then
|
|
if [ "$(uname -s 2>/dev/null)" = Linux ] &&
|
|
[ "$(uname -o 2>/dev/null)" = Android ] &&
|
|
[ -d "${PREFIX:-/data/data/com.termux/files/usr}" ]; then
|
|
usr_local="${PREFIX:-/data/data/com.termux/files/usr}"/local
|
|
usr_local_d="${_U}\$PREFIX/local${_0}"
|
|
else
|
|
usr_local=/usr/local
|
|
usr_local_d="${_U}/usr/local${_0} "
|
|
fi
|
|
|
|
add_dir "$usr_local"
|
|
add_dir ~/.local
|
|
add_dir ""
|
|
|
|
dirs_c=" ${_B}(1)${_0} $usr_local_d ${_Y}<=${_0}"
|
|
if check_sudo "$usr_local" >/dev/null 2>/dev/null; then
|
|
if [ -n "$sudo" ]; then
|
|
dirs_c="${dirs_c} uses ${_U}${_G}sudo${_0}"
|
|
else
|
|
dirs_c="${dirs_c} does not need ${_U}${_G}sudo${_0}"
|
|
fi
|
|
if [ -d "$usr_local" ]; then
|
|
dirs_c="${dirs_c} (${_B}recommended${_0})"
|
|
fi
|
|
else
|
|
dirs_c="${dirs_c} ${_R}not writable${_0}"
|
|
fi
|
|
|
|
dirs_c="${dirs_c}${lf} ${_B}(2)${_0} ${_U}~/.local${_0} ${_Y}<=${_0}"
|
|
if check_sudo ~/.local >/dev/null 2>/dev/null; then
|
|
if [ -n "$sudo" ]; then
|
|
dirs_c="${dirs_c} uses ${_U}${_G}sudo${_0}"
|
|
else
|
|
dirs_c="${dirs_c} does not need ${_U}${_G}sudo${_0}"
|
|
fi
|
|
else
|
|
dirs_c="${dirs_c} ${_R}not writable${_0}"
|
|
fi
|
|
|
|
dirs_c="${dirs_c}${lf} ${_B}(3)${_0} custom directory ${_Y}<=${_0} manual input required${lf}"
|
|
fi
|
|
|
|
if [ "$num_dirs" = 1 ]; then
|
|
choice=1
|
|
else
|
|
while true; do
|
|
echo "Choose installation directory for ${_G}tmux${_0}:"
|
|
echo ""
|
|
printf "%s" "$dirs_c"
|
|
echo ""
|
|
printf "Choice: "
|
|
read -r choice
|
|
if printf "%s" "$dirs" | cut -b 1 | grep -qxF -- "$choice"; then
|
|
break
|
|
fi
|
|
if [ -n "$choice" ]; then
|
|
>&2 echo "Invalid choice: ${_R}$choice${_0}. Try again."
|
|
fi
|
|
echo
|
|
done
|
|
asked=1
|
|
fi
|
|
|
|
dir="$(printf "%s" "$dirs" | sed "${choice}!d" | cut -b 2-)"
|
|
if [ -z "$dir" ]; then
|
|
printf "Custom directory: "
|
|
read -r dir
|
|
check_dir "$dir"
|
|
if [ -z "$quiet" ]; then
|
|
echo
|
|
fi
|
|
asked=1
|
|
elif [ -z "$quiet" ] && [ "$num_dirs" != 1 ]; then
|
|
echo
|
|
fi
|
|
|
|
if [ -z "$quiet" ]; then
|
|
printf "%s\n" "${_Y}===>${_0} installing ${_G}tmux${_0} to ${_U}$dir${_0}"
|
|
fi
|
|
|
|
check_sudo "$dir"
|
|
|
|
$sudo mkdir -p -- "$dir"
|
|
cd -- "$dir"
|
|
dir="$(pwd)"
|
|
|
|
if [ -z "$file" -a -z "$url" ]; then
|
|
kernel="$(uname -s | tr '[A-Z]' '[a-z]')"
|
|
arch="$(uname -m | tr '[A-Z]' '[a-z]')"
|
|
|
|
case "$kernel" in
|
|
linux-armv8l) kernel=linux-aarch64;;
|
|
msys_nt-6.*) kernel=msys_nt-10.0;;
|
|
msys_nt-10.*) kernel=msys_nt-10.0;;
|
|
mingw32_nt-6.*) kernel=msys_nt-10.0;;
|
|
mingw32_nt-10.*) kernel=msys_nt-10.0;;
|
|
mingw64_nt-6.*) kernel=msys_nt-10.0;;
|
|
mingw64_nt-10.*) kernel=msys_nt-10.0;;
|
|
cygwin_nt-6.*) kernel=cygwin_nt-10.0;;
|
|
cygwin_nt-10.*) kernel=cygwin_nt-10.0;;
|
|
esac
|
|
|
|
filename="tmux-${kernel}-${arch}.tar.gz"
|
|
url="$url_base/$filename"
|
|
|
|
if [ -n "${archives##*file:$filename;*}" ]; then
|
|
>&2 echo "${_R}error${_0}: there is no prebuilt binary for your architecture"
|
|
>&2 echo
|
|
>&2 echo "See ${_U}https://github.com/romkatv/tmux-bin#compiling${_0} for building one."
|
|
exit 1
|
|
fi
|
|
|
|
check_sig=1
|
|
else
|
|
check_sig=0
|
|
fi
|
|
|
|
if [ -n "$url" ]; then
|
|
if [ -n "${TMPDIR-}" -a '(' '(' -d "${TMPDIR-}" -a -w "${TMPDIR-}" ')' -o '!' '(' -d /tmp -a -w /tmp ')' ')' ]; then
|
|
tmpdir="$TMPDIR"
|
|
else
|
|
tmpdir=/tmp
|
|
fi
|
|
file="$tmpdir"/tmux-bin.tmp.$$.tar.gz
|
|
cleanup() { rm -f -- "$file"; }
|
|
trap cleanup INT QUIT TERM EXIT ILL PIPE
|
|
|
|
if [ -z "$quiet" ]; then
|
|
echo "${_Y}===>${_0} fetching ${_U}${url##*/}${_0}"
|
|
fi
|
|
|
|
(
|
|
cd -- "${file%/*}"
|
|
file="${file##*/}"
|
|
|
|
set +e
|
|
|
|
if command -v curl >/dev/null 2>&1; then
|
|
err="$(command curl -fsSLo "$file" -- "$url" 2>&1)"
|
|
elif command -v wget >/dev/null 2>&1; then
|
|
err="$(command wget -O "$file" -- "$url" 2>&1)"
|
|
else
|
|
>&2 echo "${_R}error${_0}: please install ${_G}curl${_0} or ${_G}wget${_0} and retry"
|
|
exit 1
|
|
fi
|
|
|
|
if [ $? != 0 ]; then
|
|
>&2 printf "%s\n" "$err"
|
|
>&2 echo "${_R}error${_0}: failed to download ${_U}$url${_0}"
|
|
exit 1
|
|
fi
|
|
)
|
|
else
|
|
cleanup() { true; }
|
|
fi
|
|
|
|
if [ "$check_sig" = 1 ]; then
|
|
if [ -z "$quiet" ]; then
|
|
echo "${_Y}===>${_0} verifying archive integrity"
|
|
fi
|
|
|
|
for algo in sha256 md5; do
|
|
hash=none
|
|
case "$algo" in
|
|
sha256)
|
|
{
|
|
command -v shasum >/dev/null 2>/dev/null &&
|
|
hash="$(shasum -b -a 256 -- "$file" </dev/null 2>/dev/null)" &&
|
|
hash="${hash%% *}" &&
|
|
[ ${#hash} -eq 64 ]
|
|
} || {
|
|
command -v sha256sum >/dev/null 2>/dev/null &&
|
|
hash="$(sha256sum -b -- "$file" </dev/null 2>/dev/null)" &&
|
|
hash="${hash%% *}" &&
|
|
[ ${#hash} -eq 64 ]
|
|
} || {
|
|
# Note: sha256 can be from hashalot. It's incompatible.
|
|
# Thankfully, it produces shorter output.
|
|
command -v sha256 >/dev/null 2>/dev/null &&
|
|
hash="$(sha256 -- "$file" </dev/null 2>/dev/null)" &&
|
|
hash="${hash##* }" &&
|
|
[ ${#hash} -eq 64 ]
|
|
} || {
|
|
hash=none
|
|
}
|
|
;;
|
|
md5)
|
|
{
|
|
command -v md5sum >/dev/null 2>/dev/null &&
|
|
hash="$(md5sum -b -- "$file" </dev/null 2>/dev/null)" &&
|
|
hash="${hash%% *}" &&
|
|
[ ${#hash} -eq 32 ]
|
|
} || {
|
|
command -v md5 >/dev/null 2>/dev/null &&
|
|
hash="$(md5 -- "$file" </dev/null 2>/dev/null)" &&
|
|
hash="${hash##* }" &&
|
|
[ ${#hash} -eq 32 ]
|
|
} || {
|
|
hash=none
|
|
}
|
|
;;
|
|
*)
|
|
>&2 echo "${_R}internal error${_0}: unhandled algorithm: ${_B}$algo${_0}"
|
|
exit 1
|
|
;;
|
|
esac
|
|
if [ "$hash" != none ]; then
|
|
if [ -n "${archives##* $algo:$hash;*}" ]; then
|
|
>&2 echo "${_R}error${_0}: ${_B}$algo${_0} signature mismatch"
|
|
>&2 echo ""
|
|
>&2 echo "Expected:"
|
|
>&2 echo ""
|
|
>&2 echo " ${_G}$(printf "%s" "$archives" | grep -F -- "${url##*/}" | sed 's/ */ /g')${_0}"
|
|
>&2 echo ""
|
|
>&2 echo "Found:"
|
|
>&2 echo ""
|
|
>&2 echo " ${_R}$algo:$hash${_0}"
|
|
exit 1
|
|
fi
|
|
if [ -z "$quiet" ]; then
|
|
echo "${_Y}===>${_0} ${_B}$algo${_0} signature matches"
|
|
fi
|
|
algos="${algos##*<$algo>*}"
|
|
else
|
|
if [ -z "$quiet" ]; then
|
|
echo "${_Y}===>${_0} no tools to verify ${_B}$algo${_0} signature"
|
|
fi
|
|
fi
|
|
done
|
|
fi
|
|
|
|
if [ -n "$algos" ]; then
|
|
>&2 echo "${_R}error${_0}: no tools available to verify archive integrity"
|
|
exit 1
|
|
fi
|
|
|
|
if [ -z "$quiet" ]; then
|
|
echo "${_Y}===>${_0} extracting files"
|
|
fi
|
|
|
|
$sudo tar -xzf "$file"
|
|
|
|
cleanup
|
|
|
|
if [ -z "$quiet" ]; then
|
|
echo ""
|
|
echo "Installed ${_G}tmux${_0} to ${_U}$dir${_0}"
|
|
echo
|
|
fi
|
|
|
|
if [ -n "$fd" ]; then
|
|
printf "%s\n" "$dir" >&"$fd"
|
|
fi
|
|
|
|
}
|