install.sh 10.5 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
    SKIP_ECHO \
99 100 101 102 103 104 105 106
    VERSION \
    OPTIONAL

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

    shift
A
Anmol Sethi 已提交
140
  done
141 142

  VERSION="${VERSION-$(echo_latest_version)}"
A
Anmol Sethi 已提交
143 144 145 146 147 148 149
  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 已提交
150 151 152

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

  distro_name

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

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

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

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

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

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

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

A
Anmol Sethi 已提交
233 234
  echo "+ Downloading $URL"

A
Anmol Sethi 已提交
235
  if [ -e "$FILE" ]; then
A
Anmol Sethi 已提交
236
    echo "+ Using cached $FILE"
A
Anmol Sethi 已提交
237 238 239
    return
  fi

A
Anmol Sethi 已提交
240
  SKIP_ECHO=1
A
Anmol Sethi 已提交
241 242
  sh_c curl \
    -#fL \
A
Anmol Sethi 已提交
243
    -o "$FILE.incomplete" \
A
Anmol Sethi 已提交
244 245
    -C - \
    "$URL"
A
Anmol Sethi 已提交
246 247 248 249
  sh_c mv "$FILE.incomplete" "$FILE"
  unset SKIP_ECHO

  echo "+ Downloaded into $FILE"
A
Anmol Sethi 已提交
250 251
}

252 253 254
install_macos() {
  if command_exists brew; then
    echo "Installing from Homebrew."
A
Anmol Sethi 已提交
255
    echo
256 257 258 259 260 261

    sh_c brew install code-server

    return
  fi

A
Anmol Sethi 已提交
262
  echo "Homebrew not installed."
263

A
Anmol Sethi 已提交
264
  install_archive
265 266
}

A
Anmol Sethi 已提交
267 268
install_deb() {
  echo "Installing v$VERSION deb package from GitHub releases."
A
Anmol Sethi 已提交
269
  echo
A
Anmol Sethi 已提交
270

A
Anmol Sethi 已提交
271 272
  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 已提交
273 274 275 276 277 278 279
  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 已提交
280
  echo
A
Anmol Sethi 已提交
281

A
Anmol Sethi 已提交
282 283
  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 已提交
284 285 286 287 288
  sudo_sh_c rpm -i "$CACHE_DIR/code-server-$VERSION-$ARCH.rpm"

  echo_systemd_postinstall
}

289
install_aur() {
A
Anmol Sethi 已提交
290
  echo "Installing from the AUR."
A
Anmol Sethi 已提交
291
  echo
A
Anmol Sethi 已提交
292

A
Anmol Sethi 已提交
293
  prev_dir="$PWD"
A
Anmol Sethi 已提交
294
  tmp_dir="$(mktemp -d)"
A
Anmol Sethi 已提交
295 296 297 298 299 300 301 302 303
  cd "$tmp_dir"

  echo "+ Downloading PKGBUILD from https://aur.archlinux.org/cgit/aur.git/snapshot/code-server.tar.gz"
  SKIP_ECHO=1 sh_c 'curl -fsSL https://aur.archlinux.org/cgit/aur.git/snapshot/code-server.tar.gz | tar -xz --strip-components 1'
  unset SKIP_ECHO
  echo "+ Downloaded into $tmp_dir"
  sh_c makepkg -si

  cd "$prev_dir"
A
Anmol Sethi 已提交
304 305 306 307 308
  rm -Rf "$tmp_dir"

  echo_systemd_postinstall
}

A
Anmol Sethi 已提交
309
install_archive() {
A
Anmol Sethi 已提交
310
  echo "Installing static release v$VERSION"
A
Anmol Sethi 已提交
311
  echo
A
Anmol Sethi 已提交
312

A
Anmol Sethi 已提交
313 314
  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 已提交
315 316

  sh_c="sh_c"
A
Anmol Sethi 已提交
317
  if [ ! -w "$ARCHIVE_INSTALL_PREFIX" ]; then
A
Anmol Sethi 已提交
318 319 320
    sh_c="sudo_sh_c"
  fi

A
Anmol Sethi 已提交
321 322 323 324
  SKIP_ECHO=1 sh_c mkdir -p "$ARCHIVE_INSTALL_PREFIX/lib" "$ARCHIVE_INSTALL_PREFIX/bin"
  unset SKIP_ECHO

  if [ -e "$ARCHIVE_INSTALL_PREFIX/lib/code-server-$VERSION" ]; then
325
    echo
A
Anmol Sethi 已提交
326 327 328
    echo "code-server-$VERSION is already installed at $ARCHIVE_INSTALL_PREFIX/lib/code-server-$VERSION"
    echo "Remove it to reinstall."
    exit 0
329
  fi
A
Anmol Sethi 已提交
330 331 332
  "$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 已提交
333 334 335 336 337 338 339

  echo_static_postinstall
}

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

383 384 385 386 387 388 389 390 391 392 393 394
  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 已提交
395 396 397 398 399 400 401 402 403 404 405
    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

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

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

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

468 469 470 471
echoerr() {
  echo "$@" >&2
}

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