From c31e72fb7bf13bf396c08718098e4965232fea41 Mon Sep 17 00:00:00 2001 From: Asher Date: Fri, 2 Jul 2021 13:18:37 -0500 Subject: [PATCH 1/5] Add installer integration tests --- .github/workflows/ci.yaml | 4 +-- .github/workflows/installer.yml | 39 +++++++++++++++++++++++++++++ ci/build/test-standalone-release.sh | 14 +++++++---- 3 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 .github/workflows/installer.yml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 377caec9..fef2d04e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,4 +1,4 @@ -name: ci +name: Build on: push: @@ -16,7 +16,7 @@ on: jobs: prebuild: - name: Pre-Build checks + name: Pre-build checks runs-on: ubuntu-latest timeout-minutes: 5 env: diff --git a/.github/workflows/installer.yml b/.github/workflows/installer.yml new file mode 100644 index 00000000..0a004b8b --- /dev/null +++ b/.github/workflows/installer.yml @@ -0,0 +1,39 @@ +name: Installer integration + +on: + push: + branches: + - main + paths: + - "installer.sh" + pull_request: + branches: + - main + +jobs: + ubuntu: + name: Test installer on Ubuntu + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v2 + + - name: Install code-server + run: ./install.sh + + - name: Test code-server + run: yarn test:standalone-release code-server + + macos: + name: Test installer on macOS + runs-on: macos-latest + + steps: + - name: Checkout repo + uses: actions/checkout@v2 + + - name: Install code-server + run: ./install.sh + + - name: Test code-server + run: yarn test:standalone-release code-server diff --git a/ci/build/test-standalone-release.sh b/ci/build/test-standalone-release.sh index 818aac8b..73961dd4 100755 --- a/ci/build/test-standalone-release.sh +++ b/ci/build/test-standalone-release.sh @@ -1,7 +1,9 @@ #!/usr/bin/env bash set -euo pipefail -# Makes sure the release works. +# Make sure a code-server release works. You can pass in the path otherwise it +# will use release-standalone in the current directory. +# # This is to make sure we don't have Node version errors or any other # compilation-related errors. main() { @@ -10,12 +12,14 @@ main() { local EXTENSIONS_DIR EXTENSIONS_DIR="$(mktemp -d)" - echo "Testing standalone release." + local path=${1:-./release-standalone/bin/code-server} - # Note: using a basic theme extension because it doesn't update often and is more reliable for testing - ./release-standalone/bin/code-server --extensions-dir "$EXTENSIONS_DIR" --install-extension wesbos.theme-cobalt2 + echo "Testing standalone release in $path." + + # NOTE: using a basic theme extension because it doesn't update often and is more reliable for testing + "$path" --extensions-dir "$EXTENSIONS_DIR" --install-extension wesbos.theme-cobalt2 local installed_extensions - installed_extensions="$(./release-standalone/bin/code-server --extensions-dir "$EXTENSIONS_DIR" --list-extensions 2>&1)" + installed_extensions="$("$path" --extensions-dir "$EXTENSIONS_DIR" --list-extensions 2>&1)" # We use grep as wesbos.theme-cobalt2 may have dependency extensions that change. if ! echo "$installed_extensions" | grep -q "wesbos.theme-cobalt2"; then echo "Unexpected output from listing extensions:" From 24f6834f5bdbca361db761468ef73f090dc430cf Mon Sep 17 00:00:00 2001 From: Asher Date: Tue, 13 Jul 2021 12:22:00 -0500 Subject: [PATCH 2/5] Add installer unit tests --- .github/workflows/scripts.yml | 27 ++++++ ci/dev/test-scripts.sh | 9 ++ docs/CONTRIBUTING.md | 2 + package.json | 1 + test/scripts/install.bats | 163 ++++++++++++++++++++++++++++++++++ 5 files changed, 202 insertions(+) create mode 100644 .github/workflows/scripts.yml create mode 100755 ci/dev/test-scripts.sh create mode 100644 test/scripts/install.bats diff --git a/.github/workflows/scripts.yml b/.github/workflows/scripts.yml new file mode 100644 index 00000000..47df18d6 --- /dev/null +++ b/.github/workflows/scripts.yml @@ -0,0 +1,27 @@ +name: Script unit tests + +on: + push: + branches: + - main + paths: + - "installer.sh" + pull_request: + branches: + - main + +jobs: + test: + name: Run script unit tests + runs-on: ubuntu-latest + # This runs on Alpine to make sure we're testing with actual sh. + container: "alpine:3.14" + steps: + - name: Checkout repo + uses: actions/checkout@v2 + + - name: Install bats + run: apk add bats + + - name: Run script unit tests + run: ./ci/dev/test-scripts.sh diff --git a/ci/dev/test-scripts.sh b/ci/dev/test-scripts.sh new file mode 100755 index 00000000..ebe1efa8 --- /dev/null +++ b/ci/dev/test-scripts.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail + +main() { + cd "$(dirname "$0")/../.." + bats ./test/scripts +} + +main "$@" diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index d4bf6f07..691c9f1f 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -44,6 +44,8 @@ Here is what is needed: - Get this by running `apt-get install -y build-essential` - `rsync` and `unzip` - Used for code-server releases +- `bats` + - Used to run script unit tests ## Creating pull requests diff --git a/package.json b/package.json index 51be2d53..fca00efd 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "test:e2e": "./ci/dev/test-e2e.sh", "test:standalone-release": "./ci/build/test-standalone-release.sh", "test:unit": "./ci/dev/test-unit.sh", + "test:scripts": "./ci/dev/test-scripts.sh", "package": "./ci/build/build-packages.sh", "postinstall": "./ci/dev/postinstall.sh", "update:vscode": "./ci/dev/update-vscode.sh", diff --git a/test/scripts/install.bats b/test/scripts/install.bats new file mode 100644 index 00000000..651236b7 --- /dev/null +++ b/test/scripts/install.bats @@ -0,0 +1,163 @@ +#!/usr/bin/env bats + +SCRIPT_NAME="install.sh" +SCRIPT="$BATS_TEST_DIRNAME/../../$SCRIPT_NAME" + +# Override version so it doesn't have to curl and to avoid caching in case the +# user already has the latest version installed. +export VERSION="9999.99.9" + +function should-use-deb() { + DISTRO=$1 ARCH=$2 OS=linux run "$SCRIPT" --dry-run + [ "$status" -eq 0 ] + [ "${lines[1]}" = "Installing v$VERSION of the $2 deb package from GitHub." ] + [ "${lines[-5]}" = "deb package has been installed." ] +} + +function should-use-rpm() { + DISTRO=$1 ARCH=$2 OS=linux run "$SCRIPT" --dry-run + [ "$status" -eq 0 ] + [ "${lines[1]}" = "Installing v$VERSION of the $2 rpm package from GitHub." ] + [ "${lines[-5]}" = "rpm package has been installed." ] +} + +function should-fallback-npm() { + YARN_PATH=true DISTRO=$1 ARCH=$2 OS=linux run "$SCRIPT" --dry-run + [ "$status" -eq 0 ] + [ "${lines[1]}" = "No standalone releases for $2." ] + [ "${lines[2]}" = "Falling back to installation from npm." ] + [ "${lines[3]}" = "Installing latest from npm." ] + [ "${lines[-5]}" = "npm package has been installed." ] +} + +function should-use-npm() { + YARN_PATH=true DISTRO=$1 ARCH=$2 OS=linux run "$SCRIPT" --dry-run + [ "$status" -eq 0 ] + [ "${lines[1]}" = "Installing latest from npm." ] + [ "${lines[-5]}" = "npm package has been installed." ] +} + +function should-use-aur() { + DISTRO=$1 ARCH=$2 OS=linux run "$SCRIPT" --dry-run + [ "$status" -eq 0 ] + [ "${lines[1]}" = "Installing latest from the AUR." ] + [ "${lines[-5]}" = "AUR package has been installed." ] +} + +function should-fallback-npm-brew() { + YARN_PATH=true BREW_PATH= OS=macos ARCH=$1 run "$SCRIPT" --dry-run + [ "$status" -eq 0 ] + [ "${lines[1]}" = "Homebrew not installed." ] + [ "${lines[2]}" = "Falling back to standalone installation." ] + [ "${lines[3]}" = "No standalone releases for $1." ] + [ "${lines[4]}" = "Falling back to installation from npm." ] + [ "${lines[5]}" = "Installing latest from npm." ] + [ "${lines[-5]}" = "npm package has been installed." ] +} + +function should-use-brew() { + BREW_PATH=true OS=macos ARCH=$1 run "$SCRIPT" --dry-run + [ "$status" -eq 0 ] + [ "${lines[1]}" = "Installing latest from Homebrew." ] + [ "${lines[-3]}" = "Brew release has been installed." ] +} + +function should-use-standalone() { + DISTRO=$1 ARCH=$2 OS=$3 run "$SCRIPT" --method standalone --dry-run + [ "$status" -eq 0 ] + [ "${lines[1]}" = "Installing v$VERSION of the $2 release from GitHub." ] + [[ "${lines[-5]}" = "Standalone release has been installed"* ]] +} + +@test "$SCRIPT_NAME: usage with --help" { + run "$SCRIPT" --help + [ "$status" -eq 0 ] + [ "${lines[0]}" = "Installs code-server." ] + [[ "${lines[-1]}" = "More installation docs are at"* ]] +} + +# These use the deb but fall back to npm for unsupported architectures. +@test "$SCRIPT_NAME: debian arm64" { + should-use-deb "debian" "arm64" +} +@test "$SCRIPT_NAME: debian amd64" { + should-use-deb "debian" "amd64" +} +@test "$SCRIPT_NAME: debian i386" { + should-fallback-npm "debian" "i386" +} + +# These use the rpm but fall back to npm for unsupported architectures. +@test "$SCRIPT_NAME: fedora arm64" { + should-use-rpm "fedora" "arm64" +} +@test "$SCRIPT_NAME: fedora amd64" { + should-use-rpm "fedora" "amd64" +} +@test "$SCRIPT_NAME: fedora i386" { + should-fallback-npm "fedora" "i386" +} + +# These always use npm regardless of the architecture. +@test "$SCRIPT_NAME: alpine arm64" { + should-use-npm "alpine" "arm64" +} +@test "$SCRIPT_NAME: alpine amd64" { + should-use-npm "alpine" "amd64" +} +@test "$SCRIPT_NAME: alpine i386" { + should-use-npm "alpine" "i386" +} + +@test "$SCRIPT_NAME: freebsd arm64" { + should-use-npm "freebsd" "arm64" +} +@test "$SCRIPT_NAME: freebsd amd64" { + should-use-npm "freebsd" "amd64" +} +@test "$SCRIPT_NAME: freebsd i386" { + should-use-npm "freebsd" "i386" +} + +# Arch Linux uses AUR but falls back to npm for unsuppported architectures. +@test "$SCRIPT_NAME: arch arm64" { + should-use-aur "arch" "arm64" +} +@test "$SCRIPT_NAME: arch amd64" { + should-use-aur "arch" "amd64" +} +@test "$SCRIPT_NAME: arch i386" { + should-fallback-npm "arch" "i386" +} + +# macOS use homebrew but falls back to standalone when brew is unavailable then +# to npm for unsupported architectures. +@test "$SCRIPT_NAME: macos arm64 (no brew)" { + should-fallback-npm-brew "arm64" +} +@test "$SCRIPT_NAME: macos amd64 (no brew)" { + BREW_PATH= OS=macos ARCH=amd64 run "$SCRIPT" --dry-run + [ "$status" -eq 0 ] + [ "${lines[1]}" = "Homebrew not installed." ] + [ "${lines[2]}" = "Falling back to standalone installation." ] + [ "${lines[3]}" = "Installing v$VERSION of the amd64 release from GitHub." ] + [[ "${lines[-5]}" = "Standalone release has been installed"* ]] +} +@test "$SCRIPT_NAME: macos i386 (no brew)" { + should-fallback-npm-brew "i386" +} + +@test "$SCRIPT_NAME: macos arm64 (brew)" { + should-use-brew "arm64" +} +@test "$SCRIPT_NAME: macos amd64 (brew)" { + should-use-brew "amd64" +} +@test "$SCRIPT_NAME: macos i386 (brew)" { + should-use-brew "i386" +} + +# Force standalone. +@test "$SCRIPT_NAME: debian amd64 --method standalone" { + should-use-standalone "debian" "amd64" "linux" +} From 6045fdd3ac3c92b1b19c785cbce26da041227b75 Mon Sep 17 00:00:00 2001 From: Asher Date: Tue, 13 Jul 2021 12:21:22 -0500 Subject: [PATCH 3/5] Make installer work on any os/arch --- install.sh | 274 ++++++++++++++++++++++++++++------------------------- 1 file changed, 145 insertions(+), 129 deletions(-) diff --git a/install.sh b/install.sh index 84ab8322..e51afc19 100755 --- a/install.sh +++ b/install.sh @@ -14,7 +14,7 @@ usage() { fi cath << EOF -Installs code-server for Linux, macOS and FreeBSD. +Installs code-server. It tries to use the system package manager if possible. After successful installation it explains how to start using code-server. @@ -48,24 +48,23 @@ Usage: --rsh Specifies the remote shell for remote installation. Defaults to ssh. -- For Debian, Ubuntu and Raspbian it will install the latest deb package. -- For Fedora, CentOS, RHEL and openSUSE it will install the latest rpm package. -- For Arch Linux it will install the AUR package. -- For any unrecognized Linux operating system it will install the latest standalone - release into ~/.local +The detection method works as follows: + - Debian, Ubuntu, Raspbian: install the deb package from GitHub. + - Fedora, CentOS, RHEL, openSUSE: install the rpm package from GitHub. + - Arch Linux: install from the AUR (which pulls releases from GitHub). + - FreeBSD, Alpine: install from yarn/npm. + - macOS: install using Homebrew if installed otherwise install from GitHub. + - All others: install the release from GitHub. -- For macOS it will install the Homebrew package. - - If Homebrew is not installed it will install the latest standalone release - into ~/.local +We only build releases on GitHub for amd64 and arm64 on Linux and amd64 for +macOS. When the detection method tries to pull a release from GitHub it will +fall back to installing from npm when there is no matching release for the +system's operating system and architecture. -- For FreeBSD or Alpine, it will install the npm package with yarn or npm. +The standalone method will force installion using GitHub releases. It will not +fall back to npm so on architectures without pre-built releases this will error. -- If ran on an architecture with no releases, it will install the - npm package with yarn or npm. - - We only have releases for amd64 and arm64 presently. - - The npm package builds the native modules on postinstall. - -It will cache all downloaded assets into ~/.cache/code-server +The installer will cache all downloaded assets into ~/.cache/code-server More installation docs are at https://coder.com/docs/code-server/v3.10.2/install EOF @@ -82,10 +81,11 @@ echo_latest_version() { echo_npm_postinstall() { echoh cath << EOF -The npm package has been installed successfully! -Please extend your path to use code-server: +npm package has been installed. + +Extend your path to use code-server: PATH="$NPM_BIN_DIR:\$PATH" -Please run with: +Then run with: code-server EOF } @@ -94,9 +94,20 @@ echo_standalone_postinstall() { echoh cath << EOF Standalone release has been installed into $STANDALONE_INSTALL_PREFIX/lib/code-server-$VERSION -Please extend your path to use code-server: + +Extend your path to use code-server: PATH="$STANDALONE_INSTALL_PREFIX/bin:\$PATH" -Then you can run: +Then run with: + code-server +EOF +} + +echo_brew_postinstall() { + echoh + cath << EOF +Brew release has been installed. + +Run with: code-server EOF } @@ -104,6 +115,8 @@ EOF echo_systemd_postinstall() { echoh cath << EOF +$1 package has been installed. + To have systemd start code-server now and restart on boot: sudo systemctl enable --now code-server@\$USER Or, if you don't want/need a background service you can run: @@ -120,7 +133,6 @@ main() { DRY_RUN \ METHOD \ STANDALONE_INSTALL_PREFIX \ - VERSION \ OPTIONAL \ ALL_FLAGS \ RSH_ARGS \ @@ -198,80 +210,70 @@ main() { return fi - VERSION="${VERSION-$(echo_latest_version)}" METHOD="${METHOD-detect}" if [ "$METHOD" != detect ] && [ "$METHOD" != standalone ]; then echoerr "Unknown install method \"$METHOD\"" echoerr "Run with --help to see usage." exit 1 fi - STANDALONE_INSTALL_PREFIX="${STANDALONE_INSTALL_PREFIX-$HOME/.local}" - OS="$(os)" - if [ ! "$OS" ]; then - echoerr "Unsupported OS $(uname)." - exit 1 - fi + # These are used by the various install_* functions that make use of GitHub + # releases in order to download and unpack the right release. + CACHE_DIR=$(echo_cache_dir) + STANDALONE_INSTALL_PREFIX=${STANDALONE_INSTALL_PREFIX:-$HOME/.local} + VERSION=${VERSION:-$(echo_latest_version)} + # These can be overridden for testing but shouldn't normally be used as it can + # result in a broken code-server. + OS=${OS:-$(os)} + ARCH=${ARCH:-$(arch)} distro_name - ARCH="$(arch)" - if [ ! "$ARCH" ]; then - if [ "$METHOD" = standalone ]; then - echoerr "No precompiled releases for $(uname -m)." - echoerr 'Please rerun without the "--method standalone" flag to install from npm.' - exit 1 - fi - echoh "No precompiled releases for $(uname -m)." - install_npm - return - fi - - if [ "$OS" = "freebsd" ]; then - if [ "$METHOD" = standalone ]; then - echoerr "No precompiled releases available for $OS." - echoerr 'Please rerun without the "--method standalone" flag to install from npm.' - exit 1 - fi - echoh "No precompiled releases available for $OS." - install_npm - return - fi - - if [ "$OS" = "linux" ] && [ "$(distro)" = "alpine" ]; then - if [ "$METHOD" = standalone ]; then - echoerr "No precompiled releases available for alpine." - echoerr 'Please rerun without the "--method standalone" flag to install from npm.' - exit 1 - fi - echoh "No precompiled releases available for alpine." - install_npm - return - fi - - CACHE_DIR="$(echo_cache_dir)" - + # Standalone installs by pulling pre-built releases from GitHub. if [ "$METHOD" = standalone ]; then - install_standalone - return + if has_standalone; then + install_standalone + exit 0 + else + echoerr "There are no standalone releases for $ARCH" + echoerr "Please try again without '--method standalone'" + exit 1 + fi fi - case "$(distro)" in + # DISTRO can be overridden for testing but shouldn't normally be used as it + # can result in a broken code-server. + DISTRO=${DISTRO:-$(distro)} + + case $DISTRO in + # macOS uses brew when available and falls back to standalone. We only have + # amd64 for macOS so for anything else use npm. macos) - install_macos - ;; - debian) - install_deb - ;; - fedora | opensuse) - install_rpm - ;; - arch) - install_aur + BREW_PATH="${BREW_PATH-brew}" + if command_exists "$BREW_PATH"; then + install_brew + else + echoh "Homebrew not installed." + echoh "Falling back to standalone installation." + npm_fallback install_standalone + fi ;; + # The .deb and .rpm files are pulled from GitHub and we only have amd64 and + # arm64 there and need to fall back to npm otherwise. + debian) npm_fallback install_deb ;; + fedora | opensuse) npm_fallback install_rpm ;; + # Arch uses the AUR package which only supports amd64 and arm64 since it + # pulls releases from GitHub so we need to fall back to npm. + arch) npm_fallback install_aur ;; + # We don't have GitHub releases that work on Alpine or FreeBSD so we have no + # choice but to use npm here. + alpine | freebsd) install_npm ;; + # For anything else we'll try to install standalone but fall back to npm if + # we don't have releases for the architecture. *) echoh "Unsupported package manager." - install_standalone + echoh "Falling back to standalone installation." + npm_fallback install_standalone ;; esac } @@ -326,45 +328,39 @@ fetch() { sh_c mv "$FILE.incomplete" "$FILE" } -install_macos() { - if command_exists brew; then - echoh "Installing from Homebrew." - echoh +install_brew() { + echoh "Installing latest from Homebrew." + echoh - sh_c brew install code-server + sh_c "$BREW_PATH" install code-server - return - fi - - echoh "Homebrew not installed." - - install_standalone + echo_brew_postinstall } install_deb() { - echoh "Installing v$VERSION deb package from GitHub releases." + echoh "Installing v$VERSION of the $ARCH deb package from GitHub." echoh fetch "https://github.com/cdr/code-server/releases/download/v$VERSION/code-server_${VERSION}_$ARCH.deb" \ "$CACHE_DIR/code-server_${VERSION}_$ARCH.deb" sudo_sh_c dpkg -i "$CACHE_DIR/code-server_${VERSION}_$ARCH.deb" - echo_systemd_postinstall + echo_systemd_postinstall deb } install_rpm() { - echoh "Installing v$VERSION rpm package from GitHub releases." + echoh "Installing v$VERSION of the $ARCH rpm package from GitHub." echoh fetch "https://github.com/cdr/code-server/releases/download/v$VERSION/code-server-$VERSION-$ARCH.rpm" \ "$CACHE_DIR/code-server-$VERSION-$ARCH.rpm" sudo_sh_c rpm -i "$CACHE_DIR/code-server-$VERSION-$ARCH.rpm" - echo_systemd_postinstall + echo_systemd_postinstall rpm } install_aur() { - echoh "Installing from the AUR." + echoh "Installing latest from the AUR." echoh sh_c mkdir -p "$CACHE_DIR/code-server-aur" @@ -375,11 +371,11 @@ install_aur() { fi sh_c makepkg -si - echo_systemd_postinstall + echo_systemd_postinstall AUR } install_standalone() { - echoh "Installing standalone release archive v$VERSION from GitHub releases." + echoh "Installing v$VERSION of the $ARCH release from GitHub." echoh fetch "https://github.com/cdr/code-server/releases/download/v$VERSION/code-server-$VERSION-$OS-$ARCH.tar.gz" \ @@ -406,50 +402,74 @@ install_standalone() { } install_npm() { - if command_exists yarn; then + echoh "Installing latest from npm." + echoh + + YARN_PATH="${YARN_PATH-yarn}" + NPM_PATH="${YARN_PATH-npm}" + if command_exists "$YARN_PATH"; then sh_c="sh_c" - if [ ! -w "$(yarn global bin)" ]; then + if [ ! "${DRY_RUN-}" ] && [ ! -w "$($YARN_PATH global bin)" ]; then sh_c="sudo_sh_c" fi echoh "Installing with yarn." echoh - "$sh_c" yarn global add code-server --unsafe-perm - NPM_BIN_DIR="$(yarn global bin)" echo_npm_postinstall + "$sh_c" "$YARN_PATH" global add code-server --unsafe-perm + NPM_BIN_DIR="\$($YARN_PATH global bin)" echo_npm_postinstall return - elif command_exists npm; then + elif command_exists "$NPM_PATH"; then sh_c="sh_c" - if [ ! -w "$(npm config get prefix)" ]; then + if [ ! "${DRY_RUN-}" ] && [ ! -w "$(NPM_PATH config get prefix)" ]; then sh_c="sudo_sh_c" fi echoh "Installing with npm." echoh - "$sh_c" npm install -g code-server --unsafe-perm - NPM_BIN_DIR="$(npm bin -g)" echo_npm_postinstall + "$sh_c" "$NPM_PATH" install -g code-server --unsafe-perm + NPM_BIN_DIR="\$($NPM_PATH bin -g)" echo_npm_postinstall return fi - echoh echoerr "Please install npm or yarn to install code-server!" echoerr "You will need at least node v12 and a few C dependencies." echoerr "See the docs https://coder.com/docs/code-server/v3.10.2/install#yarn-npm" + exit 1 } -os() { - case "$(uname)" in - Linux) - echo linux - ;; - Darwin) - echo macos - ;; - FreeBSD) - echo freebsd +# Run $1 if we have a standalone otherwise run install_npm. +npm_fallback() { + if has_standalone; then + $1 + else + echoh "No standalone releases for $ARCH." + echoh "Falling back to installation from npm." + install_npm + fi +} + +# Determine if we have standalone releases on GitHub for the system's arch. +has_standalone() { + case $ARCH in + amd64) return 0 ;; + # We only have amd64 for macOS. + arm64) + [ "$(distro)" != macos ] + return ;; + *) return 1 ;; esac } -# distro prints the detected operating system including linux distros. -# Also parses ID_LIKE for common distro bases. +os() { + uname="$(uname)" + case $uname in + Linux) echo linux ;; + Darwin) echo macos ;; + FreeBSD) echo freebsd ;; + *) echo "$uname" ;; + esac +} + +# Print the detected Linux distro, otherwise print the OS name. # # Example outputs: # - macos -> macos @@ -486,7 +506,7 @@ distro() { fi } -# os_name prints a pretty human readable name for the OS/Distro. +# Print a human-readable name for the OS/distro. distro_name() { if [ "$(uname)" = "Darwin" ]; then echo "macOS v$(sw_vers -productVersion)" @@ -506,20 +526,16 @@ distro_name() { } arch() { - case "$(uname -m)" in - aarch64) - echo arm64 - ;; - x86_64) - echo amd64 - ;; - amd64) # FreeBSD. - echo amd64 - ;; + uname_m=$(uname -m) + case $uname_m in + aarch64) echo arm64 ;; + x86_64) echo amd64 ;; + *) echo "$uname_m" ;; esac } command_exists() { + if [ ! "$1" ]; then return 1; fi command -v "$@" > /dev/null } From 3339853c26cf5b0f85b3619dac666e38c1d9efcd Mon Sep 17 00:00:00 2001 From: Asher Date: Fri, 2 Jul 2021 19:19:23 -0500 Subject: [PATCH 4/5] Avoid root when prefix is writable Previously if the prefix was non-existent we would switch to root even if the user does have the permissions to create the directory. Fixes #3585 --- .github/workflows/installer.yml | 18 ++++++++++++++++++ install.sh | 5 ++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/.github/workflows/installer.yml b/.github/workflows/installer.yml index 0a004b8b..959397f4 100644 --- a/.github/workflows/installer.yml +++ b/.github/workflows/installer.yml @@ -24,6 +24,24 @@ jobs: - name: Test code-server run: yarn test:standalone-release code-server + alpine: + name: Test installer on Alpine + runs-on: ubuntu-latest + container: "alpine:3.14" + steps: + - name: Checkout repo + uses: actions/checkout@v2 + + - name: Install curl + run: apk add curl + + - name: Add user + run: adduser coder --disabled-password + + # Standalone should work without root. + - name: Test standalone to a non-existent prefix + run: su coder -c "./install.sh --method standalone --prefix /tmp/does/not/yet/exist" + macos: name: Test installer on macOS runs-on: macos-latest diff --git a/install.sh b/install.sh index e51afc19..2b77c5d3 100755 --- a/install.sh +++ b/install.sh @@ -132,7 +132,6 @@ main() { unset \ DRY_RUN \ METHOD \ - STANDALONE_INSTALL_PREFIX \ OPTIONAL \ ALL_FLAGS \ RSH_ARGS \ @@ -381,6 +380,10 @@ install_standalone() { fetch "https://github.com/cdr/code-server/releases/download/v$VERSION/code-server-$VERSION-$OS-$ARCH.tar.gz" \ "$CACHE_DIR/code-server-$VERSION-$OS-$ARCH.tar.gz" + # -w only works if the directory exists so try creating it first. If this + # fails we can ignore the error as the -w check will then swap us to sudo. + sh_c mkdir -p "$STANDALONE_INSTALL_PREFIX" 2> /dev/null || true + sh_c="sh_c" if [ ! -w "$STANDALONE_INSTALL_PREFIX" ]; then sh_c="sudo_sh_c" From 4ffecd641dec6765ebeb1070d94b8ace9a2d03fc Mon Sep 17 00:00:00 2001 From: Asher Date: Tue, 13 Jul 2021 12:24:30 -0500 Subject: [PATCH 5/5] Check for bashisms in install script --- .github/workflows/scripts.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/scripts.yml b/.github/workflows/scripts.yml index 47df18d6..7b12147b 100644 --- a/.github/workflows/scripts.yml +++ b/.github/workflows/scripts.yml @@ -20,8 +20,11 @@ jobs: - name: Checkout repo uses: actions/checkout@v2 - - name: Install bats - run: apk add bats + - name: Install test utilities + run: apk add bats checkbashisms + + - name: Check Bashisms + run: checkbashisms ./install.sh - name: Run script unit tests run: ./ci/dev/test-scripts.sh