install.sh 11.0 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 13
    curl_usage="The latest script is available at https://code-server.dev/install.sh
"
14
  fi
A
Anmol Sethi 已提交
15

16
  cat << 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
${curl_usage-}
21
Usage:
A
Anmol Sethi 已提交
22

A
Anmol Sethi 已提交
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
  $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.
  --method [detect | archive]
      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.
      - archive installs a static release archive into ~/.local
        Add ~/.local/bin to your \$PATH to use it.
  --prefix <dir>
      Sets the prefix used by static release archives. Defaults to ~/.local
      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.
A
Anmol Sethi 已提交
44 45
- For any unrecognized Linux operating system it will install the latest static
  release into ~/.local
A
Anmol Sethi 已提交
46

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

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

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

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

echo_latest_version() {
62 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)"
  version="${version#https://github.com/cdr/code-server/releases/tag/v}"
65
  echo "$version"
A
Anmol Sethi 已提交
66 67 68 69
}

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

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

  unset \
    DRY_RUN \
A
Anmol Sethi 已提交
96 97
    METHOD \
    ARCHIVE_INSTALL_PREFIX \
98 99 100 101 102 103 104 105
    VERSION \
    OPTIONAL

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

    shift
A
Anmol Sethi 已提交
139
  done
140 141

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

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

  distro_name

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

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

A
Anmol Sethi 已提交
173 174
  if [ "$METHOD" = archive ]; then
    install_archive
A
Anmol Sethi 已提交
175 176 177 178 179 180 181 182 183 184 185 186 187 188
    return
  fi

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

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

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

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

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

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

247 248 249
install_macos() {
  if command_exists brew; then
    echo "Installing from Homebrew."
A
Anmol Sethi 已提交
250
    echo
251 252 253 254 255 256

    sh_c brew install code-server

    return
  fi

A
Anmol Sethi 已提交
257
  echo "Homebrew not installed."
258

A
Anmol Sethi 已提交
259
  install_archive
260 261
}

A
Anmol Sethi 已提交
262 263
install_deb() {
  echo "Installing v$VERSION deb package from GitHub releases."
A
Anmol Sethi 已提交
264
  echo
A
Anmol Sethi 已提交
265

A
Anmol Sethi 已提交
266 267
  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 已提交
268 269 270 271 272 273 274
  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."
A
Anmol Sethi 已提交
275
  echo
A
Anmol Sethi 已提交
276

A
Anmol Sethi 已提交
277 278
  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 已提交
279 280 281 282 283
  sudo_sh_c rpm -i "$CACHE_DIR/code-server-$VERSION-$ARCH.rpm"

  echo_systemd_postinstall
}

284
install_aur() {
A
Anmol Sethi 已提交
285
  echo "Installing from the AUR."
A
Anmol Sethi 已提交
286
  echo
A
Anmol Sethi 已提交
287 288

  tmp_dir="$(mktemp -d)"
A
Anmol Sethi 已提交
289

290 291 292 293
  echo "+ Downloading PKGBUILD into $tmp_dir from https://aur.archlinux.org/cgit/aur.git/snapshot/code-server.tar.gz"
  curl -fsSL https://aur.archlinux.org/cgit/aur.git/snapshot/code-server.tar.gz | tar -xzC "$tmp_dir"
  VERSION="$(. "$tmp_dir/code-server/PKGBUILD" && echo "$pkgver")"
  rm -R "$tmp_dir"
A
Anmol Sethi 已提交
294

295 296 297 298 299 300 301
  mkdir -p "$CACHE_DIR/code-server-$VERSION-aur"
  sh_c cp -a "$tmp_dir/code-server/*" "$CACHE_DIR/code-server-$VERSION-aur"

  echo "+ Installing $CACHE_DIR/code-server-$VERSION-aur"

  cd "$CACHE_DIR/code-server-$VERSION-aur"
  sh_c makepkg -si
A
Anmol Sethi 已提交
302 303 304 305

  echo_systemd_postinstall
}

A
Anmol Sethi 已提交
306
install_archive() {
A
Anmol Sethi 已提交
307
  echo "Installing static release v$VERSION"
A
Anmol Sethi 已提交
308
  echo
A
Anmol Sethi 已提交
309

A
Anmol Sethi 已提交
310 311
  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 已提交
312 313

  sh_c="sh_c"
A
Anmol Sethi 已提交
314
  if [ ! -w "$ARCHIVE_INSTALL_PREFIX" ]; then
A
Anmol Sethi 已提交
315 316 317
    sh_c="sudo_sh_c"
  fi

A
Anmol Sethi 已提交
318
  if [ -e "$ARCHIVE_INSTALL_PREFIX/lib/code-server-$VERSION" ]; then
319
    echo
A
Anmol Sethi 已提交
320 321 322
    echo "code-server-$VERSION is already installed at $ARCHIVE_INSTALL_PREFIX/lib/code-server-$VERSION"
    echo "Remove it to reinstall."
    exit 0
323
  fi
324 325

  "$sh_c" mkdir -p "$ARCHIVE_INSTALL_PREFIX/lib" "$ARCHIVE_INSTALL_PREFIX/bin"
A
Anmol Sethi 已提交
326 327 328
  "$sh_c" tar -C "$ARCHIVE_INSTALL_PREFIX/lib" -xzf "$CACHE_DIR/code-server-$VERSION-$OS-$ARCH.tar.gz"
  "$sh_c" mv -f "$ARCHIVE_INSTALL_PREFIX/lib/code-server-$VERSION-$OS-$ARCH" "$ARCHIVE_INSTALL_PREFIX/lib/code-server-$VERSION"
  "$sh_c" ln -fs "$ARCHIVE_INSTALL_PREFIX/lib/code-server-$VERSION/bin/code-server" "$ARCHIVE_INSTALL_PREFIX/bin/code-server"
A
Anmol Sethi 已提交
329 330 331 332 333 334

  echo_static_postinstall
}

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

387 388 389 390 391 392 393 394 395 396 397 398
  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 已提交
399 400 401 402 403 404 405 406 407 408 409
    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

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

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

460
echo_cache_dir() {
A
Anmol Sethi 已提交
461 462 463 464 465 466 467 468 469
  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
}

470 471 472 473 474 475 476 477
echo() {
  builtin echo "$@" | humanpath
}

cat() {
  humanpath
}

478 479 480 481
echoerr() {
  echo "$@" >&2
}

482 483 484 485 486
# humanpath replaces all occurances of $HOME with ~
humanpath() {
  sed "s#$HOME#~#g"
}

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