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

A
Anmol Sethi 已提交
4 5 6
# code-server's automatic install script.
# See https://github.com/cdr/code-server/blob/master/doc/install.md

A
Anmol Sethi 已提交
7
usage() {
A
Anmol Sethi 已提交
8
  arg0="$0"
9
  if [ "$0" = sh ]; then
A
Anmol Sethi 已提交
10
    arg0="curl -fsSL https://code-server.dev/install.sh | sh -s --"
11
  else
A
Anmol Sethi 已提交
12
    not_curl_usage="The latest script is available at https://code-server.dev/install.sh
A
Anmol Sethi 已提交
13
"
14
  fi
A
Anmol Sethi 已提交
15

16
  cath << EOF
A
Anmol Sethi 已提交
17
Installs code-server for Linux and macOS.
A
Anmol Sethi 已提交
18 19
It tries to use the system package manager if possible.
After successful installation it explains how to start using code-server.
A
Anmol Sethi 已提交
20
${not_curl_usage-}
21
Usage:
A
Anmol Sethi 已提交
22

A
Anmol Sethi 已提交
23 24 25 26 27 28
  $arg0 [--dry-run] [--version X.X.X] [--method detect] [--prefix ~/.local]

  --dry-run
      Echo the commands for the install process without running them.
  --version X.X.X
      Install a specific version instead of the latest.
29
  --method [detect | standalone]
A
Anmol Sethi 已提交
30 31 32
      Choose the installation method. Defaults to detect.
      - detect detects the system package manager and tries to use it.
        Full reference on the process is further below.
33
      - standalone installs a standalone release archive into ~/.local
A
Anmol Sethi 已提交
34 35
        Add ~/.local/bin to your \$PATH to use it.
  --prefix <dir>
36
      Sets the prefix used by standalone release archives. Defaults to ~/.local
A
Anmol Sethi 已提交
37 38 39
      The release is unarchived into ~/.local/lib/code-server-X.X.X
      and the binary symlinked into ~/.local/bin/code-server
      To install system wide pass ---prefix=/usr/local
A
Anmol Sethi 已提交
40

A
Anmol Sethi 已提交
41 42
- 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.
43
- For Arch Linux it will install the AUR package.
44
- For any unrecognized Linux operating system it will install the latest standalone
A
Anmol Sethi 已提交
45
  release into ~/.local
A
Anmol Sethi 已提交
46

47
- For macOS it will install the Homebrew package.
48
  - If Homebrew is not installed it will install the latest standalone release
A
Anmol Sethi 已提交
49
    into ~/.local
A
Anmol Sethi 已提交
50

51
- If ran on an architecture with no releases, it will install the
A
Anmol Sethi 已提交
52
  npm package with yarn or npm.
53
  - We only have releases for amd64 and arm64 presently.
A
Anmol Sethi 已提交
54
  - The npm package builds the native modules on postinstall.
A
Anmol Sethi 已提交
55

A
Anmol Sethi 已提交
56 57
It will cache all downloaded assets into ~/.cache/code-server

A
Anmol Sethi 已提交
58
More installation docs are at https://github.com/cdr/code-server/blob/master/doc/install.md
A
Anmol Sethi 已提交
59
EOF
60 61 62
}

echo_latest_version() {
63 64
  # https://gist.github.com/lukechilds/a83e1d7127b78fef38c2914c4ececc3c#gistcomment-2758860
  version="$(curl -fsSLI -o /dev/null -w "%{url_effective}" https://github.com/cdr/code-server/releases/latest)"
65 66
  version="${version#https://github.com/cdr/code-server/releases/tag/}"
  version="${version#v}"
67
  echo "$version"
A
Anmol Sethi 已提交
68 69
}

70
echo_standalone_postinstall() {
71 72
  echoh
  cath << EOF
73
Standalone release has been installed into $STANDALONE_INSTALL_PREFIX/lib/code-server-$VERSION
A
Anmol Sethi 已提交
74
Please extend your path to use code-server:
75
  PATH="$STANDALONE_INSTALL_PREFIX/bin:\$PATH"
A
Anmol Sethi 已提交
76 77 78 79 80 81
Then you can run:
  code-server
EOF
}

