From acad492cecf17d6fd01c6cb1d002db189fc48001 Mon Sep 17 00:00:00 2001 From: Anmol Sethi Date: Mon, 14 Nov 2022 02:48:47 -0800 Subject: [PATCH] install.sh: Many many improvements Closes #81 --- ci/release/_install.sh | 88 +++++++++---- install.sh | 277 +++++++++++++++++++++++++++++++++++------ 2 files changed, 303 insertions(+), 62 deletions(-) diff --git a/ci/release/_install.sh b/ci/release/_install.sh index 19a909f1c..b4d1c85f3 100755 --- a/ci/release/_install.sh +++ b/ci/release/_install.sh @@ -63,18 +63,21 @@ Flags: Install the passed version of tala instead of latest. --force: - Force installation over the existing version even if they match. It will attempt a clean - uninstall first before installing the new version. The install assets will not be deleted - from ~/.cache/d2/install. + Force installation over the existing version even if they match. It will attempt a + uninstall first before installing the new version. The release assets will be deleted + from ~/.cache/d2/release and ~/.local/share/d2/release --uninstall: - Uninstall the installed version of d2. The --method flag must be the same as for - installation. i.e if you used --method standalone you must again use --method standalone - for uninstallation. With detect, the install script will try to use the OS package manager - to uninstall instead. + Uninstall the installed version of d2. The --method and --prefix flags must be the same + as for installation. i.e if you used --method standalone you must again use --method + standalone for uninstallation. With detect, the install script will try to use the OS + package manager to uninstall instead. -All downloaded assets are cached into ~/.cache/d2/release. use \$XDG_CACHE_HOME to change -path of the cached assets. +All downloaded archives are cached into ~/.cache/d2/release. use \$XDG_CACHE_HOME to change +path of the cached assets. Archives will be unarchived into ~/.local/share/d2/release. +Use \$XDG_DATA_HOME to adjust the path of the unarchived releases. + +note: Deleting the unarchived releases will cause --uninstall to stop working. You can rerun install.sh to update your version of D2. install.sh will avoid reinstalling if the installed version is the latest unless --force is passed. @@ -144,22 +147,35 @@ main() { flag_errusage "no arguments are accepted" fi - if [ -n "${UNINSTALL-}" ]; then - uninstall - return 1 - fi - REPO=${REPO:-terrastruct/d2} PREFIX=${PREFIX:-/usr/local} OS=$(os) ARCH=$(arch) CACHE_DIR=$(cache_dir) mkdir -p "$CACHE_DIR" + DATA_DIR=$(data_dir) + mkdir -p "$DATA_DIR" + + if [ -n "${UNINSTALL-}" ]; then + if ! command -v d2 >/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 @@ -167,7 +183,9 @@ main() { return 0 fi log "uninstalling $INSTALLED_VERSION to install $VERSION" - # uninstall + if ! uninstall_standalone; then + warn "failed to uninstall $INSTALLED_VERSION" + fi fi install_standalone @@ -182,26 +200,35 @@ install_standalone() { 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 "$CACHE_DIR" -xzf "$CACHE_DIR/$ARCHIVE" - sh_c cd "$CACHE_DIR/d2-$VERSION" + 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 + if ! is_prefix_writable; then sh_c="sudo_sh_c" fi "$sh_c" make install PREFIX="$PREFIX" } -uninstall() { - log "uninstalling standalone release d2-$VERSION" +uninstall_standalone() { + log "uninstalling standalone release d2-$INSTALLED_VERSION" - sh_c cd "$CACHE_DIR/d2-$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 + 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() { @@ -224,12 +251,23 @@ cache_dir() { 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 - log "fetching info on version $req_version" if [ -e "$CACHE_DIR/$req_version.json" ]; then - log "reusing $CACHE_DIR/$req_version.json" + echo "$VERSION" + return 0 fi + log "fetching info on version $req_version" rm -f "$CACHE_DIR/req_version.json" if [ "$req_version" = latest ]; then @@ -241,7 +279,7 @@ fetch_version_info() { 'application/json' VERSION=$(cat "$CACHE_DIR/$req_version.json" | grep -m1 tag_name | sed 's/^.*: "\(.*\)",$/\1/g') if [ "$req_version" = latest ]; then - mv "$CACHE_DIR/$req_version.json" "$CACHE_DIR/$VERSION.json" + sh_c mv "$CACHE_DIR/$req_version.json" "$CACHE_DIR/$VERSION.json" fi echo "$VERSION" } diff --git a/install.sh b/install.sh index 061999567..473731ecc 100755 --- a/install.sh +++ b/install.sh @@ -97,13 +97,7 @@ catp() { prefix="$1" shift - printfp "$prefix" - printf ': ' - read -r line - _echo "$line" - - indent=$(repeat ' ' 2) - sed "s/^/$indent/" + sed "s/^/$(printfp "$prefix" '')/" } repeat() { @@ -117,27 +111,27 @@ strlen() { } echoerr() { - COLOR=1 echop err "$*" >&2 + COLOR=1 echop err "$*" | humanpath>&2 } caterr() { - COLOR=1 catp err "$@" >&2 + COLOR=1 catp err "$@" | humanpath >&2 } printferr() { - COLOR=1 printfp err "$@" >&2 + COLOR=1 printfp err "$@" | humanpath >&2 } logp() { - echop "$@" >&2 + echop "$@" | humanpath >&2 } logfp() { - printfp "$@" >&2 + printfp "$@" | humanpath >&2 } logpcat() { - catp "$@" >&2 + catp "$@" | humanpath >&2 } log() { @@ -167,10 +161,38 @@ sh_c() { 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 </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 } -latest_version() { - curl -fsSLI -o/dev/null -w '%{url_effective}' "https://github.com/$REPO/latest" +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 "$@"