#!/bin/sh set -eu # ************* # DO NOT EDIT # # install.sh was bundled together from # # - ./ci/sub/lib/rand.sh # - ./ci/sub/lib/log.sh # - ./ci/sub/lib/flag.sh # - ./ci/release/_install.sh # # The last of which implements the installation logic. # # Generated by ./ci/release/gen_install.sh. # ************* #!/bin/sh if [ "${LIB_RAND-}" ]; then return 0 fi LIB_RAND=1 rand() { seed="$1" range="$2" seed_file="$(mktemp)" _echo "$seed" | md5sum > "$seed_file" shuf -i "$range" -n 1 --random-source="$seed_file" } pick() { seed="$1" shift i="$(rand "$seed" "1-$#")" eval "_echo \"\$$i\"" } #!/bin/sh if [ "${LIB_LOG-}" ]; then return 0 fi LIB_LOG=1 tput() { if [ -n "$TERM" ]; then command tput "$@" fi } setaf() { tput setaf "$1" shift printf '%s' "$*" tput sgr0 } _echo() { printf '%s\n' "$*" } get_rand_color() { # 1-6 are regular and 9-14 are bright. # 1,2 and 9,10 are red and green but we use those for success and failure. pick "$*" 3 4 5 6 11 12 13 14 } echop() { prefix="$1" shift if [ "$#" -gt 0 ]; then printfp "$prefix" "%s\n" "$*" else printfp "$prefix" printf '\n' fi } printfp() {( prefix="$1" shift if [ -z "${COLOR:-}" ]; then COLOR="$(get_rand_color "$prefix")" fi printf '%s' "$(setaf "$COLOR" "$prefix")" if [ $# -gt 0 ]; then printf ': ' printf "$@" fi )} catp() { prefix="$1" shift sed "s/^/$(printfp "$prefix" '')/" } repeat() { char="$1" times="$2" seq -s "$char" "$times" | tr -d '[:digit:]' } strlen() { printf %s "$1" | wc -c } echoerr() { COLOR=1 echop err "$*" | humanpath>&2 } caterr() { COLOR=1 catp err "$@" | humanpath >&2 } printferr() { COLOR=1 printfp err "$@" | humanpath >&2 } logp() { echop "$@" | humanpath >&2 } logfp() { printfp "$@" | humanpath >&2 } logpcat() { catp "$@" | humanpath >&2 } log() { COLOR=5 logp log "$@" } logf() { COLOR=5 logfp log "$@" } logcat() { COLOR=5 catp log "$@" >&2 } warn() { COLOR=3 logp warn "$@" } warnf() { COLOR=3 logfp warn "$@" } sh_c() { COLOR=3 logp exec "$*" if [ -z "${DRY_RUN-}" ]; then eval "$@" fi } sudo_sh_c() { if [ "$(id -u)" -eq 0 ]; then sh_c "$@" elif command -v doas >/dev/null; then sh_c "doas $*" elif command -v sudo >/dev/null; then sh_c "sudo $*" elif command -v su >/dev/null; then sh_c "su root -c '$*'" else caterr <"$out" 2>&1 code="$?" set -e if [ "$code" -eq 0 ]; then return fi cat "$out" >&2 exit "$code" } echo_dur() { local dur=$1 local h=$((dur/60/60)) local m=$((dur/60%60)) local s=$((dur%60)) printf '%dh%dm%ds' "$h" "$m" "$s" } sponge() { dst="$1" tmp="$(mktemp)" cat > "$tmp" cat "$tmp" > "$dst" } stripansi() { # First regex gets rid of standard xterm escape sequences for controlling # visual attributes. # The second regex I'm not 100% sure, the reference says it selects the US # encoding but I'm not sure why that's necessary or why it always occurs # in tput sgr0 before the standard escape sequence. # See tput sgr0 | xxd sed -e $'s/\x1b\[[0-9;]*m//g' -e $'s/\x1b(.//g' } runtty() { case "$(uname)" in Darwin) script -q /dev/null "$@" ;; Linux) script -eqc "$*" ;; *) echoerr "runtty: unsupported OS $(uname)" return 1 esac } #!/bin/sh if [ "${LIB_FLAG-}" ]; then return 0 fi LIB_FLAG=1 # flag_parse implements a robust flag parser. # # For a full fledge example see ../examples/date.sh # # It differs from getopts(1) in that long form options are supported. Currently the only # deficiency is that short combined options are not supported like -xyzq. That would be # interpreted as a single -xyzq flag. The other deficiency is lack of support for short # flag syntax like -carg where the arg is not separated from the flag. This one is # unfixable I believe unfortunately but for combined short flags I have opened # https://github.com/terrastruct/ci/issues/6 # # flag_parse stores state in $FLAG, $FLAGRAW, $FLAGARG and $FLAGSHIFT. # FLAG contains the name of the flag without hyphens. # FLAGRAW contains the name of the flag as passed in with hyphens. # FLAGARG contains the argument for the flag if there was any. # If there was none, it will not be set. # FLAGSHIFT contains the number by which the arguments should be shifted to # start at the next flag/argument # # After each call check $FLAG for the name of the parsed flag. # If empty, then no more flags are left. # Still, call shift "$FLAGSHIFT" in case there was a -- # # If the argument for the flag is optional, then use ${FLAGARG-} to access # the argument if one was passed. Use ${FLAGARG+x} = x to check if it was set. # You only need to explicitly check if the flag was set if you care whether the user # explicitly passed the empty string as the argument. # # Otherwise, call one of the flag_*arg functions: # # If a flag requires an argument, call flag_reqarg # - $FLAGARG is guaranteed to be set after. # If a flag requires a non empty argument, call flag_nonemptyarg # - $FLAGARG is guaranteed to be set to a non empty string after. # If a flag should not be passed an argument, call flag_noarg # - $FLAGARG is guaranteed to be unset after. # # And then shift "$FLAGSHIFT" flag_parse() { case "${1-}" in -*=*) # Remove everything after first equal sign. FLAG="${1%%=*}" # Remove leading hyphens. FLAG="${FLAG#-}"; FLAG="${FLAG#-}" FLAGRAW="$(flag_fmt)" # Remove everything before first equal sign. FLAGARG="${1#*=}" FLAGSHIFT=1 ;; -) FLAG= FLAGRAW= unset FLAGARG FLAGSHIFT=0 ;; --) FLAG= FLAGRAW= unset FLAGARG FLAGSHIFT=1 ;; -*) # Remove leading hyphens. FLAG="${1#-}"; FLAG="${FLAG#-}" FLAGRAW=$(flag_fmt) unset FLAGARG FLAGSHIFT=1 if [ $# -gt 1 ]; then case "$2" in -) FLAGARG="$2" FLAGSHIFT=2 ;; -*) ;; *) FLAGARG="$2" FLAGSHIFT=2 ;; esac fi ;; *) FLAG= FLAGRAW= unset FLAGARG FLAGSHIFT=0 ;; esac return 0 } flag_reqarg() { if [ "${FLAGARG+x}" != x ]; then flag_errusage "flag $FLAGRAW requires an argument" fi } flag_nonemptyarg() { flag_reqarg if [ -z "$FLAGARG" ]; then flag_errusage "flag $FLAGRAW requires a non-empty argument" fi } flag_noarg() { if [ "$FLAGSHIFT" -eq 2 ]; then unset FLAGARG FLAGSHIFT=1 elif [ "${FLAGARG+x}" = x ]; then # Means an argument was passed via equal sign as in -$FLAG=$FLAGARG flag_errusage "flag $FLAGRAW does not accept an argument" fi } flag_errusage() { caterr </dev/null; then echoerr "no version of d2 installed" return 1 fi INSTALLED_VERSION="$(d2 version)" if ! uninstall_standalone; then echoerr "failed to uninstall $INSTALLED_VERSION" return 1 fi return 0 fi VERSION=${VERSION:-latest} if [ "$VERSION" = latest ]; then VERSION=$(fetch_version_info) fi # TODO: --tala, --tala-version if command -v d2 >/dev/null; then INSTALLED_VERSION="$(d2 version)" if [ ! "${FORCE-}" -a "$VERSION" = "$INSTALLED_VERSION" ]; then log "skipping installation as version $VERSION is already installed." return 0 fi log "uninstalling $INSTALLED_VERSION to install $VERSION" if ! uninstall_standalone; then warn "failed to uninstall $INSTALLED_VERSION" fi fi install_standalone } install_standalone() { ARCHIVE="d2-$VERSION-$OS-$ARCH.tar.gz" log "installing standalone release $ARCHIVE from github" VERSION=$(fetch_version_info) asset_line=$(cat "$CACHE_DIR/$VERSION.json" | grep -n "$ARCHIVE" | cut -d: -f1 | head -n1) asset_url=$(sed -n $((asset_line-3))p "$CACHE_DIR/$VERSION.json" | sed 's/^.*: "\(.*\)",$/\1/g') fetch_gh "$asset_url" "$CACHE_DIR/$ARCHIVE" 'application/octet-stream' sh_c tar -C "$DATA_DIR" -xzf "$CACHE_DIR/$ARCHIVE" sh_c cd "$DATA_DIR/d2-$VERSION" sh_c="sh_c" if ! is_prefix_writable; then sh_c="sudo_sh_c" fi "$sh_c" make install PREFIX="$PREFIX" } uninstall_standalone() { log "uninstalling standalone release d2-$INSTALLED_VERSION" if [ ! -e "$DATA_DIR/d2-$INSTALLED_VERSION" ]; then echoerr "no standalone release directory for d2-$INSTALLED_VERSION" return 1 fi sh_c cd "$DATA_DIR/d2-$INSTALLED_VERSION" sh_c="sh_c" if ! is_prefix_writable; then sh_c="sudo_sh_c" fi "$sh_c" make uninstall PREFIX="$PREFIX" sh_c rm -rf "$DATA_DIR/d2-$INSTALLED_VERSION" sh_c rm -rf "$CACHE_DIR/$INSTALLED_VERSION.json" sh_c rm -rf "$CACHE_DIR/d2-$INSTALLED_VERSION-$OS-$ARCH.tar.gz" } is_prefix_writable() { sh_c mkdir -p "$PREFIX" 2>/dev/null || true # The reason for checking whether bin is writable specifically is that on macOS you have # /usr/local owned by root but you don't need root to write to its subdirectories which # is all we want to do. if [ ! -w "$PREFIX/bin" ]; then return 0 fi } cache_dir() { if [ -n "${XDG_CACHE_HOME-}" ]; then echo "$XDG_CACHE_HOME/d2/release" elif [ -n "${HOME-}" ]; then echo "$HOME/.cache/d2/release" else echo "/tmp/d2-cache/release" fi } data_dir() { if [ -n "${XDG_DATA_HOME-}" ]; then echo "$XDG_DATA_HOME/d2/release" elif [ -n "${HOME-}" ]; then echo "$HOME/.local/d2/release" else echo "/tmp/d2-data/release" fi } fetch_version_info() { req_version=$VERSION if [ -e "$CACHE_DIR/$req_version.json" ]; then echo "$VERSION" return 0 fi log "fetching info on version $req_version" rm -f "$CACHE_DIR/req_version.json" if [ "$req_version" = latest ]; then release_info_url="https://api.github.com/repos/$REPO/releases/$req_version" else release_info_url="https://api.github.com/repos/$REPO/releases/tags/$req_version" fi fetch_gh "$release_info_url" "$CACHE_DIR/$req_version.json" \ 'application/json' VERSION=$(cat "$CACHE_DIR/$req_version.json" | grep -m1 tag_name | sed 's/^.*: "\(.*\)",$/\1/g') if [ "$req_version" = latest ]; then sh_c mv "$CACHE_DIR/$req_version.json" "$CACHE_DIR/$VERSION.json" fi echo "$VERSION" } curl_gh() { sh_c curl -fL ${GITHUB_TOKEN+"-H \"Authorization: Bearer \$GITHUB_TOKEN\""} "$@" } fetch_gh() { url=$1 file=$2 accept=$3 if [ -e "$file" ]; then log "reusing $file" return fi curl_gh -#o "$file.inprogress" -C- -H "'Accept: $accept'" "$url" sh_c mv "$file.inprogress" "$file" } main "$@"