Skip to content

一键更新小脚本 #168

@PoloWitty

Description

@PoloWitty

感谢大佬的开源,不过由于本项目暂时不支持自动更新,vscode提示更新后还需到Release页手动检查一下是否存在更新后的server版本,在vscode更新比较快的情况下有点麻烦,所以vibe了下面这个脚本,方便看到vscode提示可以更新后用脚本自动检查server版是否也已更新,并自动下载和安装。
(脚本写的是默认下载x64版本安装包,如果需要不同版本的话可以手动修改一下,下载位置默认是执行此脚本时的PWD)

使用方法:直接使用bash运行此脚本即可,会检查release页的最新版本并让用户选择是否更新。

#!/usr/bin/env bash
set -euo pipefail

REPO="${REPO:-MikeWang000000/vscode-server-centos7}"
INSTALL_DIR="${INSTALL_DIR:-$HOME/.vscode-server}"
DOWNLOAD_DIR="${DOWNLOAD_DIR:-$PWD}"
API_URL="https://api.github.com/repos/${REPO}/releases/latest"
LATEST_URL="https://github.com/${REPO}/releases/latest"
TMP_JSON=""
TMP_TAR=""

usage() {
  cat <<'USAGE'
Usage: ./vscode-server-update.sh

Environment variables:
  REPO         GitHub repo, default: MikeWang000000/vscode-server-centos7
  INSTALL_DIR VS Code Server install dir, default: ~/.vscode-server
  DOWNLOAD_DIR Tarball download dir, default: current directory
USAGE
}

need_cmd() {
  if ! command -v "$1" >/dev/null 2>&1; then
    echo "Error: required command not found: $1" >&2
    exit 1
  fi
}

cleanup() {
  if [[ -n "${TMP_JSON:-}" ]]; then
    rm -f "$TMP_JSON"
  fi

  if [[ -n "${TMP_TAR:-}" ]]; then
    rm -f "$TMP_TAR"
  fi
}

parse_release_with_python() {
  python3 - "$1" <<'PY'
import json
import re
import sys

path = sys.argv[1]
with open(path, "r", encoding="utf-8") as f:
    release = json.load(f)

assets = release.get("assets", [])
pattern = re.compile(r"^vscode-server_.+_x64\.tar\.gz$")
asset = next((item for item in assets if pattern.match(item.get("name", ""))), None)
if asset is None:
    raise SystemExit("no vscode-server_*_x64.tar.gz asset found in latest release")

tag = release.get("tag_name") or ""
version = tag[1:] if tag.startswith("v") else tag
if not version:
    name = asset["name"]
    match = re.match(r"^vscode-server_(.+)_x64\.tar\.gz$", name)
    version = match.group(1) if match else "unknown"

print(version)
print(asset["name"])
print(asset["browser_download_url"])
PY
}

