feat(scaffold): install binaries from latest release in install script
This commit is contained in:
parent
a9378885f2
commit
973770ed78
2 changed files with 688 additions and 25 deletions
|
|
@ -357,6 +357,30 @@ BINARY_NAME="{{.BinaryName}}"
|
|||
MODULE_PATH="{{.ModulePath}}"
|
||||
DEFAULT_PROFILE="{{.DefaultProfile}}"
|
||||
PROFILE_ENV="{{.ProfileEnv}}"
|
||||
DEFAULT_RELEASE_DRIVER="{{.ReleaseDriver}}"
|
||||
DEFAULT_RELEASE_BASE_URL="{{.ReleaseBaseURL}}"
|
||||
DEFAULT_RELEASE_REPOSITORY="{{.ReleaseRepository}}"
|
||||
DEFAULT_ASSET_NAME_TEMPLATE="{binary}-{os}-{arch}{ext}"
|
||||
DEFAULT_CHECKSUM_ASSET_NAME="{asset}.sha256"
|
||||
DEFAULT_CHECKSUM_REQUIRED="true"
|
||||
DEFAULT_TOKEN_HEADER="Authorization"
|
||||
DEFAULT_TOKEN_PREFIX="token"
|
||||
DEFAULT_TOKEN_ENV_NAME="{{.ReleaseTokenEnv}}"
|
||||
RELEASE_DRIVER="$DEFAULT_RELEASE_DRIVER"
|
||||
RELEASE_BASE_URL="$DEFAULT_RELEASE_BASE_URL"
|
||||
RELEASE_REPOSITORY="$DEFAULT_RELEASE_REPOSITORY"
|
||||
LATEST_RELEASE_URL=""
|
||||
ASSET_NAME_TEMPLATE="$DEFAULT_ASSET_NAME_TEMPLATE"
|
||||
CHECKSUM_ASSET_NAME="$DEFAULT_CHECKSUM_ASSET_NAME"
|
||||
CHECKSUM_REQUIRED="$DEFAULT_CHECKSUM_REQUIRED"
|
||||
TOKEN_HEADER="$DEFAULT_TOKEN_HEADER"
|
||||
TOKEN_PREFIX="$DEFAULT_TOKEN_PREFIX"
|
||||
AUTH_HEADER_NAME=""
|
||||
AUTH_HEADER_VALUE=""
|
||||
TOKEN_ENV_NAMES=()
|
||||
if [ -n "$DEFAULT_TOKEN_ENV_NAME" ]; then
|
||||
TOKEN_ENV_NAMES=("$DEFAULT_TOKEN_ENV_NAME")
|
||||
fi
|
||||
PREFILL_SERVER_NAME=""
|
||||
PREFILL_PROFILE_VALUE=""
|
||||
PREFILL_COMMAND_PATH=""
|
||||
|
|
@ -543,15 +567,546 @@ toml_escape() {
|
|||
printf "%s" "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'
|
||||
}
|
||||
|
||||
go_bin_dir() {
|
||||
local gobin
|
||||
gobin="$(go env GOBIN 2>/dev/null || true)"
|
||||
if [ -n "$gobin" ]; then
|
||||
printf "%s\n" "$gobin"
|
||||
trim_whitespace() {
|
||||
printf "%s" "$1" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//'
|
||||
}
|
||||
|
||||
unquote_toml() {
|
||||
local value
|
||||
value="$(trim_whitespace "$1")"
|
||||
if [ "${#value}" -ge 2 ]; then
|
||||
case "$value" in
|
||||
\"*\")
|
||||
value="${value#\"}"
|
||||
value="${value%\"}"
|
||||
;;
|
||||
\'*\')
|
||||
value="${value#\'}"
|
||||
value="${value%\'}"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
printf "%s" "$value"
|
||||
}
|
||||
|
||||
normalize_bool() {
|
||||
local value
|
||||
value="$(printf "%s" "$1" | tr '[:upper:]' '[:lower:]')"
|
||||
value="$(trim_whitespace "$value")"
|
||||
case "$value" in
|
||||
true|1|yes|y)
|
||||
printf "true"
|
||||
;;
|
||||
false|0|no|n)
|
||||
printf "false"
|
||||
;;
|
||||
*)
|
||||
printf "%s" "$2"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
toml_read_update_value() {
|
||||
local key="$1"
|
||||
awk -v key="$key" '
|
||||
BEGIN {
|
||||
in_update = 0
|
||||
}
|
||||
{
|
||||
line = $0
|
||||
sub(/[[:space:]]*#.*/, "", line)
|
||||
if (line ~ /^[[:space:]]*\[/) {
|
||||
if (line ~ /^[[:space:]]*\[update\][[:space:]]*$/) {
|
||||
in_update = 1
|
||||
} else {
|
||||
in_update = 0
|
||||
}
|
||||
}
|
||||
if (in_update == 1 && line ~ "^[[:space:]]*" key "[[:space:]]*=") {
|
||||
sub("^[[:space:]]*" key "[[:space:]]*=[[:space:]]*", "", line)
|
||||
print line
|
||||
exit
|
||||
}
|
||||
}
|
||||
' mcp.toml
|
||||
}
|
||||
|
||||
toml_read_update_array() {
|
||||
local key="$1"
|
||||
local raw
|
||||
raw="$(toml_read_update_value "$key")"
|
||||
raw="$(trim_whitespace "$raw")"
|
||||
if [ -z "$raw" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
go env GOPATH 2>/dev/null | awk '{print $1 "/bin"}'
|
||||
raw="${raw#\[}"
|
||||
raw="${raw%\]}"
|
||||
local items=()
|
||||
local item=""
|
||||
IFS=',' read -r -a items <<< "$raw"
|
||||
for item in "${items[@]}"; do
|
||||
item="$(unquote_toml "$item")"
|
||||
item="$(trim_whitespace "$item")"
|
||||
if [ -n "$item" ]; then
|
||||
printf "%s\n" "$item"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
normalize_release_config() {
|
||||
RELEASE_DRIVER="$(printf "%s" "$RELEASE_DRIVER" | tr '[:upper:]' '[:lower:]')"
|
||||
RELEASE_DRIVER="$(trim_whitespace "$RELEASE_DRIVER")"
|
||||
|
||||
RELEASE_REPOSITORY="$(trim_whitespace "$RELEASE_REPOSITORY")"
|
||||
RELEASE_REPOSITORY="${RELEASE_REPOSITORY#/}"
|
||||
RELEASE_REPOSITORY="${RELEASE_REPOSITORY%/}"
|
||||
|
||||
RELEASE_BASE_URL="$(trim_whitespace "$RELEASE_BASE_URL")"
|
||||
RELEASE_BASE_URL="${RELEASE_BASE_URL%/}"
|
||||
|
||||
LATEST_RELEASE_URL="$(trim_whitespace "$LATEST_RELEASE_URL")"
|
||||
ASSET_NAME_TEMPLATE="$(trim_whitespace "$ASSET_NAME_TEMPLATE")"
|
||||
CHECKSUM_ASSET_NAME="$(trim_whitespace "$CHECKSUM_ASSET_NAME")"
|
||||
TOKEN_HEADER="$(trim_whitespace "$TOKEN_HEADER")"
|
||||
TOKEN_PREFIX="$(trim_whitespace "$TOKEN_PREFIX")"
|
||||
|
||||
if [ -z "$ASSET_NAME_TEMPLATE" ]; then
|
||||
ASSET_NAME_TEMPLATE="$DEFAULT_ASSET_NAME_TEMPLATE"
|
||||
fi
|
||||
if [ -z "$CHECKSUM_ASSET_NAME" ]; then
|
||||
CHECKSUM_ASSET_NAME="$DEFAULT_CHECKSUM_ASSET_NAME"
|
||||
fi
|
||||
|
||||
local filtered_env_names=()
|
||||
local env_name=""
|
||||
for env_name in "${TOKEN_ENV_NAMES[@]}"; do
|
||||
env_name="$(trim_whitespace "$env_name")"
|
||||
if [ -n "$env_name" ]; then
|
||||
filtered_env_names+=("$env_name")
|
||||
fi
|
||||
done
|
||||
TOKEN_ENV_NAMES=("${filtered_env_names[@]}")
|
||||
|
||||
case "$RELEASE_DRIVER" in
|
||||
gitea)
|
||||
if [ -z "$TOKEN_HEADER" ]; then
|
||||
TOKEN_HEADER="Authorization"
|
||||
fi
|
||||
if [ -z "$TOKEN_PREFIX" ]; then
|
||||
TOKEN_PREFIX="token"
|
||||
fi
|
||||
if [ "${#TOKEN_ENV_NAMES[@]}" -eq 0 ]; then
|
||||
TOKEN_ENV_NAMES=("GITEA_TOKEN")
|
||||
fi
|
||||
;;
|
||||
gitlab)
|
||||
if [ -z "$RELEASE_BASE_URL" ]; then
|
||||
RELEASE_BASE_URL="https://gitlab.com"
|
||||
fi
|
||||
if [ -z "$TOKEN_HEADER" ]; then
|
||||
TOKEN_HEADER="PRIVATE-TOKEN"
|
||||
fi
|
||||
if [ "${#TOKEN_ENV_NAMES[@]}" -eq 0 ]; then
|
||||
TOKEN_ENV_NAMES=("GITLAB_TOKEN" "GITLAB_PRIVATE_TOKEN")
|
||||
fi
|
||||
;;
|
||||
github)
|
||||
if [ -z "$RELEASE_BASE_URL" ]; then
|
||||
RELEASE_BASE_URL="https://api.github.com"
|
||||
fi
|
||||
if [ -z "$TOKEN_HEADER" ]; then
|
||||
TOKEN_HEADER="Authorization"
|
||||
fi
|
||||
if [ -z "$TOKEN_PREFIX" ]; then
|
||||
TOKEN_PREFIX="Bearer"
|
||||
fi
|
||||
if [ "${#TOKEN_ENV_NAMES[@]}" -eq 0 ]; then
|
||||
TOKEN_ENV_NAMES=("GITHUB_TOKEN")
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
load_release_config_from_manifest() {
|
||||
if [ ! -f "mcp.toml" ]; then
|
||||
ui_warn "mcp.toml introuvable: utilisation de la configuration release integree au script."
|
||||
normalize_release_config
|
||||
return
|
||||
fi
|
||||
|
||||
local value
|
||||
value="$(toml_read_update_value "driver")"
|
||||
if [ -n "$value" ]; then
|
||||
RELEASE_DRIVER="$(printf "%s" "$(unquote_toml "$value")" | tr '[:upper:]' '[:lower:]')"
|
||||
fi
|
||||
|
||||
value="$(toml_read_update_value "repository")"
|
||||
if [ -n "$value" ]; then
|
||||
RELEASE_REPOSITORY="$(unquote_toml "$value")"
|
||||
fi
|
||||
|
||||
value="$(toml_read_update_value "base_url")"
|
||||
if [ -n "$value" ]; then
|
||||
RELEASE_BASE_URL="$(unquote_toml "$value")"
|
||||
fi
|
||||
|
||||
value="$(toml_read_update_value "latest_release_url")"
|
||||
if [ -n "$value" ]; then
|
||||
LATEST_RELEASE_URL="$(unquote_toml "$value")"
|
||||
fi
|
||||
|
||||
value="$(toml_read_update_value "asset_name_template")"
|
||||
if [ -n "$value" ]; then
|
||||
ASSET_NAME_TEMPLATE="$(unquote_toml "$value")"
|
||||
fi
|
||||
|
||||
value="$(toml_read_update_value "checksum_asset_name")"
|
||||
if [ -n "$value" ]; then
|
||||
CHECKSUM_ASSET_NAME="$(unquote_toml "$value")"
|
||||
fi
|
||||
|
||||
value="$(toml_read_update_value "checksum_required")"
|
||||
if [ -n "$value" ]; then
|
||||
CHECKSUM_REQUIRED="$(normalize_bool "$(unquote_toml "$value")" "$CHECKSUM_REQUIRED")"
|
||||
fi
|
||||
|
||||
value="$(toml_read_update_value "token_header")"
|
||||
if [ -n "$value" ]; then
|
||||
TOKEN_HEADER="$(unquote_toml "$value")"
|
||||
fi
|
||||
|
||||
value="$(toml_read_update_value "token_prefix")"
|
||||
if [ -n "$value" ]; then
|
||||
TOKEN_PREFIX="$(unquote_toml "$value")"
|
||||
fi
|
||||
|
||||
local parsed_token_env_names=()
|
||||
local parsed_env_name=""
|
||||
while IFS= read -r parsed_env_name; do
|
||||
if [ -n "$parsed_env_name" ]; then
|
||||
parsed_token_env_names+=("$parsed_env_name")
|
||||
fi
|
||||
done < <(toml_read_update_array "token_env_names")
|
||||
if [ "${#parsed_token_env_names[@]}" -gt 0 ]; then
|
||||
TOKEN_ENV_NAMES=("${parsed_token_env_names[@]}")
|
||||
fi
|
||||
|
||||
normalize_release_config
|
||||
}
|
||||
|
||||
resolve_goos() {
|
||||
case "$(uname -s)" in
|
||||
Linux)
|
||||
printf "linux"
|
||||
;;
|
||||
Darwin)
|
||||
printf "darwin"
|
||||
;;
|
||||
FreeBSD)
|
||||
printf "freebsd"
|
||||
;;
|
||||
OpenBSD)
|
||||
printf "openbsd"
|
||||
;;
|
||||
NetBSD)
|
||||
printf "netbsd"
|
||||
;;
|
||||
CYGWIN*|MINGW*|MSYS*)
|
||||
printf "windows"
|
||||
;;
|
||||
*)
|
||||
ui_error "OS non supporte: $(uname -s)"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
resolve_goarch() {
|
||||
case "$(uname -m)" in
|
||||
x86_64|amd64)
|
||||
printf "amd64"
|
||||
;;
|
||||
aarch64|arm64)
|
||||
printf "arm64"
|
||||
;;
|
||||
armv7*|armv6*|armhf)
|
||||
printf "arm"
|
||||
;;
|
||||
i386|i686)
|
||||
printf "386"
|
||||
;;
|
||||
ppc64le)
|
||||
printf "ppc64le"
|
||||
;;
|
||||
s390x)
|
||||
printf "s390x"
|
||||
;;
|
||||
riscv64)
|
||||
printf "riscv64"
|
||||
;;
|
||||
*)
|
||||
ui_error "Architecture non supportee: $(uname -m)"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
resolve_asset_name() {
|
||||
local goos="$1"
|
||||
local goarch="$2"
|
||||
local ext=""
|
||||
if [ "$goos" = "windows" ]; then
|
||||
ext=".exe"
|
||||
fi
|
||||
|
||||
local template="$ASSET_NAME_TEMPLATE"
|
||||
if [ -z "$template" ]; then
|
||||
template="$DEFAULT_ASSET_NAME_TEMPLATE"
|
||||
fi
|
||||
|
||||
local asset_name="$template"
|
||||
asset_name="${asset_name//\{binary\}/$BINARY_NAME}"
|
||||
asset_name="${asset_name//\{os\}/$goos}"
|
||||
asset_name="${asset_name//\{arch\}/$goarch}"
|
||||
asset_name="${asset_name//\{ext\}/$ext}"
|
||||
asset_name="$(trim_whitespace "$asset_name")"
|
||||
|
||||
if [ -z "$asset_name" ]; then
|
||||
ui_error "Le template d'asset resolve vers une valeur vide."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "$asset_name" in
|
||||
*/*|*\\*)
|
||||
ui_error "Nom d'asset invalide (separateur de chemin): $asset_name"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
printf "%s" "$asset_name"
|
||||
}
|
||||
|
||||
resolve_latest_release_url() {
|
||||
if [ -n "$LATEST_RELEASE_URL" ]; then
|
||||
printf "%s" "$LATEST_RELEASE_URL"
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -z "$RELEASE_DRIVER" ]; then
|
||||
ui_error "Configuration release incomplete: definir [update].driver ou [update].latest_release_url."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$RELEASE_REPOSITORY" ]; then
|
||||
ui_error "Configuration release incomplete: definir [update].repository."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "$RELEASE_DRIVER" in
|
||||
gitea)
|
||||
if [ -z "$RELEASE_BASE_URL" ]; then
|
||||
ui_error "Configuration release incomplete: [update].base_url requis pour driver gitea."
|
||||
exit 1
|
||||
fi
|
||||
printf "%s/api/v1/repos/%s/releases/latest" "$RELEASE_BASE_URL" "$RELEASE_REPOSITORY"
|
||||
;;
|
||||
gitlab)
|
||||
local encoded_repository
|
||||
encoded_repository="$(jq -nr --arg value "$RELEASE_REPOSITORY" '$value|@uri')"
|
||||
printf "%s/api/v4/projects/%s/releases/permalink/latest" "$RELEASE_BASE_URL" "$encoded_repository"
|
||||
;;
|
||||
github)
|
||||
printf "%s/repos/%s/releases/latest" "$RELEASE_BASE_URL" "$RELEASE_REPOSITORY"
|
||||
;;
|
||||
*)
|
||||
ui_error "Driver release non supporte: $RELEASE_DRIVER (attendu: gitea, gitlab ou github)."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
resolve_auth_header() {
|
||||
AUTH_HEADER_NAME=""
|
||||
AUTH_HEADER_VALUE=""
|
||||
|
||||
local token=""
|
||||
local env_name
|
||||
for env_name in "${TOKEN_ENV_NAMES[@]}"; do
|
||||
if [ -z "$env_name" ]; then
|
||||
continue
|
||||
fi
|
||||
if [ -n "${!env_name:-}" ]; then
|
||||
token="$(trim_whitespace "${!env_name}")"
|
||||
if [ -n "$token" ]; then
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "$token" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
local header_name
|
||||
header_name="$(trim_whitespace "$TOKEN_HEADER")"
|
||||
if [ -z "$header_name" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
local prefix
|
||||
prefix="$(trim_whitespace "$TOKEN_PREFIX")"
|
||||
if [ -n "$prefix" ]; then
|
||||
local lower_token
|
||||
local lower_prefix
|
||||
lower_token="$(printf "%s" "$token" | tr '[:upper:]' '[:lower:]')"
|
||||
lower_prefix="$(printf "%s" "$prefix" | tr '[:upper:]' '[:lower:]')"
|
||||
if [[ "$lower_token" != "$lower_prefix"* ]]; then
|
||||
token="$prefix $token"
|
||||
fi
|
||||
fi
|
||||
|
||||
AUTH_HEADER_NAME="$header_name"
|
||||
AUTH_HEADER_VALUE="$token"
|
||||
}
|
||||
|
||||
curl_download() {
|
||||
local url="$1"
|
||||
local output_path="$2"
|
||||
local mode="${3:-}"
|
||||
local curl_args=(
|
||||
-fsSL
|
||||
-H "User-Agent: mcp install wizard"
|
||||
)
|
||||
|
||||
if [ "$mode" = "json" ]; then
|
||||
curl_args+=(-H "Accept: application/json")
|
||||
fi
|
||||
if [ -n "$AUTH_HEADER_NAME" ] && [ -n "$AUTH_HEADER_VALUE" ]; then
|
||||
curl_args+=(-H "${AUTH_HEADER_NAME}: ${AUTH_HEADER_VALUE}")
|
||||
fi
|
||||
|
||||
curl "${curl_args[@]}" "$url" -o "$output_path"
|
||||
}
|
||||
|
||||
resolve_url_reference() {
|
||||
local value="$1"
|
||||
local base="$2"
|
||||
|
||||
if printf "%s" "$value" | grep -Eq '^https?://'; then
|
||||
printf "%s" "$value"
|
||||
return
|
||||
fi
|
||||
|
||||
local origin
|
||||
origin="$(printf "%s" "$base" | sed -E 's#^(https?://[^/]+).*$#\1#')"
|
||||
|
||||
if [ -z "$origin" ]; then
|
||||
printf "%s" "$value"
|
||||
return
|
||||
fi
|
||||
|
||||
if [ "${value#/}" != "$value" ]; then
|
||||
printf "%s%s" "$origin" "$value"
|
||||
return
|
||||
fi
|
||||
|
||||
local base_no_query
|
||||
base_no_query="$(printf "%s" "$base" | sed 's/[?#].*$//')"
|
||||
local base_dir="${base_no_query%/*}"
|
||||
printf "%s/%s" "$base_dir" "$value"
|
||||
}
|
||||
|
||||
resolve_asset_url_from_release() {
|
||||
local release_json_path="$1"
|
||||
local asset_name="$2"
|
||||
jq -r --arg asset "$asset_name" '
|
||||
(
|
||||
.assets.links[]? | select(.name == $asset) | (.direct_asset_url // .browser_download_url // .url // empty)
|
||||
),
|
||||
(
|
||||
.assets[]? | select(.name == $asset) | (.direct_asset_url // .browser_download_url // .url // empty)
|
||||
)
|
||||
| select(. != null and . != "")
|
||||
' "$release_json_path" | head -n 1
|
||||
}
|
||||
|
||||
release_assets_preview() {
|
||||
local release_json_path="$1"
|
||||
jq -r '
|
||||
[
|
||||
(.assets.links[]?.name),
|
||||
(.assets[]?.name)
|
||||
]
|
||||
| map(select(. != null and . != ""))
|
||||
| unique
|
||||
| .[:8]
|
||||
| join(", ")
|
||||
' "$release_json_path"
|
||||
}
|
||||
|
||||
parse_checksum_for_asset() {
|
||||
local checksum_file="$1"
|
||||
local asset_name="$2"
|
||||
awk -v asset="$asset_name" '
|
||||
function is_hex(value) {
|
||||
return value ~ /^[0-9A-Fa-f]{64}$/
|
||||
}
|
||||
{
|
||||
line = $0
|
||||
sub(/#.*/, "", line)
|
||||
gsub(/^[[:space:]]+|[[:space:]]+$/, "", line)
|
||||
if (line == "") {
|
||||
next
|
||||
}
|
||||
|
||||
n = split(line, fields, /[[:space:]]+/)
|
||||
if (n == 1 && is_hex(fields[1]) && fallback == "") {
|
||||
fallback = fields[1]
|
||||
next
|
||||
}
|
||||
|
||||
if (n >= 2 && is_hex(fields[1])) {
|
||||
candidate = fields[2]
|
||||
sub(/^\*/, "", candidate)
|
||||
sub(/^\.\/+/, "", candidate)
|
||||
if (candidate == asset) {
|
||||
print fields[1]
|
||||
exit
|
||||
}
|
||||
}
|
||||
|
||||
if (n >= 2 && is_hex(fields[n])) {
|
||||
candidate = fields[1]
|
||||
sub(/^\*/, "", candidate)
|
||||
sub(/^\.\/+/, "", candidate)
|
||||
if (candidate == asset) {
|
||||
print fields[n]
|
||||
exit
|
||||
}
|
||||
}
|
||||
}
|
||||
END {
|
||||
if (fallback != "") {
|
||||
print fallback
|
||||
}
|
||||
}
|
||||
' "$checksum_file"
|
||||
}
|
||||
|
||||
sha256_file() {
|
||||
local file_path="$1"
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
sha256sum "$file_path" | awk '{print $1}'
|
||||
return
|
||||
fi
|
||||
if command -v shasum >/dev/null 2>&1; then
|
||||
shasum -a 256 "$file_path" | awk '{print $1}'
|
||||
return
|
||||
fi
|
||||
|
||||
ui_error "Aucun outil SHA-256 detecte (sha256sum ou shasum requis)."
|
||||
exit 1
|
||||
}
|
||||
|
||||
resolve_binary_path() {
|
||||
|
|
@ -560,13 +1115,9 @@ resolve_binary_path() {
|
|||
return
|
||||
fi
|
||||
|
||||
if command -v go >/dev/null 2>&1; then
|
||||
local bin_dir
|
||||
bin_dir="$(go_bin_dir)"
|
||||
if [ -n "$bin_dir" ] && [ -x "$bin_dir/$BINARY_NAME" ]; then
|
||||
printf "%s\n" "$bin_dir/$BINARY_NAME"
|
||||
return
|
||||
fi
|
||||
if [ -x "$HOME/.local/bin/$BINARY_NAME" ]; then
|
||||
printf "%s\n" "$HOME/.local/bin/$BINARY_NAME"
|
||||
return
|
||||
fi
|
||||
|
||||
printf "%s\n" "$HOME/.local/bin/$BINARY_NAME"
|
||||
|
|
@ -583,10 +1134,18 @@ ensure_cli() {
|
|||
}
|
||||
|
||||
install_binary() {
|
||||
ensure_cli "curl"
|
||||
ensure_cli "jq"
|
||||
|
||||
load_release_config_from_manifest
|
||||
resolve_auth_header
|
||||
|
||||
local target_path="$HOME/.local/bin/$BINARY_NAME"
|
||||
if command -v "$BINARY_NAME" >/dev/null 2>&1; then
|
||||
ui_success "Binaire detecte: $(command -v "$BINARY_NAME")"
|
||||
target_path="$(command -v "$BINARY_NAME")"
|
||||
ui_success "Binaire detecte: $target_path"
|
||||
local reinstall
|
||||
reinstall="$(prompt "Reinstaller via go install ? (y/N)" "N")"
|
||||
reinstall="$(prompt "Reinstaller depuis la derniere release ? (y/N)" "N")"
|
||||
case "$reinstall" in
|
||||
y|Y|yes|YES)
|
||||
;;
|
||||
|
|
@ -596,19 +1155,118 @@ install_binary() {
|
|||
esac
|
||||
fi
|
||||
|
||||
if ! command -v go >/dev/null 2>&1; then
|
||||
ui_error "Go n'est pas installe. Installe Go ou choisis une configuration manuelle."
|
||||
if [ ! -w "$(dirname "$target_path")" ]; then
|
||||
ui_warn "Pas de droit d'ecriture dans $(dirname "$target_path"), installation dans $HOME/.local/bin."
|
||||
target_path="$HOME/.local/bin/$BINARY_NAME"
|
||||
fi
|
||||
|
||||
local goos
|
||||
goos="$(resolve_goos)"
|
||||
local goarch
|
||||
goarch="$(resolve_goarch)"
|
||||
local asset_name
|
||||
asset_name="$(resolve_asset_name "$goos" "$goarch")"
|
||||
local release_url
|
||||
release_url="$(resolve_latest_release_url)"
|
||||
|
||||
ui_info "Recherche de la derniere release pour $RELEASE_REPOSITORY ($goos/$goarch)..."
|
||||
local release_json
|
||||
release_json="$(mktemp)"
|
||||
if ! curl_download "$release_url" "$release_json" "json"; then
|
||||
rm -f "$release_json"
|
||||
ui_error "Impossible de recuperer la release latest depuis $release_url."
|
||||
if [ "${#TOKEN_ENV_NAMES[@]}" -gt 0 ]; then
|
||||
ui_info "Si le repo est prive, configure un token via: ${TOKEN_ENV_NAMES[*]}"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ui_info "Installation du binaire via go install..."
|
||||
go install "${MODULE_PATH}/cmd/${BINARY_NAME}@latest"
|
||||
local release_tag
|
||||
release_tag="$(jq -r '.tag_name // empty' "$release_json")"
|
||||
if [ -z "$release_tag" ]; then
|
||||
rm -f "$release_json"
|
||||
ui_error "Reponse release invalide: tag_name manquant."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local bin_dir
|
||||
bin_dir="$(go_bin_dir)"
|
||||
if [ -n "$bin_dir" ]; then
|
||||
ui_success "Binaire installe dans $bin_dir"
|
||||
ui_info "Ajoute ce dossier au PATH si necessaire."
|
||||
local asset_url
|
||||
asset_url="$(resolve_asset_url_from_release "$release_json" "$asset_name")"
|
||||
if [ -z "$asset_url" ]; then
|
||||
local preview
|
||||
preview="$(release_assets_preview "$release_json")"
|
||||
rm -f "$release_json"
|
||||
ui_error "Aucun asset \"$asset_name\" dans la release $release_tag."
|
||||
if [ -n "$preview" ]; then
|
||||
ui_info "Assets disponibles: $preview"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
asset_url="$(resolve_url_reference "$asset_url" "$release_url")"
|
||||
|
||||
ui_info "Telechargement de l'asset $asset_name ($release_tag)..."
|
||||
local download_path
|
||||
download_path="$(mktemp)"
|
||||
if ! curl_download "$asset_url" "$download_path"; then
|
||||
rm -f "$release_json" "$download_path"
|
||||
ui_error "Echec du telechargement de l'asset: $asset_url"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local checksum_asset_name
|
||||
checksum_asset_name="${CHECKSUM_ASSET_NAME//\{asset\}/$asset_name}"
|
||||
if [ -z "$checksum_asset_name" ]; then
|
||||
checksum_asset_name="${asset_name}.sha256"
|
||||
fi
|
||||
local checksum_url
|
||||
checksum_url="$(resolve_asset_url_from_release "$release_json" "$checksum_asset_name")"
|
||||
if [ -n "$checksum_url" ]; then
|
||||
checksum_url="$(resolve_url_reference "$checksum_url" "$release_url")"
|
||||
local checksum_path
|
||||
checksum_path="$(mktemp)"
|
||||
if ! curl_download "$checksum_url" "$checksum_path"; then
|
||||
rm -f "$release_json" "$download_path" "$checksum_path"
|
||||
ui_error "Echec du telechargement du checksum: $checksum_url"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local expected_checksum
|
||||
expected_checksum="$(parse_checksum_for_asset "$checksum_path" "$asset_name")"
|
||||
if [ -z "$expected_checksum" ]; then
|
||||
rm -f "$release_json" "$download_path" "$checksum_path"
|
||||
ui_error "Checksum introuvable dans $checksum_asset_name pour l'asset $asset_name."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local actual_checksum
|
||||
actual_checksum="$(sha256_file "$download_path")"
|
||||
local actual_checksum_lc
|
||||
actual_checksum_lc="$(printf "%s" "$actual_checksum" | tr '[:upper:]' '[:lower:]')"
|
||||
local expected_checksum_lc
|
||||
expected_checksum_lc="$(printf "%s" "$expected_checksum" | tr '[:upper:]' '[:lower:]')"
|
||||
if [ "$actual_checksum_lc" != "$expected_checksum_lc" ]; then
|
||||
rm -f "$release_json" "$download_path" "$checksum_path"
|
||||
ui_error "Checksum invalide pour $asset_name."
|
||||
exit 1
|
||||
fi
|
||||
rm -f "$checksum_path"
|
||||
ui_success "Checksum verifie pour $asset_name."
|
||||
else
|
||||
if [ "$CHECKSUM_REQUIRED" = "true" ]; then
|
||||
rm -f "$release_json" "$download_path"
|
||||
ui_error "Checksum requis mais asset \"$checksum_asset_name\" introuvable."
|
||||
exit 1
|
||||
fi
|
||||
ui_warn "Checksum non disponible pour $asset_name (verification ignoree)."
|
||||
fi
|
||||
|
||||
chmod +x "$download_path"
|
||||
mkdir -p "$(dirname "$target_path")"
|
||||
mv "$download_path" "$target_path"
|
||||
rm -f "$release_json"
|
||||
ui_success "Binaire installe: $target_path"
|
||||
|
||||
if ! printf ":%s:" "$PATH" | grep -Fq ":$(dirname "$target_path"):"; then
|
||||
ui_info "Ajoute $(dirname "$target_path") au PATH si necessaire."
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -127,7 +127,12 @@ func TestGenerateCreatesRecommendedSkeleton(t *testing.T) {
|
|||
for _, snippet := range []string{
|
||||
"#!/usr/bin/env bash",
|
||||
`MODULE_PATH="example.com/acme/my-mcp"`,
|
||||
`go install "${MODULE_PATH}/cmd/${BINARY_NAME}@latest"`,
|
||||
`DEFAULT_RELEASE_REPOSITORY="org/my-mcp"`,
|
||||
`load_release_config_from_manifest`,
|
||||
`resolve_latest_release_url()`,
|
||||
`curl_download "$release_url" "$release_json" "json"`,
|
||||
`asset_name="$(resolve_asset_name "$goos" "$goarch")"`,
|
||||
`Reinstaller depuis la derniere release ? (y/N)`,
|
||||
"MCP Install Wizard",
|
||||
`menu_select() {`,
|
||||
`Utilise ↑/↓ puis Entrée.`,
|
||||
|
|
|
|||
Loading…
Reference in a new issue