Files
vs-code-setup/scripts/install.sh
T
maxandClaude Fable 5.1 c058c09050 Bash install.sh and settings.sh for Linux and macOS
Twins of the PowerShell scripts, needing only bash, curl and one of jq,
node or python3 for JSON. install.sh downloads a release (or installs
from dist/), settings.sh pushes, pulls or diffs User/, both resolve the
code CLI and user folder per platform.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0169iPWwKHZoBTNN9qwXiwqk
2026-09-08 19:50:07 +02:00

110 lines
3.8 KiB
Bash

#!/usr/bin/env bash
# Installs the extensions into VS Code, from a Gitea release or from dist/.
#
# The bash twin of install.ps1, for a Linux or macOS machine without PowerShell. By
# default it downloads the .vsix assets of the "latest" release and installs them, so a
# fresh machine needs nothing but VS Code, curl, and this repo. --local installs what is
# already in dist/ instead.
#
# Every install passes --force: without it VS Code declines to reinstall a version it
# already has, which would silently do nothing every time the same version number is
# republished.
#
# Usage:
# scripts/install.sh install the "latest" release
# scripts/install.sh --tag v0.1.0 a specific release
# scripts/install.sh --local from dist/
# scripts/install.sh --only vertical-tabs --only colored-references
# scripts/install.sh --uninstall
# scripts/install.sh --token <token> otherwise GITEA_TOKEN or ~/.gitea-token
# shellcheck source=common.sh
. "$(dirname "${BASH_SOURCE[0]}")/common.sh"
tag=latest
token=""
only=""
local_install=""
uninstall=""
while [ $# -gt 0 ]; do
case "$1" in
--tag) tag="$2"; shift 2 ;;
--token) token="$2"; shift 2 ;;
--only) only="$only $2"; shift 2 ;;
--local) local_install=1; shift ;;
--uninstall) uninstall=1; shift ;;
-h|--help) sed -n '2,20p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
*) die "unknown argument: $1 (try --help)" ;;
esac
done
load_config
code="$(code_command)"
extensions="$(configured_extensions "$only")"
if [ -n "$uninstall" ]; then
while IFS=$'\t' read -r id _path _repo; do
[ -n "$id" ] || continue
# The manifest's publisher is "local", so the installed id is local.<name>.
note "uninstalling local.$id"
"$code" --uninstall-extension "local.$id" || true
done <<<"$extensions"
echo "Reload the window for this to take effect."
exit 0
fi
packages=()
staging=""
if [ -n "$local_install" ]; then
while IFS=$'\t' read -r id _path _repo; do
[ -n "$id" ] || continue
found="$(ls -1 "$setup_dist"/"$id"-*.vsix 2>/dev/null | sort -r | head -n1 || true)"
[ -n "$found" ] || die "no package for $id in $setup_dist. Run build.ps1 or ci-release.sh first."
packages+=("$found")
done <<<"$extensions"
else
require_gitea
token="$(gitea_token "$token")"
release="$(gitea_release "$tag" "$token")"
[ -n "$release" ] || die "no release tagged '$tag' in $gitea_owner/$gitea_repo. Run publish.ps1 first."
assets="$(json_rows - assets name browser_download_url <<<"$release")"
[ -n "$assets" ] || die "release '$tag' has no assets"
# Downloads go to a temp folder, not dist/, so an install never disturbs a build.
staging="$(mktemp -d -t vsix-XXXXXX)"
trap 'rm -rf "$staging"' EXIT
while IFS=$'\t' read -r id _path _repo; do
[ -n "$id" ] || continue
match="$(grep -P "^$id-.*\.vsix\t" <<<"$assets" | sort -r | head -n1 || true)"
if [ -z "$match" ]; then
warn "release '$tag' has no asset for $id, skipping"
continue
fi
name="${match%%$'\t'*}"
url="${match#*$'\t'}"
note "downloading $name"
gitea_download "$url" "$staging/$name" "$token"
packages+=("$staging/$name")
done <<<"$extensions"
fi
[ ${#packages[@]} -gt 0 ] || die "nothing to install"
failed=0
for package in "${packages[@]}"; do
printf 'installing %s' "$(basename "$package")"
if "$code" --install-extension "$package" --force >/dev/null 2>&1; then
ok ' ok'
else
printf '\033[31m FAILED\033[0m\n'
failed=$((failed + 1))
fi
done
echo
[ "$failed" -eq 0 ] || die "$failed of ${#packages[@]} failed to install"
echo "installed ${#packages[@]} extension(s). Reload the window."