echo_systemd_postinstall() {
82 83
  echoh
  cath << EOF
A
Anmol Sethi 已提交
84 85 86 87 88 89 90 91
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() {
92 93 94 95 96 97
  if [ "${TRACE-}" ]; then
    set -x
  fi

  unset \
    DRY_RUN \
A
Anmol Sethi 已提交
98
    METHOD \
99
    STANDALONE_INSTALL_PREFIX \
100 101 102 103 104 105 106 107
    VERSION \
    OPTIONAL

  while [ "$#" -gt 0 ]; do
    case "$1" in
    --dry-run)
      DRY_RUN=1
      ;;
A
Anmol Sethi 已提交
108 109 110 111 112 113
    --method)
      METHOD="$(parse_arg "$@")"
      shift
      ;;
    --method=*)
      METHOD="$(parse_arg "$@")"
114
      ;;
A
Anmol Sethi 已提交
115
    --prefix)
116
      STANDALONE_INSTALL_PREFIX="$(parse_arg "$@")"
A
Anmol Sethi 已提交
117 118 119
      shift
      ;;
    --prefix=*)
120
      STANDALONE_INSTALL_PREFIX="$(parse_arg "$@")"
121 122 123 124 125 126 127 128
      ;;
    --version)
      VERSION="$(parse_arg "$@")"
      shift
      ;;
    --version=*)
      VERSION="$(parse_arg "$@")"
      ;;
A
Anmol Sethi 已提交
129
    -h | --h | -help | --help)
130 131 132 133 134 135 136 137
      usage
      exit 0
      ;;
    *)
      echoerr "Unknown flag $1"
      echoerr "Run with --help to see usage."
      exit 1
      ;;
A
Anmol Sethi 已提交
138
    esac
139 140

    shift
A
Anmol Sethi 已提交
141
  done
142 143

  VERSION="${VERSION-$(echo_latest_version)}"
A
Anmol Sethi 已提交
144
  METHOD="${METHOD-detect}"
145
  if [ "$METHOD" != detect ] && [ "$METHOD" != standalone ]; then
A
Anmol Sethi 已提交
146 147 148 149
    echoerr "Unknown install method \"$METHOD\""
    echoerr "Run with --help to see usage."
    exit 1
  fi
150
  STANDALONE_INSTALL_PREFIX="${STANDALONE_INSTALL_PREFIX-$HOME/.local}"
A
Anmol Sethi 已提交
151 152 153

  OS="$(os)"
  if [ ! "$OS" ]; then
154
    echoerr "Unsupported OS $(uname)."
A
Anmol Sethi 已提交
155 156 157 158 159 160 161
    exit 1
  fi

  distro_name

  ARCH="$(arch)"
  if [ ! "$ARCH" ]; then
162 163 164
    if [ "$METHOD" = standalone ]; then
      echoerr "No releases available for the architecture $(uname -m)."
      echoerr 'Please rerun without the "--method standalone" flag to install from npm.'
A
Anmol Sethi 已提交
165 166
      exit 1
    fi
167
    echoh "No precompiled releases for $(uname -m)."
A
Anmol Sethi 已提交
168
    install_npm
A
Anmol Sethi 已提交
169
    return
A
Anmol Sethi 已提交
170 171
  fi

172
  CACHE_DIR="$(echo_cache_dir)"
A
Anmol Sethi 已提交
173 174
  mkdir -p "$CACHE_DIR"

175 176
  if [ "$METHOD" = standalone ]; then
    install_standalone
A
Anmol Sethi 已提交
177 178 179 180 181 182 183 184 185 186 187 188 189 190
    return
  fi

  case "$(distro)" in
  macos)
    install_macos
    ;;
  ubuntu | debian | raspbian)
    install_deb
    ;;
  centos | fedora | rhel | opensuse)
    install_rpm
    ;;
  arch)
A
Anmol Sethi 已提交
191
    install_aur
A
Anmol Sethi 已提交
192 193
    ;;
  *)
194
    echoh "Unsupported package manager."
195
    install_standalone
A
Anmol Sethi 已提交
196 197 198 199
    ;;
  esac
}

200 201 202
parse_arg() {
  case "$1" in
  *=*)
203 204 205
    # Remove everything after first equal sign.
    opt="${1%%=*}"
    # Remove everything before first equal sign.
