zmx-remote-install.fish

  1function zmx-remote-install --description "Install zmx on a remote host by streaming a locally downloaded release tarball"
  2    argparse 'h/help' 'upgrade-only' 'v/version=' -- $argv
  3    or return 1
  4
  5    if set -q _flag_help; or test (count $argv) -ne 1
  6        echo "Usage: zmx-remote-install [--upgrade-only] [--version VERSION] [user@]host"
  7        echo "Example: zmx-remote-install hel1"
  8        echo "By default, installs the active local zmx version."
  9        echo "With --upgrade-only, only upgrades an existing remote zmx that is older than local."
 10        return 0
 11    end
 12
 13    set -l destination $argv[1]
 14    set -l desired_version
 15
 16    if set -q _flag_version
 17        set desired_version $_flag_version
 18    else if type -q zmx
 19        set desired_version (zmx version | awk 'NR == 1 {print $2}')
 20    else if type -q mise
 21        set desired_version (mise exec -- zmx version | awk 'NR == 1 {print $2}')
 22    end
 23
 24    if test -z "$desired_version"
 25        echo "zmx-remote-install: could not determine local zmx version from zmx or mise" >&2
 26        return 1
 27    end
 28
 29    mkdir -p "$HOME/.ssh/controlmasters"
 30
 31    set -l remote_version (command ssh \
 32        -o ControlMaster=auto \
 33        -o ControlPersist=10m \
 34        -o ControlPath="$HOME/.ssh/controlmasters/%C" \
 35        $destination \
 36        "sh -c 'PATH=\"\$HOME/.local/bin:\$PATH\"; if command -v zmx >/dev/null 2>&1; then zmx version | awk \"NR == 1 {print \\\$2}\"; fi'")
 37    or return $status
 38
 39    if test -z "$remote_version"
 40        if set -q _flag_upgrade_only
 41            return 0
 42        end
 43
 44        echo "Remote zmx is not installed; installing local zmx $desired_version..." >&2
 45    else if test "$remote_version" = "$desired_version"
 46        return 0
 47    else
 48        if not type -q semver
 49            echo "zmx-remote-install: semver is required to compare local zmx $desired_version with remote zmx $remote_version" >&2
 50            return 1
 51        end
 52
 53        if not semver "$desired_version" >/dev/null 2>&1; or not semver "$remote_version" >/dev/null 2>&1
 54            echo "zmx-remote-install: cannot compare local zmx $desired_version with remote zmx $remote_version; refusing to sidegrade" >&2
 55            return 1
 56        end
 57
 58        if not semver -r ">$remote_version" "$desired_version" >/dev/null 2>&1
 59            return 0
 60        end
 61
 62        echo "Remote zmx is $remote_version; upgrading to local zmx $desired_version..." >&2
 63    end
 64
 65    set -l remote_platform (command ssh \
 66        -o ControlMaster=auto \
 67        -o ControlPersist=10m \
 68        -o ControlPath="$HOME/.ssh/controlmasters/%C" \
 69        $destination \
 70        "sh -c 'printf \"%s %s\\n\" \"\$(uname -s)\" \"\$(uname -m)\"'")
 71    or return $status
 72
 73    set -l remote_os (string split ' ' -- $remote_platform)[1]
 74    set -l remote_arch (string split ' ' -- $remote_platform)[2]
 75    set -l zmx_os
 76    set -l zmx_arch
 77
 78    switch $remote_os
 79        case Linux
 80            set zmx_os linux
 81        case Darwin
 82            set zmx_os macos
 83        case '*'
 84            echo "zmx-remote-install: unsupported remote OS '$remote_os'" >&2
 85            return 2
 86    end
 87
 88    switch $remote_arch
 89        case x86_64 amd64
 90            set zmx_arch x86_64
 91        case aarch64 arm64
 92            set zmx_arch aarch64
 93        case '*'
 94            echo "zmx-remote-install: unsupported remote architecture '$remote_arch'" >&2
 95            return 2
 96    end
 97
 98    set -l archive "zmx-$desired_version-$zmx_os-$zmx_arch.tar.gz"
 99    set -l base_url "https://zmx.sh/a"
100    set -l temp_dir (mktemp -d)
101    set -l archive_path "$temp_dir/$archive"
102    set -l checksum_path "$archive_path.sha256"
103
104    if test -z "$temp_dir"
105        echo "zmx-remote-install: failed to create a temporary directory" >&2
106        return 1
107    end
108
109    echo "Downloading $archive..." >&2
110    if not curl -fsSL "$base_url/$archive" -o "$archive_path"
111        rm -rf $temp_dir
112        return 1
113    end
114
115    if curl -fsSL "$base_url/$archive.sha256" -o "$checksum_path"
116        set -l expected (awk '{print $1}' "$checksum_path")
117        set -l actual
118
119        if type -q sha256sum
120            set actual (sha256sum "$archive_path" | awk '{print $1}')
121        else if type -q shasum
122            set actual (shasum -a 256 "$archive_path" | awk '{print $1}')
123        else
124            echo "zmx-remote-install: no local sha256sum or shasum found; refusing to install unverified archive" >&2
125            rm -rf $temp_dir
126            return 1
127        end
128
129        if test "$expected" != "$actual"
130            echo "zmx-remote-install: checksum verification failed for $archive" >&2
131            rm -rf $temp_dir
132            return 1
133        end
134    else
135        echo "zmx-remote-install: could not download checksum for $archive; refusing to install unverified archive" >&2
136        rm -rf $temp_dir
137        return 1
138    end
139
140    echo "Installing zmx $desired_version on $destination..." >&2
141    if not command ssh \
142            -o ControlMaster=auto \
143            -o ControlPersist=10m \
144            -o ControlPath="$HOME/.ssh/controlmasters/%C" \
145            $destination \
146            "sh -c 'mkdir -p \"\$HOME/.local/bin\" && tmp=\$(mktemp \"\$HOME/.local/bin/.zmx.XXXXXX\") && tar -xOzf - zmx > \"\$tmp\" && chmod 755 \"\$tmp\" && mv \"\$tmp\" \"\$HOME/.local/bin/zmx\"'" <"$archive_path"
147        rm -rf $temp_dir
148        return 1
149    end
150
151    rm -rf $temp_dir
152
153    command ssh \
154        -o ControlMaster=auto \
155        -o ControlPersist=10m \
156        -o ControlPath="$HOME/.ssh/controlmasters/%C" \
157        $destination \
158        "sh -c 'PATH=\"\$HOME/.local/bin:\$PATH\"; zmx version'"
159end