install.sh 9.4 KB
Newer Older
A
Anmol Sethi 已提交
1 2 3 4
#!/bin/sh
set -eu

usage() {
5 6
  cat <<EOF
$0 [--dry-run] [--version X.X.X] [--static <install-prefix>=~/.local]
A
Anmol Sethi 已提交
7

8
Installs latest code-server on any macOS or Linux system preferring to use the OS package manager.
A
Anmol Sethi 已提交
9

10
  curl -fsSL https://code-server.dev/install.sh | sh -s --
A
Anmol Sethi 已提交
11

12 13 14 15 16
- For Debian, Ubuntu, Raspbian it will install the latest deb package.
- For Fedora, CentOS, RHEL, 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 static release into ~/.local
  - Add ~/.local/bin to your \$PATH to run code-server.
A
Anmol Sethi 已提交
17

18 19 20
- For macOS it will install the Homebrew package.
  - If Homebrew is not installed it will install the latest static release into ~/.local
  - Add ~/.local/bin to your \$PATH to run code-server.
A
Anmol Sethi 已提交
21

22 23 24
- If ran on an architecture with no binary releases or outdated libc/libcxx, it will install the
  npm package with yarn or npm.
  - We only have binary releases for amd64 and arm64 presently.
A
Anmol Sethi 已提交
25

26 27
    --dry-run Enables a dry run where where the steps that would have taken place
              are printed but do not actually execute.
A
Anmol Sethi 已提交
28

29
    --version Pass to install a specific version instead of the latest release.
A
Anmol Sethi 已提交
30

31
    --static  Forces the installation of a static release into ~/.local
A
Anmol Sethi 已提交
32

33 34 35 36
              This flag takes an optional argument for the installation prefix which defaults to "~/.local".
              code-server will be unarchived into ~/.local/lib/code-server.X.X.X and the binary will be symlinked
              into "~/.local/bin/code-server". You will need to add ~/.local/bin to your \$PATH to use it without
              the full path.
A
Anmol Sethi 已提交
37

38
              To install system wide set the prefix to /usr/local.
A
Anmol Sethi 已提交
39
EOF
40 41 42 43 44 45 46
}

echo_latest_version() {
  version="$(curl -fsSL https://api.github.com/repos/cdr/code-server/releases/latest | jq -r .tag_name)"
  # Strip leading v.
  version="${version:1}"
  echo "$version"
A
Anmol Sethi 已提交
47 48 49 50
}

echo_static_postinstall() {
  echo
51
  cat <<EOF
A
Anmol Sethi 已提交
52 53 54 55 56 57 58 59 60 61
Static release has been installed into $STATIC_INSTALL_PREFIX/code-server-$VERSION
Please extend your path to use code-server:
  PATH="$STATIC_INSTALL_PREFIX/code-server-$VERSION/bin:\$PATH"
Then you can run:
  code-server
EOF
}

echo_systemd_postinstall() {
  echo
62
  cat <<EOF
A
Anmol Sethi 已提交
63 64 65 66 67 68 69 70
To have systemd start code-server now and restart on boot:
  systemctl --user enable --now code-server
Or, if you don't want/need a background service you can run:
  code-server
EOF
}

main() {
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
  if [ "${TRACE-}" ]; then
    set -x
  fi

  unset \
    DRY_RUN \
    STATIC \
    STATIC_INSTALL_PREFIX \
    SKIP_LOG \
    VERSION \
    OPTIONAL

  while [ "$#" -gt 0 ]; do
    case "$1" in
    --dry-run)
      DRY_RUN=1
      ;;
    --static)
      STATIC=1
      if [ "${2-}" ]; then
        STATIC_INSTALL_PREFIX="$(OPTIONAL=1 parse_arg "$@")"
        shift
      fi
      ;;
    --static=*)
      STATIC=1
      STATIC_INSTALL_PREFIX="$(OPTIONAL=1 parse_arg "$@")"
      ;;
    --version)
      VERSION="$(parse_arg "$@")"
      shift
      ;;
    --version=*)
      VERSION="$(parse_arg "$@")"
      ;;
    -h | --h | --help)
      usage
      exit 0
      ;;
    *)
      echoerr "Unknown flag $1"
      echoerr "Run with --help to see usage."
      exit 1
      ;;
A
Anmol Sethi 已提交
115
    esac
116 117

    shift