206
    optarg="${1#*=}"
207
    if [ ! "$optarg" ] && [ ! "${OPTIONAL-}" ]; then
208 209 210 211 212
      echoerr "$opt requires an argument"
      echoerr "Run with --help to see usage."
      exit 1
    fi
    echo "$optarg"
A
Anmol Sethi 已提交
213
    return
214 215
    ;;
  esac
A
Anmol Sethi 已提交
216

217
  case "${2-}" in
218
  "" | -*)
219 220 221 222 223 224 225 226 227 228 229
    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 已提交
230 231 232 233 234 235 236
}

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

  if [ -e "$FILE" ]; then
237
    echoh "+ Reusing $CACHE_DIR/${URL##*/}"
A
Anmol Sethi 已提交
238 239 240 241 242
    return
  fi

  sh_c curl \
    -#fL \
A
Anmol Sethi 已提交
243
    -o "$FILE.incomplete" \
A
Anmol Sethi 已提交
244 245
    -C - \
    "$URL"
A
Anmol Sethi 已提交
246
  sh_c mv "$FILE.incomplete" "$FILE"
A
Anmol Sethi 已提交
247 248
}

249 250
install_macos() {
  if command_exists brew; then
251 252
    echoh "Installing from Homebrew."
    echoh
253 254 255 256 257 258

    sh_c brew install code-server

    return
  fi

259
  echoh "Homebrew not installed."
260

261
  install_standalone
262 263
}

A
Anmol Sethi 已提交
264
install_deb() {
265 266
  echoh "Installing v$VERSION deb package from GitHub releases."
  echoh
A
Anmol Sethi 已提交
267

A
Anmol Sethi 已提交
268 269
  fetch "https://github.com/cdr/code-server/releases/download/v$VERSION/code-server_${VERSION}_$ARCH.deb" \
    "$CACHE_DIR/code-server_${VERSION}_$ARCH.deb"
A
Anmol Sethi 已提交
270 271 272 273 274 275
  sudo_sh_c dpkg -i "$CACHE_DIR/code-server_${VERSION}_$ARCH.deb"

  echo_systemd_postinstall
}

install_rpm() {
276 277
  echoh "Installing v$VERSION rpm package from GitHub releases."
  echoh
A
Anmol Sethi 已提交
278

A
Anmol Sethi 已提交
279 280
  fetch "https://github.com/cdr/code-server/releases/download/v$VERSION/code-server-$VERSION-$ARCH.rpm" \
    "$CACHE_DIR/code-server-$VERSION-$ARCH.rpm"
A
Anmol Sethi 已提交
281 282 283 284 285
  sudo_sh_c rpm -i "$CACHE_DIR/code-server-$VERSION-$ARCH.rpm"

  echo_systemd_postinstall
}

286
install_aur() {
287 288
  echoh "Installing from the AUR."
  echoh
A
Anmol Sethi 已提交
289

A
Anmol Sethi 已提交
290 291 292 293 294 295
  sh_c mkdir -p "$CACHE_DIR/code-server-aur"
  sh_c "curl -#fsSL https://aur.archlinux.org/cgit/aur.git/snapshot/code-server.tar.gz | tar -xzC $CACHE_DIR/code-server-aur --strip-components 1"
  echo "+ cd $CACHE_DIR/code-server-aur"
  if [ ! "${DRY_RUN-}" ]; then
    cd "$CACHE_DIR/code-server-aur"
  fi
296
  sh_c makepkg -si
A
Anmol Sethi 已提交
297 298 299 300

  echo_systemd_postinstall
}

