mirror of
https://github.com/jimeh/.vscode.d.git
synced 2026-02-19 11:26:39 +00:00
chore(siren): various refactoring and improvements
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
# cursor Extensions
|
||||
# Generated on Fri Jul 25 10:15:07 BST 2025
|
||||
# Generated on Sat Jul 26 16:05:14 BST 2025
|
||||
|
||||
alefragnani.project-manager@12.8.0
|
||||
anthropic.claude-code@1.0.60
|
||||
anthropic.claude-code@1.0.61
|
||||
antiantisepticeye.vscode-color-picker@0.0.4
|
||||
antyos.openscad@1.3.2
|
||||
anysphere.cursorpyright@1.0.7
|
||||
arrterian.nix-env-selector@1.1.0
|
||||
arturodent.command-alias@0.6.2
|
||||
bibhasdn.unique-lines@1.0.0
|
||||
@@ -24,25 +25,25 @@ connor4312.esbuild-problem-matchers@0.0.3
|
||||
connorshea.vscode-ruby-test-adapter@0.9.2
|
||||
ctf0.macros@1.1.1
|
||||
davidanson.vscode-markdownlint@0.60.0
|
||||
dbaeumer.vscode-eslint@3.0.10
|
||||
dbaeumer.vscode-eslint@3.0.15
|
||||
dewski.simplecov@0.0.7
|
||||
dnut.rewrap-revived@1.16.3
|
||||
dnut.rewrap-revived@17.9.0
|
||||
editorconfig.editorconfig@0.17.4
|
||||
elijah-potter.harper@0.52.0
|
||||
emeraldwalk.runonsave@0.2.7
|
||||
elijah-potter.harper@0.53.0
|
||||
emeraldwalk.runonsave@0.3.2
|
||||
esbenp.prettier-vscode@11.0.0
|
||||
exiasr.hadolint@1.1.2
|
||||
fogio.inline-go-struct-tags-syntax-highlight@1.0.0
|
||||
github.remotehub@0.64.0
|
||||
github.remotehub@0.65.2025063001
|
||||
github.vscode-github-actions@0.27.2
|
||||
github.vscode-pull-request-github@0.108.0
|
||||
gofenix.go-lines@0.0.10
|
||||
golang.go@0.48.0
|
||||
golang.go@0.49.0
|
||||
gruntfuggly.todo-tree@0.0.226
|
||||
hashicorp.terraform@2.34.5
|
||||
hashicorp.terraform@2.34.2025012311
|
||||
hbenl.vscode-test-explorer@2.22.1
|
||||
hoovercj.vscode-settings-cycler@1.0.1
|
||||
humao.rest-client@0.26.0
|
||||
humao.rest-client@0.25.1
|
||||
hverlin.mise-vscode@0.52.0
|
||||
jakearl.search-editor-apply-changes@0.1.1
|
||||
jnoortheen.nix-ide@0.4.22
|
||||
@@ -51,53 +52,54 @@ kahole.magit@0.6.67
|
||||
karunamurti.haml@1.4.1
|
||||
koichisasada.vscode-rdbg@0.2.2
|
||||
letrieu.expand-region@0.1.4
|
||||
lroolle.doom-themes@1.2.1
|
||||
m4ns0ur.base64@1.0.0
|
||||
mads-hartmann.bash-ide-vscode@1.43.0
|
||||
matthewpi.caddyfile-support@0.4.0
|
||||
mattn.lisp@0.1.12
|
||||
mermaidchart.vscode-mermaid-chart@2.4.1
|
||||
mermaidchart.vscode-mermaid-chart@2.5.0
|
||||
mhutchie.git-graph@1.30.0
|
||||
mkhl.direnv@0.17.0
|
||||
mrmlnc.vscode-duplicate@1.2.1
|
||||
ms-azuretools.vscode-containers@2.1.0
|
||||
ms-kubernetes-tools.vscode-kubernetes-tools@1.3.25
|
||||
ms-python.debugpy@2025.8.0
|
||||
ms-python.debugpy@2025.11.2025072201
|
||||
ms-python.python@2025.6.1
|
||||
ms-python.vscode-pylance@2024.8.1
|
||||
ms-vscode-remote.remote-containers@0.394.0
|
||||
ms-vscode-remote.remote-ssh@0.113.1
|
||||
ms-vscode-remote.remote-containers@0.424.0
|
||||
ms-vscode-remote.remote-ssh@0.121.2025071515
|
||||
ms-vscode-remote.remote-ssh-edit@0.87.0
|
||||
ms-vscode.extension-test-runner@0.0.12
|
||||
ms-vscode.hexeditor@1.11.1
|
||||
ms-vscode.remote-explorer@0.5.0
|
||||
ms-vscode.remote-repositories@0.42.0
|
||||
ms-vscode.remote-server@1.5.2
|
||||
ms-vscode.remote-explorer@0.6.2025072209
|
||||
ms-vscode.remote-repositories@0.43.2025063001
|
||||
ms-vscode.remote-server@1.6.2025072309
|
||||
ms-vscode.test-adapter-converter@0.2.1
|
||||
ms-vscode.vscode-speech@0.14.0
|
||||
ms-vscode.vscode-speech@0.16.0
|
||||
ms-vsliveshare.vsliveshare@1.0.5948
|
||||
pflannery.vscode-versionlens@1.22.2
|
||||
pkief.material-icon-theme@5.24.0
|
||||
redhat.vscode-xml@0.29.0
|
||||
redhat.vscode-xml@0.29.2025051008
|
||||
redhat.vscode-yaml@1.18.0
|
||||
romanpeshkov.vscode-text-tables@0.1.5
|
||||
rrudi.vscode-dired@0.0.9
|
||||
rust-lang.rust-analyzer@0.3.2547
|
||||
rust-lang.rust-analyzer@0.4.2552
|
||||
shopify.ruby-extensions-pack@0.1.13
|
||||
shopify.ruby-lsp@0.9.31
|
||||
sidneys1.gitconfig@2.0.1
|
||||
sorbet.sorbet-vscode-extension@0.3.44
|
||||
streetsidesoftware.code-spell-checker@4.0.47
|
||||
streetsidesoftware.code-spell-checker@4.2.3
|
||||
stuart.unique-window-colors@1.0.51
|
||||
sumneko.lua@3.15.0
|
||||
svelte.svelte-vscode@109.10.0
|
||||
swellaby.vscode-rust-test-adapter@0.11.1
|
||||
swellaby.vscode-rust-test-adapter@0.11.0
|
||||
swellaby.workspace-config-plus@0.2.5
|
||||
tamasfe.even-better-toml@0.21.2
|
||||
tootone.org-mode@0.5.0
|
||||
tuttieee.emacs-mcx@0.75.0
|
||||
tuttieee.emacs-mcx@0.78.0
|
||||
tyriar.sort-lines@1.12.0
|
||||
viktorzetterstrom.non-breaking-space-highlighter@0.0.3
|
||||
wenhoujx.swiper@2.1.2
|
||||
zhuangtongfa.material-theme@3.19.0
|
||||
ziyasal.vscode-open-in-github@1.4.1
|
||||
ziyasal.vscode-open-in-github@1.3.6
|
||||
zxh404.vscode-proto3@0.5.5
|
||||
|
||||
590
siren
590
siren
@@ -1,4 +1,4 @@
|
||||
#! /usr/bin/env bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# ==============================================================================
|
||||
# Settings
|
||||
@@ -34,6 +34,8 @@ define_settings() {
|
||||
}
|
||||
|
||||
# Get extensions lockfile path for current editor.
|
||||
#
|
||||
# Returns: Path to extensions lock file via `STDOUT`.
|
||||
get_extensions_lock() {
|
||||
echo "${SCRIPT_DIR}/extensions.${SETUP_EDITOR}.lock"
|
||||
}
|
||||
@@ -58,6 +60,8 @@ Commands:
|
||||
config, conf Create symlinks for editor config files
|
||||
dump-extensions, dump Export installed editor extensions to a lock file.
|
||||
extensions, ext Install editor extensions from a lock file.
|
||||
install Install a specific extension by identifier (e.g., ms-python.python).
|
||||
If no version is specified, installs the latest version.
|
||||
|
||||
Options:
|
||||
--latest When used with the extensions command, installs the
|
||||
@@ -80,6 +84,8 @@ EOF
|
||||
# ==============================================================================
|
||||
|
||||
# Determine editor config directory.
|
||||
#
|
||||
# Returns: Editor config directory path via `STDOUT`.
|
||||
editor_config_dir() {
|
||||
case "$(uname -s)" in
|
||||
"Darwin")
|
||||
@@ -136,6 +142,8 @@ editor_config_dir() {
|
||||
}
|
||||
|
||||
# Determine harper-ls config directory.
|
||||
#
|
||||
# Returns: Harper-ls config directory path via `STDOUT`.
|
||||
harper_config_dir() {
|
||||
case "$(uname -s)" in
|
||||
"Darwin")
|
||||
@@ -156,6 +164,8 @@ harper_config_dir() {
|
||||
}
|
||||
|
||||
# Cross-platform function to resolve symlinks.
|
||||
#
|
||||
# Returns: Resolved symlink path via `STDOUT`.
|
||||
resolve_symlink() {
|
||||
local path="$1"
|
||||
if command -v realpath > /dev/null 2>&1; then
|
||||
@@ -236,6 +246,8 @@ do_config() {
|
||||
}
|
||||
|
||||
# Find the editor CLI command.
|
||||
#
|
||||
# Returns: Editor command path via `STDOUT`.
|
||||
find_editor_cmd() {
|
||||
local editor_cmd=""
|
||||
local possible_commands=()
|
||||
@@ -316,7 +328,7 @@ do_dump_extensions() {
|
||||
echo "# ${SETUP_EDITOR} Extensions"
|
||||
echo "# Generated on ${current_date}"
|
||||
echo
|
||||
"${editor_cmd}" --list-extensions --show-versions
|
||||
"${editor_cmd}" --list-extensions --show-versions 2> /dev/null
|
||||
} > "${extensions_lock}"
|
||||
|
||||
echo "Extensions list dumped to ${extensions_lock}"
|
||||
@@ -372,26 +384,105 @@ validate_extension_line() {
|
||||
_INSTALLED_EXTENSIONS=""
|
||||
|
||||
# Get installed extensions with versions, using cache if available.
|
||||
#
|
||||
# Returns: List of installed extensions with versions via `STDOUT`.
|
||||
installed_extensions() {
|
||||
local editor_cmd="$1"
|
||||
|
||||
# Populate the cache if it's not already populated.
|
||||
if [[ -z "${_INSTALLED_EXTENSIONS}" ]]; then
|
||||
_INSTALLED_EXTENSIONS="$("${editor_cmd}" --list-extensions --show-versions)"
|
||||
_INSTALLED_EXTENSIONS="$(
|
||||
"${editor_cmd}" --list-extensions --show-versions 2> /dev/null
|
||||
)"
|
||||
fi
|
||||
|
||||
echo "${_INSTALLED_EXTENSIONS}"
|
||||
}
|
||||
|
||||
# Get the currently installed version of an extension.
|
||||
#
|
||||
# Returns: Version string of installed extension via `STDOUT` (empty if not installed).
|
||||
get_installed_version() {
|
||||
local editor_cmd="$1"
|
||||
local extension="$2"
|
||||
local extension_pattern
|
||||
extension_pattern="$(printf '%s' "${extension}" | sed 's/[[\.*^()$+?{|]/\\&/g')"
|
||||
|
||||
# Extract version from cached list.
|
||||
installed_extensions "${editor_cmd}" |
|
||||
grep "^$(printf '%s' "${extension}" | sed "s/[[\.*^$()+?{|]/\\\\&/g")@" |
|
||||
sed "s/^[^@]*@//"
|
||||
grep "^${extension_pattern}@" |
|
||||
sed 's/^[^@]*@//'
|
||||
}
|
||||
|
||||
# Query latest version of an extension.
|
||||
#
|
||||
# Returns: Latest version string via `STDOUT` on success.
|
||||
query_latest_version() {
|
||||
local extension="$1"
|
||||
|
||||
if query_marketplace_latest_version "${extension}"; then
|
||||
return 0
|
||||
elif query_openvsx_latest_version "${extension}"; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Query latest version from OpenVSX registry.
|
||||
#
|
||||
# Returns: Latest version string via `STDOUT` on success.
|
||||
query_openvsx_latest_version() {
|
||||
local extension="$1"
|
||||
local publisher_id="${extension%%.*}"
|
||||
local extension_id="${extension#*.}"
|
||||
local openvsx_api_url="https://open-vsx.org/api/${publisher_id}/${extension_id}"
|
||||
|
||||
# Check for jq availability
|
||||
if ! command -v jq > /dev/null 2>&1; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Query OpenVSX API and extract latest version
|
||||
if curl --silent --compressed "${openvsx_api_url}" 2> /dev/null |
|
||||
jq -r '.version // empty' 2> /dev/null; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Query latest version from VS Marketplace.
|
||||
#
|
||||
# Returns: Latest version string via `STDOUT` on success.
|
||||
query_marketplace_latest_version() {
|
||||
local extension="$1"
|
||||
local metadata_url="https://marketplace.visualstudio.com/_apis/public/gallery/extensionquery"
|
||||
|
||||
# Check for jq availability
|
||||
if ! command -v jq > /dev/null 2>&1; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Use jq to properly construct JSON
|
||||
local request_data
|
||||
request_data=$(jq -n --arg ext "$extension" '{
|
||||
filters: [{
|
||||
criteria: [{ filterType: 7, value: $ext }]
|
||||
}],
|
||||
flags: 2
|
||||
}')
|
||||
|
||||
# Query the marketplace and extract latest version
|
||||
if curl --silent --compressed -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json; api-version=7.2-preview.1" \
|
||||
-d "${request_data}" "${metadata_url}" 2> /dev/null |
|
||||
jq -r '.results[0].extensions[0].versions[0].version // empty' 2> /dev/null; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Install an extension directly using the marketplace.
|
||||
@@ -399,14 +490,13 @@ install_extension_direct() {
|
||||
local editor_cmd="$1"
|
||||
local extension="$2"
|
||||
local version="$3"
|
||||
local use_latest="$4"
|
||||
local force_install="$5"
|
||||
local force_install="$4"
|
||||
local result=0
|
||||
|
||||
if [[ "${use_latest}" == "true" ]]; then
|
||||
echo "Installing ${extension} (latest version)"
|
||||
if ! "${editor_cmd}" --install-extension "${extension}" --force; then
|
||||
echo "Warning: Direct install failed for ${extension}"
|
||||
if [[ "${version}" == "latest" ]]; then
|
||||
echo "Installing ${extension} (latest version)" >&2
|
||||
if ! "${editor_cmd}" --install-extension "${extension}" --force 2> /dev/null; then
|
||||
echo "Warning: Direct install failed for ${extension}" >&2
|
||||
result=1
|
||||
fi
|
||||
else
|
||||
@@ -415,8 +505,8 @@ install_extension_direct() {
|
||||
if [[ "${force_install}" == "true" ]]; then
|
||||
install_cmd+=(--force)
|
||||
fi
|
||||
if ! "${install_cmd[@]}"; then
|
||||
echo "Warning: Direct install failed for ${extension}@${version}"
|
||||
if ! "${install_cmd[@]}" 2> /dev/null; then
|
||||
echo "Warning: Direct install failed for ${extension}@${version}" >&2
|
||||
result=1
|
||||
fi
|
||||
fi
|
||||
@@ -424,43 +514,89 @@ install_extension_direct() {
|
||||
return ${result}
|
||||
}
|
||||
|
||||
# Install an extension via downloading `*.vsix` file.
|
||||
install_extension_via_vsix() {
|
||||
local editor_cmd="$1"
|
||||
local extension="$2"
|
||||
local version="$3"
|
||||
local use_latest="$4"
|
||||
local extensions_cache_dir="$5"
|
||||
local result=0
|
||||
|
||||
# Download extension from OpenVSX registry.
|
||||
#
|
||||
# Returns: Path to downloaded `.vsix` file via `STDOUT` on success.
|
||||
download_from_openvsx() {
|
||||
local extension="$1"
|
||||
local version="$2"
|
||||
local extensions_cache_dir="$3"
|
||||
local publisher_id="${extension%%.*}"
|
||||
local extension_id="${extension#*.}"
|
||||
local install_version="${version}"
|
||||
local vsix_path=""
|
||||
local vsix_url=""
|
||||
local install_version=""
|
||||
|
||||
if [[ "${use_latest}" == "true" ]]; then
|
||||
# Check for `jq` availability when using `--latest` flag.
|
||||
# If version is "latest", query OpenVSX API for latest version
|
||||
if [[ "${version}" == "latest" ]]; then
|
||||
echo "Querying OpenVSX for latest version of ${extension}..." >&2
|
||||
if install_version=$(query_openvsx_latest_version "${extension}"); then
|
||||
if [[ -z "${install_version}" ]]; then
|
||||
echo "Error: Could not determine latest version from OpenVSX for ${extension}" >&2
|
||||
return 1
|
||||
fi
|
||||
echo "Latest version of ${extension} from OpenVSX is ${install_version}" >&2
|
||||
else
|
||||
echo "Error: Failed to query OpenVSX API for ${extension}" >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Set up download path and URL
|
||||
vsix_path="${extensions_cache_dir}/${extension}@${install_version}.vsix"
|
||||
local openvsx_url="https://open-vsx.org/api/${publisher_id}/${extension_id}/${install_version}/file/${publisher_id}.${extension_id}-${install_version}.vsix"
|
||||
|
||||
echo "Downloading ${extension}@${install_version} from OpenVSX..." >&2
|
||||
echo " - OpenVSX URL: ${openvsx_url}" >&2
|
||||
|
||||
# Create extensions directory if it doesn't exist
|
||||
mkdir -p "${extensions_cache_dir}"
|
||||
|
||||
if curl --compressed -L -o "${vsix_path}" "${openvsx_url}" 2> /dev/null; then
|
||||
# Verify the download was successful by checking file size
|
||||
if [[ -s "${vsix_path}" ]]; then
|
||||
echo "Successfully downloaded from OpenVSX" >&2
|
||||
echo "${vsix_path}"
|
||||
return 0
|
||||
else
|
||||
echo "OpenVSX download failed (empty file)" >&2
|
||||
rm -f "${vsix_path}"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
echo "OpenVSX download failed" >&2
|
||||
rm -f "${vsix_path}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Download extension from VS Marketplace.
|
||||
#
|
||||
# Returns: Path to downloaded `.vsix` file via `STDOUT` on success.
|
||||
download_from_marketplace() {
|
||||
local extension="$1"
|
||||
local version="$2"
|
||||
local extensions_cache_dir="$3"
|
||||
local publisher_id="${extension%%.*}"
|
||||
local extension_id="${extension#*.}"
|
||||
local install_version="${version}"
|
||||
local vsix_path=""
|
||||
|
||||
# If version is "latest", query VS Marketplace API for latest version
|
||||
if [[ "${version}" == "latest" ]]; then
|
||||
echo "Querying VS Marketplace for latest version of ${extension}..." >&2
|
||||
local metadata_url="https://marketplace.visualstudio.com/_apis/public/gallery/extensionquery"
|
||||
local temp_metadata="${extensions_cache_dir}/marketplace-${extension}.json"
|
||||
|
||||
# Create extensions directory if it doesn't exist
|
||||
mkdir -p "${extensions_cache_dir}"
|
||||
|
||||
# Check for jq availability
|
||||
if ! command -v jq > /dev/null 2>&1; then
|
||||
echo "Error: jq is required when using --latest flag to parse" \
|
||||
"marketplace API responses."
|
||||
echo "Please install jq or remove the --latest flag to use exact" \
|
||||
"versions from the lock file."
|
||||
echo "Error: jq is required to parse VS Marketplace API response for latest version" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# In latest mode, we need to first query the marketplace to get the latest
|
||||
# version.
|
||||
echo "Finding latest version for ${extension}..."
|
||||
|
||||
# Query the VS Marketplace API to get the extension metadata.
|
||||
local metadata_url="https://marketplace.visualstudio.com/_apis/public/gallery/extensionquery"
|
||||
local temp_metadata="${extensions_cache_dir}/metadata-${extension}.json"
|
||||
|
||||
# Create extensions directory if it doesn't exist.
|
||||
mkdir -p "${extensions_cache_dir}"
|
||||
|
||||
# Use `jq` to properly construct JSON.
|
||||
# Use jq to properly construct JSON
|
||||
local request_data
|
||||
request_data=$(jq -n --arg ext "$extension" '{
|
||||
filters: [{
|
||||
@@ -469,77 +605,193 @@ install_extension_via_vsix() {
|
||||
flags: 2
|
||||
}')
|
||||
|
||||
# Query the marketplace for extension metadata.
|
||||
if ! curl --silent --compressed -X POST \
|
||||
# Query the marketplace for extension metadata
|
||||
if curl --silent --compressed -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json; api-version=7.2-preview.1" \
|
||||
-d "${request_data}" "${metadata_url}" > "${temp_metadata}"; then
|
||||
echo "Warning: Failed to query metadata for ${extension}"
|
||||
-d "${request_data}" "${metadata_url}" > "${temp_metadata}" 2> /dev/null; then
|
||||
|
||||
# Extract the latest version from the response using jq
|
||||
install_version=$(
|
||||
jq -r '.results[0].extensions[0].versions[0].version // empty' "${temp_metadata}" \
|
||||
2> /dev/null
|
||||
)
|
||||
|
||||
if [[ -z "${install_version}" || "${install_version}" == "null" ]]; then
|
||||
echo "Error: Could not determine latest version from VS Marketplace for ${extension}" >&2
|
||||
rm -f "${temp_metadata}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "Latest version of ${extension} from VS Marketplace is ${install_version}" >&2
|
||||
else
|
||||
echo "Error: Failed to query VS Marketplace API for ${extension}" >&2
|
||||
rm -f "${temp_metadata}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Extract the latest version from the response using `jq`.
|
||||
install_version=$(
|
||||
jq -r '.results[0].extensions[0].versions[0].version' "${temp_metadata}" \
|
||||
2> /dev/null
|
||||
)
|
||||
|
||||
# Clean up metadata file.
|
||||
rm -f "${temp_metadata}"
|
||||
|
||||
# If we couldn't extract a version, use original version as fallback.
|
||||
if [[ -z "${install_version}" || "${install_version}" == "null" ]]; then
|
||||
echo "Warning: Could not determine latest version, falling back to" \
|
||||
"lock file version"
|
||||
install_version="${version}"
|
||||
else
|
||||
echo "Latest version of ${extension} is ${install_version}"
|
||||
fi
|
||||
|
||||
# Set up the download path and URL for the specific version we found.
|
||||
vsix_path="${extensions_cache_dir}/${extension}@${install_version}.vsix"
|
||||
vsix_url="https://marketplace.visualstudio.com/_apis/public/gallery/publishers/${publisher_id}/vsextensions/${extension_id}/${install_version}/vspackage"
|
||||
else
|
||||
# In strict mode, use the exact version from the lock file.
|
||||
echo "Installing ${extension}@${version} via .vsix"
|
||||
vsix_path="${extensions_cache_dir}/${extension}@${version}.vsix"
|
||||
vsix_url="https://marketplace.visualstudio.com/_apis/public/gallery/publishers/${publisher_id}/vsextensions/${extension_id}/${version}/vspackage"
|
||||
install_version="${version}"
|
||||
fi
|
||||
|
||||
# Create extensions directory if it doesn't exist.
|
||||
# Set up download path and URL
|
||||
vsix_path="${extensions_cache_dir}/${extension}@${install_version}.vsix"
|
||||
local marketplace_url="https://marketplace.visualstudio.com/_apis/public/gallery/publishers/${publisher_id}/vsextensions/${extension_id}/${install_version}/vspackage"
|
||||
|
||||
echo "Downloading ${extension}@${install_version} from VS Marketplace..." >&2
|
||||
echo " - Marketplace URL: ${marketplace_url}" >&2
|
||||
|
||||
# Create extensions directory if it doesn't exist
|
||||
mkdir -p "${extensions_cache_dir}"
|
||||
|
||||
# Download the `*.vsix` file.
|
||||
echo "Downloading ${extension}@${install_version}.vsix..."
|
||||
echo " - URL: ${vsix_url}"
|
||||
if ! curl --compressed -L -o "${vsix_path}" "${vsix_url}"; then
|
||||
echo "Warning: Failed to download ${extension}@${install_version}.vsix"
|
||||
rm -f "${vsix_path}" # Clean up potential partial downloads
|
||||
if curl --compressed -L -o "${vsix_path}" "${marketplace_url}"; then
|
||||
if [[ -s "${vsix_path}" ]]; then
|
||||
echo "Successfully downloaded from VS Marketplace" >&2
|
||||
echo "${vsix_path}"
|
||||
return 0
|
||||
else
|
||||
echo "VS Marketplace download failed (empty file)" >&2
|
||||
rm -f "${vsix_path}"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
echo "VS Marketplace download failed" >&2
|
||||
rm -f "${vsix_path}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Install the extension from `*.vsix` file.
|
||||
# Note: Installing from `*.vsix` automatically overwrites existing versions.
|
||||
echo "Installing extension from ${vsix_path}"
|
||||
if ! "${editor_cmd}" --install-extension "${vsix_path}"; then
|
||||
echo "Warning: Failed to install ${extension}@${install_version}" \
|
||||
"from '*.vsix'"
|
||||
# Try downloading extension from OpenVSX first, then fallback to official marketplace.
|
||||
#
|
||||
# Returns: Path to downloaded `.vsix` file via `STDOUT` on success.
|
||||
download_extension_vsix() {
|
||||
local extension="$1"
|
||||
local version="$2"
|
||||
local extensions_cache_dir="$3"
|
||||
local downloaded_path=""
|
||||
|
||||
# Try VS Marketplace first
|
||||
echo "Trying VS Marketplace for ${extension}@${version}..." >&2
|
||||
if downloaded_path=$(download_from_marketplace "${extension}" "${version}" "${extensions_cache_dir}"); then
|
||||
echo "${downloaded_path}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Try OpenVSX second
|
||||
echo "Trying OpenVSX for ${extension}@${version}..." >&2
|
||||
if downloaded_path=$(download_from_openvsx "${extension}" "${version}" "${extensions_cache_dir}"); then
|
||||
echo "${downloaded_path}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "Error: Failed to download ${extension}@${version} from both OpenVSX and VS Marketplace" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
# Install an extension via downloading `*.vsix` file.
|
||||
install_extension_via_vsix() {
|
||||
local editor_cmd="$1"
|
||||
local extension="$2"
|
||||
local version="$3"
|
||||
local extensions_cache_dir="$4"
|
||||
local result=0
|
||||
local vsix_path=""
|
||||
|
||||
vsix_path="$(
|
||||
download_extension_vsix "${extension}" "${version}" "${extensions_cache_dir}"
|
||||
)"
|
||||
|
||||
if [[ -n "${vsix_path}" ]]; then
|
||||
# Install the extension from the downloaded `*.vsix` file.
|
||||
# Note: Installing from `*.vsix` automatically overwrites existing versions.
|
||||
echo "Installing extension from ${vsix_path}"
|
||||
if ! "${editor_cmd}" --install-extension "${vsix_path}" --force; then
|
||||
echo "Warning: Failed to install ${extension} from '*.vsix'" >&2
|
||||
result=1
|
||||
fi
|
||||
|
||||
# Clean up the `*.vsix` file after installation attempt.
|
||||
rm -f "${vsix_path}"
|
||||
else
|
||||
echo "Warning: Failed to download ${extension}@${version}.vsix" >&2
|
||||
result=1
|
||||
fi
|
||||
|
||||
# Clean up the `*.vsix` file after installation attempt.
|
||||
rm -f "${vsix_path}"
|
||||
|
||||
return ${result}
|
||||
}
|
||||
|
||||
# Install an extension.
|
||||
install_extension() {
|
||||
local editor_cmd="$1"
|
||||
local extension="$2"
|
||||
local version="$3"
|
||||
local use_latest="$4"
|
||||
local force_install="false"
|
||||
|
||||
local extensions_cache_dir
|
||||
extensions_cache_dir="${SCRIPT_DIR}/cache/extensions"
|
||||
|
||||
# Check if already installed and get current version
|
||||
local current_version
|
||||
current_version="$(get_installed_version "${editor_cmd}" "${extension}")"
|
||||
|
||||
if [[ "${use_latest}" != "false" ]]; then
|
||||
if [[ -n "${current_version}" && "${use_latest}" != "force" ]]; then
|
||||
echo "Extension ${extension} is already installed" \
|
||||
"(current: ${current_version}), skipping"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "Checking latest version for ${extension}..." >&2
|
||||
local latest_version
|
||||
if latest_version=$(query_latest_version "${extension}"); then
|
||||
echo " - Latest available version: ${latest_version}"
|
||||
version="${latest_version}"
|
||||
else
|
||||
echo "Error: Could not determine latest version for ${extension}" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -z "${current_version}" ]]; then
|
||||
# Extension not installed.
|
||||
echo "Installing ${extension}@${version}"
|
||||
elif [[ "${current_version}" == "${version}" ]]; then
|
||||
# Exact version already installed.
|
||||
echo "Extension ${extension}@${version} is already installed, skipping"
|
||||
return 0
|
||||
else
|
||||
# Wrong version installed, need to force install.
|
||||
echo "Extension ${extension} has wrong version installed" \
|
||||
"(current: ${current_version}, wanted: ${version})," \
|
||||
"force-installing ${version}"
|
||||
force_install="true"
|
||||
fi
|
||||
|
||||
# For Cursor we need to download and install from `*.vsix` file, as
|
||||
# installation via ID fails with a signature verification error.
|
||||
if [[ "${SETUP_EDITOR}" == "cursor" ]]; then
|
||||
install_extension_via_vsix "${editor_cmd}" "${extension}" "${version}" \
|
||||
"${extensions_cache_dir}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! install_extension_direct "${editor_cmd}" "${extension}" \
|
||||
"${version}" "${force_install}"; then
|
||||
echo "Direct installation failed, trying .vsix download method..." >&2
|
||||
install_extension_via_vsix "${editor_cmd}" "${extension}" "${version}" \
|
||||
"${extensions_cache_dir}"
|
||||
fi
|
||||
|
||||
# Clean up extensions directory if empty
|
||||
rmdir "${extensions_cache_dir}" 2> /dev/null || true
|
||||
echo "Extension ${extension} installed successfully!"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Install extensions from `extensions.lock`.
|
||||
do_install_extensions() {
|
||||
local editor_cmd
|
||||
editor_cmd="$(find_editor_cmd)"
|
||||
local extensions_cache_dir="${SCRIPT_DIR}/cache/extensions"
|
||||
local extensions_lock
|
||||
extensions_lock="$(get_extensions_lock)"
|
||||
local use_latest="${1:-false}"
|
||||
@@ -549,9 +801,8 @@ do_install_extensions() {
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Warn the installed extensions cache before we start processing the lock
|
||||
# file.
|
||||
installed_extensions "${editor_cmd}"
|
||||
# Warm the installed extensions cache before we start processing the lockfile.
|
||||
installed_extensions "${editor_cmd}" > /dev/null
|
||||
|
||||
# Process each extension.
|
||||
while IFS= read -r line; do
|
||||
@@ -561,54 +812,64 @@ do_install_extensions() {
|
||||
continue
|
||||
fi
|
||||
|
||||
local extension
|
||||
local version
|
||||
extension="${line%@*}"
|
||||
version="${line#*@}"
|
||||
|
||||
# Check if already installed and get current version.
|
||||
local current_version
|
||||
current_version="$(get_installed_version "${editor_cmd}" "${extension}")"
|
||||
local force_install="false"
|
||||
|
||||
if [[ -z "${current_version}" ]]; then
|
||||
# Extension not installed.
|
||||
echo "Installing ${extension}@${version}"
|
||||
elif [[ "${use_latest}" == "true" ]]; then
|
||||
# In latest mode, skip if any version is installed.
|
||||
echo "Extension ${extension} is already installed" \
|
||||
"(current: ${current_version}), skipping"
|
||||
continue
|
||||
elif [[ "${current_version}" == "${version}" ]]; then
|
||||
# Exact version already installed.
|
||||
echo "Extension ${extension}@${version} is already installed, skipping"
|
||||
continue
|
||||
else
|
||||
# Wrong version installed, need to force install.
|
||||
echo "Extension ${extension} is installed but wrong version" \
|
||||
"(current: ${current_version}, wanted: ${version})," \
|
||||
"force-installing ${version}"
|
||||
force_install="true"
|
||||
fi
|
||||
|
||||
# For Cursor we need to download and install from `*.vsix` file, as
|
||||
# installation via ID fails with a signature verification error.
|
||||
if [[ "${SETUP_EDITOR}" == "cursor" ]]; then
|
||||
install_extension_via_vsix "${editor_cmd}" "${extension}" "${version}" \
|
||||
"${use_latest}" "${extensions_cache_dir}"
|
||||
continue
|
||||
fi
|
||||
|
||||
if ! install_extension_direct "${editor_cmd}" "${extension}" \
|
||||
"${version}" "${use_latest}" "${force_install}"; then
|
||||
echo "Direct installation failed, trying .vsix download method..."
|
||||
install_extension_via_vsix "${editor_cmd}" "${extension}" "${version}" \
|
||||
"${use_latest}" "${extensions_cache_dir}"
|
||||
fi
|
||||
install_extension "${editor_cmd}" "${extension}" "${version}" \
|
||||
"${use_latest}"
|
||||
fi
|
||||
done < "${extensions_lock}"
|
||||
}
|
||||
|
||||
# Clean up extensions directory if empty.
|
||||
rmdir "${extensions_cache_dir}" 2> /dev/null || true
|
||||
echo "Extensions installation complete!"
|
||||
# Install a specific extension by identifier.
|
||||
do_install_extension() {
|
||||
local extension_id="$1"
|
||||
local use_latest="${2:-false}"
|
||||
local editor_cmd
|
||||
editor_cmd="$(find_editor_cmd)"
|
||||
local extensions_cache_dir="${SCRIPT_DIR}/cache/extensions"
|
||||
local extension=""
|
||||
local version=""
|
||||
|
||||
if [[ -z "${extension_id}" ]]; then
|
||||
echo "Error: Extension identifier required"
|
||||
echo "Usage: siren EDITOR install EXTENSION_ID"
|
||||
echo "Example: siren cursor install ms-python.python"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Parse extension ID - can be just extension name or extension@version
|
||||
if [[ "${extension_id}" =~ @ ]]; then
|
||||
# Extension with specific version
|
||||
if ! validate_extension_line "${extension_id}"; then
|
||||
echo "Error: Invalid extension format '${extension_id}'"
|
||||
echo "Expected format: publisher.extension or publisher.extension@version"
|
||||
exit 1
|
||||
fi
|
||||
extension="${extension_id%@*}"
|
||||
version="${extension_id#*@}"
|
||||
else
|
||||
# Extension without version - install latest
|
||||
if [[ ! "${extension_id}" =~ ^[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+$ ]]; then
|
||||
echo "Error: Invalid extension format '${extension_id}'"
|
||||
echo "Expected format: publisher.extension or publisher.extension@version"
|
||||
exit 1
|
||||
fi
|
||||
extension="${extension_id}"
|
||||
version="latest"
|
||||
fi
|
||||
|
||||
# Warm the installed extensions cache
|
||||
installed_extensions "${editor_cmd}" > /dev/null
|
||||
|
||||
if [[ "${version}" == "latest" ]]; then
|
||||
use_latest="force"
|
||||
fi
|
||||
|
||||
install_extension "${editor_cmd}" "${extension}" "${version}" "${use_latest}"
|
||||
return 0
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
@@ -676,21 +937,53 @@ main() {
|
||||
|
||||
# Default values for options.
|
||||
local use_latest="false"
|
||||
local extension_id=""
|
||||
|
||||
# Parse additional options.
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--latest)
|
||||
use_latest="true"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Error: Unknown option '$1'"
|
||||
show_help
|
||||
# Handle command-specific options.
|
||||
case "${command}" in
|
||||
"install" | "inst")
|
||||
# Handle install command specially since it requires an extension argument
|
||||
if [[ $# -lt 1 ]]; then
|
||||
echo "Error: Extension identifier required for install command"
|
||||
echo "Usage: siren EDITOR install EXTENSION_ID"
|
||||
echo "Example: siren cursor install ms-python.python"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
extension_id="$1"
|
||||
shift
|
||||
|
||||
# For install command, reject any additional options
|
||||
if [[ $# -gt 0 ]]; then
|
||||
echo "Error: Unknown option '$1' for install command"
|
||||
echo "Usage: siren EDITOR install EXTENSION_ID"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
"extensions" | "ext")
|
||||
# Parse additional options for other commands
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--latest)
|
||||
if [[ "${use_latest}" != "force" ]]; then
|
||||
use_latest="true"
|
||||
fi
|
||||
shift
|
||||
;;
|
||||
--force-latest)
|
||||
use_latest="force"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Error: Unknown option '$1'"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
;;
|
||||
esac
|
||||
|
||||
# Handle commands.
|
||||
case "${command}" in
|
||||
@@ -703,6 +996,9 @@ main() {
|
||||
"extensions" | "ext")
|
||||
do_install_extensions "${use_latest}"
|
||||
;;
|
||||
"install")
|
||||
do_install_extension "${extension_id}"
|
||||
;;
|
||||
"")
|
||||
echo "Error: No command provided"
|
||||
show_help
|
||||
|
||||
Reference in New Issue
Block a user