A
Anmol Sethi 已提交
118
  done
119 120 121 122 123 124 125 126

  VERSION="${VERSION-$(echo_latest_version)}"
  STATIC_INSTALL_PREFIX="${STATIC_INSATLL_PREFIX-$HOME/.local}"

  echo "${DRY_RUN-}"
  echo "${STATIC_INSTALL_PREFIX-}"
  echo "${VERSION-}"
  exit 1
A
Anmol Sethi 已提交
127 128 129

  OS="$(os)"
  if [ ! "$OS" ]; then
130
    echoerr "Unsupported OS $(uname)."
A
Anmol Sethi 已提交
131 132 133 134 135 136 137 138
    exit 1
  fi

  distro_name

  ARCH="$(arch)"
  if [ ! "$ARCH" ]; then
    if [ "${STATIC-}" ]; then
139 140
      echoerr "No static releases available for the architecture $(uname -m)."
      echoerr "Please rerun without the -s flag to install from npm."
A
Anmol Sethi 已提交
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
      exit 1
    fi
    install_npm
    exit 0
  fi

  CACHE_DIR="$(cache_dir)"
  mkdir -p "$CACHE_DIR"

  if [ "${STATIC-}" ]; then
    install_static
    return
  fi

  case "$(distro)" in
  macos)
    install_macos
    ;;
  ubuntu | debian | raspbian)
    install_deb
    ;;
  centos | fedora | rhel | opensuse)
    install_rpm
    ;;
  arch)
    install_arch
    ;;
  *)
    install_static
    ;;

  esac
}

175 176 177 178 179 180 181 182 183 184 185
parse_arg() {
  case "$1" in
  *=*)
    opt="${1#=*}"
    optarg="${1#*=}"
    if [ ! "$optarg" -a ! "${OPTIONAL-}" ]; then
      echoerr "$opt requires an argument"
      echoerr "Run with --help to see usage."
      exit 1
    fi
    echo "$optarg"
A
Anmol Sethi 已提交
186
    return
187 188
    ;;
  esac
A
Anmol Sethi 已提交
189

190 191 192 193 194 195 196 197 198 199 200 201 202
  case "${2-}" in
  "" | -* | --*)
    if [ ! "${OPTIONAL-}" ]; then
      echoerr "$1 requires an argument"
      echoerr "Run with --help to see usage."
      exit 1
    fi
    ;;
  *)
    echo "$2"
    return
    ;;
  esac
A
Anmol Sethi 已提交
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
}

fetch() {
  URL="$1"
  FILE="$2"

  if [ -e "$FILE" ]; then
    echo
    echo "+ Using cached $FILE from $URL"
    return
  fi

  sh_c curl \
    -#fL \
    -Ro "$FILE.incomplete" \
    -C - \
    "$URL"
  mv "$FILE.incomplete" "$FILE"
}

223 224 225 226 227 228 229 230 231 232 233 234 235 236
install_macos() {
  if command_exists brew; then
    echo "Installing from Homebrew."

    sh_c brew install code-server

    return
  fi

  echo "Homebrew is not installed so installing static release."

  install_static
}

A
Anmol Sethi 已提交
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
install_deb() {
  echo "Installing v$VERSION deb package from GitHub releases."

  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
}

install_rpm() {
  echo "Installing v$VERSION rpm package from GitHub releases."

  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
}

255
install_aur() {
A
Anmol Sethi 已提交
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
  echo "Installing from the AUR."

  fetch "https://aur.archlinux.org/cgit/aur.git/snapshot/code-server.tar.gz" "$CACHE_DIR/code-server-aur.tar.gz"

  tmp_dir="$(mktemp -d)"
  (
    cd "$tmp_dir"
    tar -xzf "$CACHE_DIR/code-server-aur.tar.gz" --strip-components 1
    sh_c makepkg -si
  )
  rm -Rf "$tmp_dir"

  echo_systemd_postinstall
}

