mirror of
https://github.com/romkatv/powerlevel10k
synced 2024-12-23 14:32:18 +00:00
a6009c74a9
1a80249d build: verify libgit2 tarball sha256 74c3d56f bash: call mktemp only once and avoid `mktemp -u` b139dec4 install: use mktemp if available 9f594d24 bash: block SIGQUIT and SIGTSTP in daemon 73f47ea3 add sha256 verification for downloaded gitstatusd; enable gitee mirror git-subtree-dir: gitstatus git-subtree-split: 1a80249d2b6a53fd076ae846f8fcc501183ca5a5
378 lines
11 KiB
Bash
Executable File
378 lines
11 KiB
Bash
Executable File
#!/bin/sh
|
|
#
|
|
# This script does not have a stable API.
|
|
|
|
_gitstatus_install_main() {
|
|
if [ -n "${ZSH_VERSION:-}" ]; then
|
|
emulate -L sh -o no_unset
|
|
else
|
|
set -u
|
|
fi
|
|
|
|
local argv1=$1
|
|
shift
|
|
|
|
local no_check= no_install= uname_s= uname_m= gitstatus_dir= dl_status=
|
|
local opt= OPTARG= OPTIND=1
|
|
|
|
while getopts ':s:m:d:p:fnh' opt "$@"; do
|
|
case "$opt" in
|
|
h)
|
|
command cat <<\END
|
|
Usage: install [-s KERNEL] [-m ARCH] [-d DIR] [-p CMD] [-f|-n] [-- CMD [ARG]...]
|
|
|
|
If positional arguments are specified, call this on success:
|
|
|
|
CMD [ARG]... DAEMON VERSION INSTALLED
|
|
|
|
DAEMON is path to gitstatusd. VERSION is a glob pattern for the
|
|
version this daemon should support; it's supposed to be passed as
|
|
-G to gitstatusd. INSTALLED is 1 if gitstatusd has just been
|
|
downloaded and 0 otherwise.
|
|
|
|
Options:
|
|
|
|
-s KERNEL use this instead of lowercase `uname -s`
|
|
-m ARCH use this instead of lowercase `uname -m`
|
|
-d DIR use this instead of `dirname "$0"`
|
|
-p CMD eval this every second while downloading gitstatusd
|
|
-f download gitstatusd even if there is one locally
|
|
-n do not download gitstatusd (fail instead)
|
|
END
|
|
return
|
|
;;
|
|
n)
|
|
if [ -n "$no_install" ]; then
|
|
>&2 echo "[gitstatus] error: duplicate option: -$opt"
|
|
return 1
|
|
fi
|
|
no_install=1
|
|
;;
|
|
f)
|
|
if [ -n "$no_check" ]; then
|
|
>&2 echo "[gitstatus] error: duplicate option: -$opt"
|
|
return 1
|
|
fi
|
|
no_check=1
|
|
;;
|
|
d)
|
|
if [ -n "$gitstatus_dir" ]; then
|
|
>&2 echo "[gitstatus] error: duplicate option: -$opt"
|
|
return 1
|
|
fi
|
|
if [ -z "$OPTARG" ]; then
|
|
>&2 echo "[error] incorrect value of -$opt: $OPTARG"
|
|
return 1
|
|
fi
|
|
gitstatus_dir="$OPTARG"
|
|
;;
|
|
p)
|
|
if [ -n "$dl_status" ]; then
|
|
>&2 echo "[gitstatus] error: duplicate option: -$opt"
|
|
return 1
|
|
fi
|
|
if [ -z "$OPTARG" ]; then
|
|
>&2 echo "[error] incorrect value of -$opt: $OPTARG"
|
|
return 1
|
|
fi
|
|
dl_status="$OPTARG"
|
|
;;
|
|
m)
|
|
if [ -n "$uname_m" ]; then
|
|
>&2 echo "[gitstatus] error: duplicate option: -$opt"
|
|
return 1
|
|
fi
|
|
if [ -z "$OPTARG" ]; then
|
|
>&2 echo "[error] incorrect value of -$opt: $OPTARG"
|
|
return 1
|
|
fi
|
|
uname_m="$OPTARG"
|
|
;;
|
|
s)
|
|
if [ -n "$uname_s" ]; then
|
|
>&2 echo "[gitstatus] error: duplicate option: -$opt"
|
|
return 1
|
|
fi
|
|
if [ -z "$OPTARG" ]; then
|
|
>&2 echo "[error] incorrect value of -$opt: $OPTARG"
|
|
return 1
|
|
fi
|
|
uname_s="$OPTARG"
|
|
;;
|
|
\?) >&2 echo "[gitstatus] error: invalid option: -$OPTARG" ; return 1;;
|
|
:) >&2 echo "[gitstatus] error: missing required argument: -$OPTARG"; return 1;;
|
|
*) >&2 echo "[gitstatus] internal error: unhandled option: -$opt" ; return 1;;
|
|
esac
|
|
done
|
|
|
|
shift "$((OPTIND - 1))"
|
|
|
|
: "${gitstatus_dir:=$argv1}"
|
|
|
|
if [ -n "$no_check" -a -n "$no_install" ]; then
|
|
>&2 echo "[gitstatus] error: incompatible options: -f, -n"
|
|
return 1
|
|
fi
|
|
|
|
if [ -z "$uname_s" ]; then
|
|
uname_s="$(command uname -s)" || return
|
|
uname_s="$(printf '%s' "$uname_s" | command tr '[A-Z]' '[a-z]')" || return
|
|
fi
|
|
if [ -z "$uname_m" ]; then
|
|
uname_m="$(command uname -m)" || return
|
|
uname_m="$(printf '%s' "$uname_m" | command tr '[A-Z]' '[a-z]')" || return
|
|
fi
|
|
|
|
local daemon="${GITSTATUS_DAEMON:-}"
|
|
local cache_dir="${GITSTATUS_CACHE_DIR:-${XDG_CACHE_HOME:-$HOME/.cache}/gitstatus}"
|
|
|
|
if [ -z "$no_check" ]; then
|
|
if [ -n "${daemon##/*}" ]; then
|
|
>&2 echo "[gitstatus] error: GITSTATUS_DAEMON is not absolute path: $daemon"
|
|
return 1
|
|
fi
|
|
if [ -z "$daemon" ]; then
|
|
daemon="$gitstatus_dir"/usrbin/gitstatusd
|
|
if [ ! -e "$daemon" ]; then
|
|
daemon="$daemon"-"$uname_s"-"$uname_m"
|
|
if [ ! -e "$daemon" ]; then
|
|
daemon=
|
|
fi
|
|
fi
|
|
fi
|
|
if [ -n "$daemon" ]; then
|
|
local gitstatus_version= libgit2_version=
|
|
if ! . "$gitstatus_dir"/build.info; then
|
|
>&2 echo "[gitstatus] internal error: failed to source build.info"
|
|
return 1
|
|
fi
|
|
if [ -z "$gitstatus_version" ]; then
|
|
>&2 echo "[gitstatus] internal error: empty gitstatus_version in build.info"
|
|
return 1
|
|
fi
|
|
[ $# = 0 ] || "$@" "$daemon" "$gitstatus_version" 0
|
|
return
|
|
fi
|
|
fi
|
|
|
|
while IFS= read -r line; do
|
|
line="${line###*}"
|
|
[ -n "$line" ] || continue
|
|
|
|
local uname_s_glob= uname_m_glob= file= version= sha256=
|
|
eval "$line" || return
|
|
|
|
if [ -z "$uname_s_glob" -o \
|
|
-z "$uname_m_glob" -o \
|
|
-z "$file" -o \
|
|
-z "$version" -o \
|
|
-z "$sha256" ]; then
|
|
>&2 echo "[gitstatus] internal error: invalid install.info line: $line"
|
|
return 1
|
|
fi
|
|
|
|
case "$uname_s" in
|
|
$uname_s_glob) ;;
|
|
*) continue;;
|
|
esac
|
|
case "$uname_m" in
|
|
$uname_m_glob) ;;
|
|
*) continue;;
|
|
esac
|
|
|
|
# Found a match. The while loop will terminate during this iteration.
|
|
|
|
if [ -z "$no_check" ]; then
|
|
# Check if a suitable gitstatusd already exists.
|
|
local daemon="$cache_dir"/"$file"
|
|
if [ -e "$daemon" ]; then
|
|
[ $# = 0 ] || "$@" "$daemon" "$version" 0
|
|
return
|
|
fi
|
|
daemon="$daemon"-"$uname_s"-"$uname_m"
|
|
if [ -e "$daemon" ]; then
|
|
local gitstatus_version= libgit2_version=
|
|
if ! . "$gitstatus_dir"/build.info; then
|
|
>&2 echo "[gitstatus] internal error: failed to source build.info"
|
|
return 1
|
|
fi
|
|
if [ -z "$gitstatus_version" ]; then
|
|
>&2 echo "[gitstatus] internal error: empty gitstatus_version in build.info"
|
|
return 1
|
|
fi
|
|
[ $# = 0 ] || "$@" "$daemon" "$gitstatus_version" 0
|
|
return
|
|
fi
|
|
fi
|
|
|
|
# No suitable gitstatusd exists. Need to download.
|
|
|
|
if [ -n "$no_install" ]; then
|
|
>&2 echo "[gitstatus] error: no gitstatusd found and installation is disabled"
|
|
return 1
|
|
fi
|
|
|
|
local daemon="$cache_dir"/"$file"
|
|
|
|
if [ -n "${cache_dir##/*}" ]; then
|
|
>&2 echo "[gitstatus] error: GITSTATUS_CACHE_DIR is not absolute: $cache_dir"
|
|
return 1
|
|
fi
|
|
[ -d "$cache_dir" ] || mkdir -p -- "$cache_dir" || return
|
|
|
|
local tmpdir
|
|
if ! command -v mktemp >/dev/null 2>&1 ||
|
|
! tmpdir="$(command mktemp -d "${TMPDIR:-/tmp}"/gitstatus-install.XXXXXXXXXX)"; then
|
|
tmpdir="${TMPDIR:-/tmp}/gitstatus-install.tmp.$$"
|
|
mkdir -p -- "$tmpdir" || return
|
|
fi
|
|
|
|
(
|
|
if [ -n "${ZSH_VERSION:-}" ]; then
|
|
builtin cd -q -- "$tmpdir" || exit
|
|
else
|
|
cd -- "$tmpdir" || exit
|
|
fi
|
|
|
|
local fetch
|
|
if command -v curl >/dev/null 2>&1; then
|
|
fetch="command curl -fsSLo"
|
|
elif command -v wget >/dev/null 2>&1; then
|
|
fetch="command wget -O"
|
|
else
|
|
>&2 echo "[gitstatus] error: please install curl or wget"
|
|
exit 1
|
|
fi
|
|
|
|
local url1="https://github.com/romkatv/gitstatus/releases/download/$version/$file.tar.gz"
|
|
local url2="https://gitee.com/romkatv/gitstatus/raw/release-$version/release/$file.tar.gz"
|
|
|
|
check_sha256() {
|
|
local file="$1".tar.gz
|
|
local hash=
|
|
if command -v shasum >/dev/null 2>/dev/null; then
|
|
hash="$(command shasum -b -a 256 -- "$file")" || hash=
|
|
hash="${hash%% *}"
|
|
elif command -v sha256sum >/dev/null 2>/dev/null; then
|
|
hash="$(command sha256sum -b -- "$file")" || hash=
|
|
hash="${hash%% *}"
|
|
elif command -v sha256 >/dev/null 2>/dev/null; then
|
|
hash="$(command sha256 -- "$file" </dev/null)" || hash=
|
|
# Ignore sha256 output if it's from hashalot. It's incompatible.
|
|
if [ ${#hash} -lt 64 ]; then
|
|
hash=
|
|
else
|
|
hash="${hash##* }"
|
|
fi
|
|
fi
|
|
[ "$1" = 1 -a -z "$hash" -o "$hash" = "$sha256" ]
|
|
}
|
|
|
|
local sig='INT QUIT TERM ILL PIPE'
|
|
|
|
fetch() {
|
|
local trapped=
|
|
trap 'trapped=1' $sig
|
|
if [ "$1" != 1 ] && command -v sleep >/dev/null 2>/dev/null; then
|
|
sleep "$1"
|
|
fi
|
|
$fetch "$1".tar.gz -- "$2" 2>/dev/null &
|
|
local pid=$!
|
|
local die="trap - $sig; kill -- $pid 2>/dev/null; exit 1"
|
|
trap "$die" $sig
|
|
[ -z "$trapped" ] || eval "$die"
|
|
wait -- "$pid" 2>/dev/null && check_sha256 "$1"
|
|
local ret="$?"
|
|
echo -n >"$1".status
|
|
trap - $sig
|
|
return "$ret"
|
|
}
|
|
|
|
local trapped=
|
|
trap 'trapped=1' $sig
|
|
fetch 1 "$url1" &
|
|
local pid1=$!
|
|
fetch 2 "$url2" &
|
|
local pid2=$!
|
|
|
|
local die="trap - $sig; kill -- $pid1 $pid2 2>/dev/null; exit 1"
|
|
trap "$die" $sig
|
|
[ -z "$trapped" ] || eval "$die"
|
|
|
|
local n=
|
|
while true; do
|
|
[ -z "$dl_status" ] || eval "$dl_status" || eval "$die"
|
|
if command -v sleep >/dev/null 2>/dev/null; then
|
|
command sleep 1
|
|
elif command -v true >/dev/null 2>/dev/null; then
|
|
command true
|
|
fi
|
|
if [ -n "$pid1" -a -e 1.status ]; then
|
|
wait -- "$pid1" 2>/dev/null
|
|
local ret="$?"
|
|
pid1=
|
|
if [ "$ret" = 0 ]; then
|
|
[ -z "$pid2" ] || kill -- "$pid2" 2>/dev/null
|
|
n=1
|
|
break
|
|
elif [ -z "$pid2" ]; then
|
|
break
|
|
fi
|
|
elif [ -n "$pid2" -a -e 2.status ]; then
|
|
wait -- "$pid2" 2>/dev/null
|
|
local ret="$?"
|
|
pid2=
|
|
if [ "$ret" = 0 ]; then
|
|
[ -z "$pid1" ] || kill -- "$pid1" 2>/dev/null
|
|
n=2
|
|
break
|
|
elif [ -z "$pid1" ]; then
|
|
break
|
|
fi
|
|
fi
|
|
done
|
|
|
|
trap - $sig
|
|
|
|
if [ -z "$n" ]; then
|
|
>&2 echo "[gitstatus] error: failed to download gitstatusd from any mirror"
|
|
>&2 echo ""
|
|
>&2 echo " 1. $url1"
|
|
>&2 echo " 2. $url2"
|
|
exit 1
|
|
fi
|
|
|
|
command tar -xzf "$n".tar.gz || exit
|
|
|
|
local tmpfile
|
|
if ! command -v mktemp >/dev/null 2>&1 ||
|
|
! tmpfile="$(command mktemp "$cache_dir"/gitstatusd.XXXXXXXXXX)"; then
|
|
tmpfile="$cache_dir"/gitstatusd.tmp.$$
|
|
fi
|
|
|
|
command mv -f -- gitstatusd-* "$tmpfile" || exit
|
|
command mv -f -- "$tmpfile" "$cache_dir"/"$file" && exit
|
|
command rm -f -- "$cache_dir"/"$file"
|
|
command mv -f -- "$tmpfile" "$cache_dir"/"$file" && exit
|
|
command rm -f -- "$tmpfile"
|
|
exit 1
|
|
)
|
|
|
|
local ret=$?
|
|
command rm -rf -- "$tmpdir"
|
|
[ "$ret" = 0 ] || return
|
|
|
|
[ $# = 0 ] || "$@" "$daemon" "$version" 1
|
|
return
|
|
done <"$gitstatus_dir"/install.info
|
|
|
|
>&2 echo "[gitstatus] error: no gitstatusd found for $uname_s $uname_m"
|
|
return 1
|
|
}
|
|
|
|
if [ -z "${0##*/*}" ]; then
|
|
_gitstatus_install_main "${0%/*}" "$@"
|
|
else
|
|
_gitstatus_install_main . "$@"
|
|
fi
|