Skip to content

一键更新小脚本 #168

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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