parse_release_with_sed() {
  local json_file="$1"
  local flat_file version asset_name asset_url

  flat_file="$(mktemp)"
  sed 's/[{},]/\
/g' "$json_file" > "$flat_file"

  version="$(sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"v\{0,1\}\([^"]*\)".*/\1/p' "$flat_file" | head -n 1)"
  asset_name="$(sed -n 's/.*"name"[[:space:]]*:[[:space:]]*"\(vscode-server_[^"]*_x64\.tar\.gz\)".*/\1/p' "$flat_file" | head -n 1)"
  asset_url="$(sed -n 's#.*"browser_download_url"[[:space:]]*:[[:space:]]*"\([^"]*vscode-server_[^"]*_x64\.tar\.gz\)".*#\1#p' "$flat_file" | head -n 1)"
  rm -f "$flat_file"

  if [[ -z "${version}" && -n "${asset_name}" ]]; then
    version="${asset_name#vscode-server_}"
    version="${version%_x64.tar.gz}"
  fi

  if [[ -z "${version}" || -z "${asset_name}" || -z "${asset_url}" ]]; then
    echo "Error: failed to parse latest release metadata from ${API_URL}" >&2
    exit 1
  fi

  printf '%s\n%s\n%s\n' "$version" "$asset_name" "$asset_url"
}

release_from_latest_redirect() {
  local effective_url tag version asset_name asset_url

  if ! effective_url="$(curl -fsSLI -o /dev/null -w '%{url_effective}' -H 'User-Agent: vscode-server-update.sh' "$LATEST_URL")"; then
    echo "Error: failed to access ${LATEST_URL}" >&2
    exit 1
  fi

  tag="${effective_url##*/}"
  version="${tag#v}"

  if [[ -z "$version" || "$version" == "$effective_url" || "$tag" == "latest" || "$effective_url" != */releases/tag/v* ]]; then
    echo "Error: failed to detect latest release tag from ${LATEST_URL}" >&2
    exit 1
  fi

  asset_name="vscode-server_${version}_x64.tar.gz"
  asset_url="https://github.com/${REPO}/releases/download/v${version}/${asset_name}"

  printf '%s\n%s\n%s\n' "$version" "$asset_name" "$asset_url"
}

fetch_latest_info() {
  local tmp_json="$1"

  if curl -fsSL -H 'Accept: application/vnd.github+json' -H 'User-Agent: vscode-server-update.sh' "$API_URL" -o "$tmp_json"; then
    if command -v python3 >/dev/null 2>&1; then
      parse_release_with_python "$tmp_json"
    else
      parse_release_with_sed "$tmp_json"
    fi
    return
  fi

  echo "GitHub API unavailable; falling back to ${LATEST_URL}" >&2
  release_from_latest_redirect
}

confirm_update() {
  local version="$1"
  local answer

  printf 'Update to VS Code Server %s? [Y/N] ' "$version"
  read -r answer

  case "$answer" in
    Y|y|YES|Yes|yes)
      return 0
      ;;
    *)
      return 1
      ;;
  esac
}

main() {
  if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
    usage
    exit 0
  fi

  need_cmd curl
  need_cmd tar
  need_cmd sed
  need_cmd head

  local latest_info latest_version asset_name asset_url tarball current_version
  TMP_JSON="$(mktemp)"
  TMP_TAR=""
  trap cleanup EXIT

  echo "Fetching latest release metadata from ${API_URL}"
  latest_info="$(fetch_latest_info "$TMP_JSON")"

  latest_version="$(printf '%s\n' "$latest_info" | sed -n '1p')"
  asset_name="$(printf '%s\n' "$latest_info" | sed -n '2p')"
  asset_url="$(printf '%s\n' "$latest_info" | sed -n '3p')"
  tarball="${DOWNLOAD_DIR%/}/${asset_name}"

  echo "Latest version : ${latest_version}"
  echo "Package        : ${asset_name}"
  echo "Download URL   : ${asset_url}"
  echo "Install dir    : ${INSTALL_DIR}"
  echo "Download dir   : ${DOWNLOAD_DIR}"

  if [[ -x "${INSTALL_DIR}/code-latest" ]]; then
    current_version="$("${INSTALL_DIR}/code-latest" --version 2>/dev/null | head -n 1 || true)"
    if [[ -n "$current_version" ]]; then
      echo "Current version: ${current_version}"
    fi
  fi

  if ! confirm_update "$latest_version"; then
    echo "Canceled."
    exit 0
  fi

  mkdir -p "$DOWNLOAD_DIR" "$INSTALL_DIR"

  TMP_TAR="${tarball}.part.$$"
  echo "Downloading ${asset_name}"
  curl -fL --retry 3 --retry-delay 2 -o "$TMP_TAR" "$asset_url"
  mv -f "$TMP_TAR" "$tarball"
  TMP_TAR=""

  echo "Extracting to ${INSTALL_DIR}"
  tar xzf "$tarball" -C "$INSTALL_DIR" --strip-components 1

  if [[ ! -x "${INSTALL_DIR}/code-latest" ]]; then
    echo "Error: ${INSTALL_DIR}/code-latest is missing or not executable after extraction" >&2
    exit 1
  fi

  echo "Patching VS Code Server"
  "${INSTALL_DIR}/code-latest" --patch-now

  echo "Update completed: ${latest_version}"
}

if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
  main "$@"
fi

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions