cdsr: initial import of deployed stack (runtime 4.133.0, pinned extensions, SSOT vault)
This commit is contained in:
75
scripts/install-extensions.sh
Executable file
75
scripts/install-extensions.sh
Executable file
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env bash
|
||||
# Install the pinned Open VSX extension baseline for the cdsr code-server deployment.
|
||||
# ./scripts/install-extensions.sh # baseline only
|
||||
# ./scripts/install-extensions.sh --include-optional # baseline + optional entries
|
||||
# Lock file is the single source of truth; no unpinned marketplace installs.
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
LOCK="$ROOT/config/extensions.lock.json"
|
||||
CACHE="$ROOT/tmp/extensions"
|
||||
CODE_SERVER="${CODE_SERVER_BIN:-/usr/bin/code-server}"
|
||||
CONFIG="$ROOT/config/config.yaml"
|
||||
|
||||
INCLUDE_OPTIONAL=0
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--include-optional) INCLUDE_OPTIONAL=1 ;;
|
||||
*) echo "unknown argument: $arg" >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
[[ -f "$LOCK" ]] || { echo "missing lock file: $LOCK" >&2; exit 1; }
|
||||
command -v python3 >/dev/null || { echo "python3 is required" >&2; exit 1; }
|
||||
mkdir -p "$CACHE"
|
||||
|
||||
# The selector must not run inside process substitution: its exit status would be lost and
|
||||
# a malformed lock file would be misreported as "no extensions selected". Write to a temp
|
||||
# file, check python's status, then read the file.
|
||||
SELECTION="$(mktemp "${TMPDIR:-/tmp}/cdsr-extension-selection.XXXXXX")"
|
||||
trap 'rm -f "$SELECTION"' EXIT
|
||||
|
||||
# one tab-separated record per selected extension: id ver platform vsix_url sha_url mode
|
||||
if ! INCLUDE_OPTIONAL="$INCLUDE_OPTIONAL" python3 - "$LOCK" >"$SELECTION" <<'PY'
|
||||
import json, os, sys
|
||||
lock = json.load(open(sys.argv[1]))
|
||||
want_optional = os.environ.get("INCLUDE_OPTIONAL") == "1"
|
||||
for e in lock["extensions"]:
|
||||
if e["mode"] == "baseline" or (want_optional and e["mode"] == "optional"):
|
||||
print("\t".join([e["id"], e["version"], e["platform"], e["vsix_url"], e["sha256_url"], e["mode"]]))
|
||||
PY
|
||||
then
|
||||
echo "could not read extension selection from $LOCK (see the python traceback above)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mapfile -t ENTRIES <"$SELECTION"
|
||||
(( ${#ENTRIES[@]} )) || { echo "no extensions selected from $LOCK" >&2; exit 1; }
|
||||
|
||||
for entry in "${ENTRIES[@]}"; do
|
||||
IFS=$'\t' read -r id version platform vsix_url sha_url mode <<<"$entry"
|
||||
|
||||
vsix="$CACHE/${id}-${version}@${platform}.vsix"
|
||||
echo "==> $id@$version ($platform, $mode)"
|
||||
|
||||
if [[ ! -s "$vsix" ]]; then
|
||||
curl -fsSL --retry 3 -o "$vsix.part" "$vsix_url"
|
||||
mv "$vsix.part" "$vsix"
|
||||
fi
|
||||
|
||||
expected=$(curl -fsSL --retry 3 "$sha_url" | tr -d '[:space:]')
|
||||
[[ -n "$expected" ]] || { echo "empty checksum for $id" >&2; exit 1; }
|
||||
actual=$(sha256sum "$vsix" | cut -d' ' -f1)
|
||||
if [[ "$expected" != "$actual" ]]; then
|
||||
echo "checksum mismatch for $id@$version" >&2
|
||||
echo " expected: $expected" >&2
|
||||
echo " actual: $actual" >&2
|
||||
rm -f "$vsix"
|
||||
exit 1
|
||||
fi
|
||||
echo " sha256 ok: $actual"
|
||||
|
||||
"$CODE_SERVER" --config "$CONFIG" --install-extension "$vsix" --force
|
||||
done
|
||||
|
||||
echo "done. audit with: $ROOT/scripts/list-extension-versions.sh"
|
||||
Reference in New Issue
Block a user