301
install_standalone() {
A
Anmol Sethi 已提交
302
  echoh "Installing standalone release archive v$VERSION from GitHub releases."
303
  echoh
A
Anmol Sethi 已提交
304

A
Anmol Sethi 已提交
305 306
  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"
A
Anmol Sethi 已提交
307 308

  sh_c="sh_c"
309
  if [ ! -w "$STANDALONE_INSTALL_PREFIX" ]; then
A
Anmol Sethi 已提交
310 311 312
    sh_c="sudo_sh_c"
  fi

313
  if [ -e "$STANDALONE_INSTALL_PREFIX/lib/code-server-$VERSION" ]; then
314 315 316
    echoh
    echoh "code-server-$VERSION is already installed at $STANDALONE_INSTALL_PREFIX/lib/code-server-$VERSION"
    echoh "Remove it to reinstall."
A
Anmol Sethi 已提交
317
    exit 0
318
  fi
319

320 321 322 323
  "$sh_c" mkdir -p "$STANDALONE_INSTALL_PREFIX/lib" "$STANDALONE_INSTALL_PREFIX/bin"
  "$sh_c" tar -C "$STANDALONE_INSTALL_PREFIX/lib" -xzf "$CACHE_DIR/code-server-$VERSION-$OS-$ARCH.tar.gz"
  "$sh_c" mv -f "$STANDALONE_INSTALL_PREFIX/lib/code-server-$VERSION-$OS-$ARCH" "$STANDALONE_INSTALL_PREFIX/lib/code-server-$VERSION"
  "$sh_c" ln -fs "$STANDALONE_INSTALL_PREFIX/lib/code-server-$VERSION/bin/code-server" "$STANDALONE_INSTALL_PREFIX/bin/code-server"
A
Anmol Sethi 已提交
324

325
  echo_standalone_postinstall
A
Anmol Sethi 已提交
326 327 328 329
}

install_npm() {
  if command_exists yarn; then
330 331 332 333
    sh_c="sh_c"
    if [ ! -w "$(yarn global bin)" ]; then
      sh_c="sudo_sh_c"
    fi
334 335
    echoh "Installing with yarn."
    echoh
336
    "$sh_c" yarn global add code-server --unsafe-perm
A
Anmol Sethi 已提交
337 338
    return
  elif command_exists npm; then
339 340 341 342
    sh_c="sh_c"
    if [ ! -w "$(npm config get prefix)" ]; then
      sh_c="sudo_sh_c"
    fi
343 344
    echoh "Installing with npm."
    echoh
345
    "$sh_c" npm install -g code-server --unsafe-perm
A
Anmol Sethi 已提交
346 347
    return
  fi
348
  echoh
349
  echoerr "Please install npm or yarn to install code-server!"
A
Anmol Sethi 已提交
350
  echoerr "You will need at least node v12 and a few C dependencies."
351
  echoerr "See the docs https://github.com/cdr/code-server#yarn-npm"
A
Anmol Sethi 已提交
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
  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

382 383 384 385 386 387 388 389 390 391 392 393
  if [ -f /etc/os-release ]; then
    (
      . /etc/os-release
      case "$ID" in opensuse-*)
        # opensuse's ID's look like opensuse-leap and opensuse-tumbleweed.
        echo "opensuse"
        return
        ;;
      esac

      echo "$ID"
    )
A
Anmol Sethi 已提交
394 395 396 397 398 399 400 401 402 403 404
    return
  fi
}

# 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

405
  if [ -f /etc/os-release ]; then
A
Anmol Sethi 已提交
406 407 408 409
    (
      . /etc/os-release
      echo "$PRETTY_NAME"
    )
410
    return
A
Anmol Sethi 已提交
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428
  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() {
429
  command -v "$@" > /dev/null 2>&1
A
Anmol Sethi 已提交
430 431 432
}

sh_c() {
433
  echoh "+ $*"
A
Anmol Sethi 已提交
434 435 436 437 438 439 440 441 442 443 444 445 446
  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
447
    echoh
448 449
    echoerr "This script needs to run the following command as root."
    echoerr "  $*"
A
Anmol Sethi 已提交
450
    echoerr "Please install sudo or su."
A
Anmol Sethi 已提交
451 452 453 454
    exit 1
  fi
}

455
echo_cache_dir() {
A
Anmol Sethi 已提交
456 457 458 459 460 461 462 463 464
  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
}

465 466
echoh() {
  echo "$@" | humanpath
467 468
}

469
cath() {
470 471 472
  humanpath
}

473
echoerr() {
474
  echoh "$@" >&2
475 476
}

A
Anmol Sethi 已提交
477 478
# humanpath replaces all occurances of " $HOME" with " ~"
# and all occurances of '"$HOME' with the literal '"$HOME'.
479
humanpath() {
A
Anmol Sethi 已提交
480
  sed "s# $HOME# ~#g; s#\"$HOME#\"\$HOME#g"
481 482
}

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