install_static() {
  STATIC_INSTALL_PREFIX=${STATIC_INSTALL_PREFIX-/usr/local/lib}

  echo "Installing static release v$VERSION"

  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"

  if [ ! -d "$STATIC_INSTALL_PREFIX" ]; then
    echo
280
    echoerr "Static release install prefix $STATIC_INSTALL_PREFIX does not exist"
A
Anmol Sethi 已提交
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
    exit 1
  fi

  sh_c="sh_c"
  if [ ! -w "$STATIC_INSTALL_PREFIX" ]; then
    sh_c="sudo_sh_c"
  fi

  "$sh_c" tar -C "$STATIC_INSTALL_PREFIX" -xzf "$CACHE_DIR/code-server-$VERSION-$OS-$ARCH.tar.gz"
  # In case previously installed.
  SKIP_LOG=1 "$sh_c" rm -Rf "$STATIC_INSTALL_PREFIX/code-server-$VERSION"
  "$sh_c" mv -f "$STATIC_INSTALL_PREFIX/code-server-$VERSION-$OS-$ARCH" "$STATIC_INSTALL_PREFIX/code-server-$VERSION"

  echo_static_postinstall
}

install_npm() {
298
  echoerr "No precompiled releases for $(uname -m)."
A
Anmol Sethi 已提交
299 300 301 302 303 304 305 306 307
  if command_exists yarn; then
    echo "Installing with yarn."
    sh_c yarn global add code-server --unsafe-perm
    return
  elif command_exists npm; then
    echo "Installing with npm."
    sh_c npm install -g code-server --unsafe-perm
    return
  fi
308 309 310 311
  echoerr
  echoerr "Please install npm or yarn to install code-server!"
  echoerr "You will need at least node v12 and a few C build dependencies."
  echoerr "See the docs https://github.com/cdr/code-server#yarn-npm"
A
Anmol Sethi 已提交
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
  exit 1
}

os() {
  case "$(uname)" in
  Linux)
    echo linux
    ;;
  Darwin)
    echo macos
    ;;
  esac
}

# distro prints the detected operating system including linux distros.
#
# Example outputs:
# - macos
# - debian, ubuntu, raspbian
# - centos, fedora, rhel, opensuse
# - alpine
# - arch
#
# Inspired by https://github.com/docker/docker-install/blob/26ff363bcf3b3f5a00498ac43694bf1c7d9ce16c/install.sh#L111-L120.
distro() {
  if [ "$(uname)" = "Darwin" ]; then
    echo "macos"
    return
  fi

  if [ ! -f /etc/os-release ]; then
    return
  fi

  (
    . /etc/os-release
    case "$ID" in opensuse-*)
      # opensuse's ID's look like opensuse-leap and opensuse-tumbleweed.
      echo "opensuse"
      return
      ;;
    esac

    echo "$ID"
  )
}

# os_name prints a pretty human readable name for the OS/Distro.
distro_name() {
  if [ "$(uname)" = "Darwin" ]; then
    echo "macOS v$(sw_vers -productVersion)"
    return
  fi

  if [ ! -f /etc/os-release ]; then
    (
      . /etc/os-release
      echo "$PRETTY_NAME"
    )
  fi

  # Prints something like: Linux 4.19.0-9-amd64
  uname -sr
}

arch() {
  case "$(uname -m)" in
  aarch64)
    echo arm64
    ;;
  x86_64)
    echo amd64
    ;;
  esac
}

command_exists() {
389
  command -v "$@" >/dev/null 2>&1
A
Anmol Sethi 已提交
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410
}

sh_c() {
  if [ ! "${SKIP_LOG-}" ]; then
    echo
    echo "+ $*"
  fi
  if [ ! "${DRY_RUN-}" ]; then
    sh -c "$*"
  fi
}

sudo_sh_c() {
  if [ "$(id -u)" = 0 ]; then
    sh_c "$@"
  elif command_exists sudo; then
    sh_c "sudo $*"
  elif command_exists su; then
    sh_c "su -c '$*'"
  else
    echo
411 412 413
    echoerr "This script needs to run the following command as root."
    echoerr "  $*"
    echoerr "Please run this script as root or install sudo or su."
A
Anmol Sethi 已提交
414 415 416 417
    exit 1
  fi
}

418
echo_cache_dir() {
A
Anmol Sethi 已提交
419 420 421 422 423 424 425 426 427
  if [ "${XDG_CACHE_HOME-}" ]; then
    echo "$XDG_CACHE_HOME/code-server"
  elif [ "${HOME-}" ]; then
    echo "$HOME/.cache/code-server"
  else
    echo "/tmp/code-server-cache"
  fi
}

428 429 430 431
echoerr() {
  echo "$@" >&2
}

A
Anmol Sethi 已提交
432
main "$@"