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

usage() {
5 6 7 8 9 10 11 12 13 14 15
  cli="$0"
  if [ "$0" = sh ]; then
    cli="curl -fsSL https://code-server.dev/install.sh | sh -s --"
  else
    curl_usage="$(
      cat << EOF

To use latest:

  curl -fsSL https://code-server.dev/install.sh | sh -s -- <args>
EOF
16 17
    )""
"
18
  fi
19
  cat << EOF
A
Anmol Sethi 已提交
20
Installs the latest code-server on Linux or macOS preferring to use the system package manager.
A
Anmol Sethi 已提交
21

22
Usage:
A
Anmol Sethi 已提交
23

24 25
  $cli [--dry-run] [--version X.X.X] [--static <install-prefix>=~/.local]
${curl_usage-}
26 27 28 29 30
- 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 已提交
31

32 33 34
- 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 已提交
35

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

39 40
    --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 已提交
41

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

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

46 47 48 49
              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 已提交
50

51
              To install system wide set the prefix to /usr/local.
A
Anmol Sethi 已提交
52
EOF
53 54 55
}

echo_latest_version() {
56 57 58
  # 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}"
59
  echo "$version"
A
Anmol Sethi 已提交
60 61 62 63
}

echo_static_postinstall() {
  echo
64 65
  cat << EOF
Static release has been installed into $STATIC_INSTALL_PREFIX/lib/code-server-$VERSION
A
Anmol Sethi 已提交
66
Please extend your path to use code-server:
67
  PATH="$STATIC_INSTALL_PREFIX/bin:\$PATH"
A
Anmol Sethi 已提交
68 69 70 71 72 73 74
Then you can run:
  code-server
EOF
}

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

  unset \
    DRY_RUN \
    STATIC \
    STATIC_INSTALL_PREFIX \
92
    SKIP_ECHO \
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
    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 已提交
128
    esac
129 130

    shift
A
Anmol Sethi 已提交
131
  done
132 133

  VERSION="${VERSION-$(echo_latest_version)}"
134
  STATIC_INSTALL_PREFIX="${STATIC_INSTALL_PREFIX-$HOME/.local}"
A
Anmol Sethi 已提交
135 136 137

  OS="$(os)"
  if [ ! "$OS" ]; then
138
    echoerr "Unsupported OS $(uname)."
A
Anmol Sethi 已提交
139 140 141 142 143 144 145 146
    exit 1
  fi

  distro_name

  ARCH="$(arch)"
  if [ ! "$ARCH" ]; then
    if [ "${STATIC-}" ]; then
147 148
      echoerr "No static releases available for the architecture $(uname -m)."
      echoerr "Please rerun without the -s flag to install from npm."
A
Anmol Sethi 已提交
149 150 151 152 153 154
      exit 1
    fi
    install_npm
    exit 0
  fi

155
  CACHE_DIR="$(echo_cache_dir)"
A
Anmol Sethi 已提交
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
  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
}

183 184 185 186 187
parse_arg() {
  case "$1" in
  *=*)
    opt="${1#=*}"
    optarg="${1#*=}"
188
    if [ ! "$optarg" ] && [ ! "${OPTIONAL-}" ]; then
189 190 191 192 193
      echoerr "$opt requires an argument"
      echoerr "Run with --help to see usage."
      exit 1
    fi
    echo "$optarg"
A
Anmol Sethi 已提交
194
    return
195 196
    ;;
  esac
A
Anmol Sethi 已提交
197

198
  case "${2-}" in
199
  "" | -*)
200 201 202 203 204 205 206 207 208 209 210
    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 已提交
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
}

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"
228
  SKIP_ECHO=1 sh_c mv "$FILE.incomplete" "$FILE"
A
Anmol Sethi 已提交
229 230
}

231 232 233 234 235 236 237 238 239 240 241 242 243 244
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 已提交
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
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
}

263
install_aur() {
A
Anmol Sethi 已提交
264 265 266 267 268 269 270
  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"
271
    SKIP_ECHO=1 sh_c tar -xzf "$CACHE_DIR/code-server-aur.tar.gz" --strip-components 1
A
Anmol Sethi 已提交
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
    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
288
    echoerr "Static release install prefix $STATIC_INSTALL_PREFIX does not exist"
A
Anmol Sethi 已提交
289 290 291 292 293 294 295
    exit 1
  fi

  sh_c="sh_c"
  if [ ! -w "$STATIC_INSTALL_PREFIX" ]; then
    sh_c="sudo_sh_c"
  fi
296
  SKIP_ECHO=1 sh_c mkdir -p "$STATIC_INSTALL_PREFIX/lib" "$STATIC_INSTALL_PREFIX/bin"
A
Anmol Sethi 已提交
297

298
  if [ -e "$STATIC_INSTALL_PREFIX/lib/code-server-$VERSION" ]; then
299 300 301 302 303 304 305
    echo
    echoerr "code-server-$VERSION is already installed at $STATIC_INSTALL_PREFIX/lib/code-server-$VERSION"
    echoerr "Please remove it to reinstall."
    exit 1
  fi
  "$sh_c" tar -C "$STATIC_INSTALL_PREFIX/lib" -xzf "$CACHE_DIR/code-server-$VERSION-$OS-$ARCH.tar.gz"
  "$sh_c" mv -f "$STATIC_INSTALL_PREFIX/lib/code-server-$VERSION-$OS-$ARCH" "$STATIC_INSTALL_PREFIX/lib/code-server-$VERSION"
A
Anmol Sethi 已提交
306 307 308 309 310

  echo_static_postinstall
}

install_npm() {
311
  echoerr "No precompiled releases for $(uname -m)."
A
Anmol Sethi 已提交
312 313 314 315 316 317 318 319 320
  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
321 322 323 324
  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 已提交
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
  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

355 356 357 358 359 360 361 362 363 364 365 366
  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 已提交
367 368 369 370 371 372 373 374 375 376 377
    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

378
  if [ -f /etc/os-release ]; then
A
Anmol Sethi 已提交
379 380 381 382
    (
      . /etc/os-release
      echo "$PRETTY_NAME"
    )
383
    return
A
Anmol Sethi 已提交
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
  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() {
402
  command -v "$@" > /dev/null 2>&1
A
Anmol Sethi 已提交
403 404 405
}

sh_c() {
406
  if [ ! "${SKIP_ECHO-}" ]; then
A
Anmol Sethi 已提交
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
    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
424 425 426
    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 已提交
427 428 429 430
    exit 1
  fi
}

431
echo_cache_dir() {
A
Anmol Sethi 已提交
432 433 434 435 436 437 438 439 440
  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
}

441 442 443 444
echoerr() {
  echo "$@" >&2
}

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