mirror of
https://github.com/dexoron/dcr.git
synced 2026-10-21 21:19:35 +00:00
Introduce `--mirror` and `DCRUP_MIRROR` so `dcrup` can fetch prebuilt binaries from multiple CDNs. Default `auto` tries cf → gh → sf → ya and uses the first successful download. - dcrup.sh / dcrup.ps1: mirror chain, CLI flag, env override - remove install.sh / install.ps1 / install_bsd.sh (superseded by dcrup) - GitHub Actions: upload releases to Cloudflare R2 next to Yandex S3 - docs: README, FAQ, changelog, installation, env vars, contributing
669 lines
20 KiB
Bash
Executable File
669 lines
20 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -Eeuo pipefail
|
|
|
|
DCRUP_HOME="${DCRUP_HOME:-$HOME/.dcr}"
|
|
DCRUP_BIN="${DCRUP_BIN:-$DCRUP_HOME/bin}"
|
|
DCRUP_TC="${DCRUP_HOME}/toolchains"
|
|
DCRUP_META="${DCRUP_HOME}/meta"
|
|
REPO_URL="${DCRUP_REPO:-https://github.com/dexoron/dcr}"
|
|
DCRUP_MIRROR="${DCRUP_MIRROR:-auto}"
|
|
API_LATEST="https://api.github.com/repos/dexoron/dcr/releases/latest"
|
|
API_ALL="https://api.github.com/repos/dexoron/dcr/releases"
|
|
FEATURES="${DCR_FEATURES:-archive}"
|
|
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
CYAN='\033[0;36m'
|
|
NC='\033[0m'
|
|
|
|
log() { printf "${CYAN}[dcrup]${NC} %s\n" "$*"; }
|
|
ok() { printf "${GREEN}[ok]${NC} %s\n" "$*"; }
|
|
warn() { printf "${YELLOW}[warn]${NC} %s\n" "$*"; }
|
|
die() { printf "${RED}[error]${NC} %s\n" "$*" >&2; exit 1; }
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
dcrup — install and switch DCR versions
|
|
|
|
Usage:
|
|
dcrup install <spec> [--build|--release] [--force] [--libc gnu|musl|auto] [--mirror auto|cf|gh|sf|ya]
|
|
dcrup default <spec>
|
|
dcrup update
|
|
dcrup list
|
|
dcrup show
|
|
dcrup which
|
|
dcrup uninstall [<spec>|--all]
|
|
dcrup self-install [--to DIR]
|
|
dcrup help
|
|
|
|
Spec:
|
|
stable | dev | night
|
|
VERSION → VERSION@stable (e.g. 0.8.2)
|
|
VERSION@stable
|
|
VERSION@dev
|
|
night → always build from branch "dev" HEAD
|
|
|
|
Modes:
|
|
--release download prebuilt binary (default for stable/dev)
|
|
--build cargo build --release --features archive
|
|
night always --build (prebuilt not available)
|
|
|
|
Linux libc (prebuilt triple only):
|
|
--libc gnu x86_64-unknown-linux-gnu (default)
|
|
--libc musl x86_64-unknown-linux-musl
|
|
--libc auto musl if host ldd/libc is musl, else gnu
|
|
|
|
Mirrors (prebuilt download only):
|
|
--mirror auto try cf → gh → sf → ya, first successful download wins (default)
|
|
--mirror cf download from cdn-global.dcr-tool.ru
|
|
--mirror gh download from github.com/dexoron/dcr
|
|
--mirror sf download from sourceforge.net/projects/dcr-tool
|
|
--mirror ya download from cdn-ru.dcr-tool.ru
|
|
DCRUP_MIRROR env override (default: auto)
|
|
|
|
Env:
|
|
DCRUP_HOME default ~/.dcr
|
|
DCRUP_BIN default $DCRUP_HOME/bin
|
|
DCR_FEATURES default archive
|
|
DCRUP_REPO git/GitHub repo URL
|
|
DCRUP_LIBC gnu|musl|auto (default: gnu)
|
|
DCRUP_MIRROR auto|cf|gh|sf|ya (default: auto)
|
|
EOF
|
|
}
|
|
|
|
need_cmd() {
|
|
command -v "$1" >/dev/null 2>&1 || die "required command not found: $1"
|
|
}
|
|
|
|
detect_linux_libc() {
|
|
local pref="${DCRUP_LIBC:-gnu}"
|
|
case "$pref" in
|
|
gnu|glibc) echo "gnu" ;;
|
|
musl) echo "musl" ;;
|
|
auto)
|
|
if command -v ldd >/dev/null 2>&1; then
|
|
if ldd --version 2>&1 | grep -qi musl; then
|
|
echo "musl"
|
|
return 0
|
|
fi
|
|
fi
|
|
if [[ -e /lib/ld-musl-x86_64.so.1 || -e /lib/ld-musl-aarch64.so.1 ]]; then
|
|
echo "musl"
|
|
return 0
|
|
fi
|
|
if command -v getconf >/dev/null 2>&1 && getconf GNU_LIBC_VERSION >/dev/null 2>&1; then
|
|
echo "gnu"
|
|
return 0
|
|
fi
|
|
echo "gnu"
|
|
;;
|
|
*) die "invalid DCRUP_LIBC / --libc: $pref (use gnu|musl|auto)" ;;
|
|
esac
|
|
}
|
|
|
|
detect_triple() {
|
|
local os arch libc
|
|
os="$(uname -s)"
|
|
arch="$(uname -m)"
|
|
case "$os:$arch" in
|
|
Linux:x86_64)
|
|
libc="$(detect_linux_libc)"
|
|
if [[ "$libc" == "musl" ]]; then
|
|
echo "x86_64-unknown-linux-musl"
|
|
else
|
|
echo "x86_64-unknown-linux-gnu"
|
|
fi
|
|
;;
|
|
Linux:aarch64|Linux:arm64)
|
|
libc="$(detect_linux_libc)"
|
|
if [[ "$libc" == "musl" ]]; then
|
|
echo "aarch64-unknown-linux-musl"
|
|
else
|
|
echo "aarch64-unknown-linux-gnu"
|
|
fi
|
|
;;
|
|
Linux:i686|Linux:i386)
|
|
libc="$(detect_linux_libc)"
|
|
if [[ "$libc" == "musl" ]]; then
|
|
echo "i686-unknown-linux-musl"
|
|
else
|
|
echo "i686-unknown-linux-gnu"
|
|
fi
|
|
;;
|
|
Linux:armv7l|Linux:armv7)
|
|
libc="$(detect_linux_libc)"
|
|
if [[ "$libc" == "musl" ]]; then
|
|
echo "armv7-unknown-linux-musleabihf"
|
|
else
|
|
echo "armv7-unknown-linux-gnueabihf"
|
|
fi
|
|
;;
|
|
Linux:riscv64)
|
|
libc="$(detect_linux_libc)"
|
|
if [[ "$libc" == "musl" ]]; then
|
|
echo "riscv64gc-unknown-linux-musl"
|
|
else
|
|
echo "riscv64gc-unknown-linux-gnu"
|
|
fi
|
|
;;
|
|
Darwin:x86_64) echo "x86_64-apple-darwin" ;;
|
|
Darwin:arm64|Darwin:aarch64) echo "aarch64-apple-darwin" ;;
|
|
FreeBSD:x86_64|FreeBSD:amd64) echo "x86_64-unknown-freebsd" ;;
|
|
FreeBSD:aarch64|FreeBSD:arm64) echo "aarch64-unknown-freebsd" ;;
|
|
OpenBSD:x86_64|OpenBSD:amd64) echo "x86_64-unknown-openbsd" ;;
|
|
NetBSD:x86_64|NetBSD:amd64) echo "x86_64-unknown-netbsd" ;;
|
|
MINGW*|MSYS*|CYGWIN*)
|
|
case "$arch" in
|
|
x86_64|amd64) echo "x86_64-pc-windows-gnu" ;;
|
|
aarch64|arm64) echo "aarch64-pc-windows-gnullvm" ;;
|
|
i686|i386) echo "i686-pc-windows-gnu" ;;
|
|
*) die "unsupported Windows arch under MSYS: $arch" ;;
|
|
esac
|
|
;;
|
|
*) die "unsupported platform: $os/$arch" ;;
|
|
esac
|
|
}
|
|
|
|
normalize_version() {
|
|
local v="$1"
|
|
v="${v#v}"
|
|
printf '%s' "$v"
|
|
}
|
|
|
|
parse_spec() {
|
|
local raw="$1"
|
|
SPEC_RAW="$raw"
|
|
SPEC_CHANNEL=""
|
|
SPEC_VERSION=""
|
|
SPEC_FLOATING=0
|
|
|
|
case "$raw" in
|
|
"") die "missing version/channel spec" ;;
|
|
stable|dev|night)
|
|
SPEC_CHANNEL="$raw"
|
|
SPEC_VERSION=""
|
|
SPEC_FLOATING=1
|
|
;;
|
|
*@*)
|
|
SPEC_VERSION="$(normalize_version "${raw%@*}")"
|
|
SPEC_CHANNEL="${raw#*@}"
|
|
case "$SPEC_CHANNEL" in
|
|
stable|dev) ;;
|
|
night) die "cannot pin a version on night (use: dcrup install night)" ;;
|
|
*) die "unknown channel in spec: $SPEC_CHANNEL (use stable|dev)" ;;
|
|
esac
|
|
[[ -n "$SPEC_VERSION" ]] || die "empty version in spec: $raw"
|
|
;;
|
|
*)
|
|
SPEC_VERSION="$(normalize_version "$raw")"
|
|
SPEC_CHANNEL="stable"
|
|
[[ -n "$SPEC_VERSION" ]] || die "invalid spec: $raw"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
toolchain_id() {
|
|
if [[ "$SPEC_CHANNEL" == "night" ]]; then
|
|
local sha="${1:-unknown}"
|
|
echo "night-${sha}"
|
|
elif [[ "$SPEC_FLOATING" -eq 1 ]]; then
|
|
local ver="${1:-latest}"
|
|
echo "${SPEC_CHANNEL}-${ver}"
|
|
else
|
|
echo "${SPEC_VERSION}-${SPEC_CHANNEL}"
|
|
fi
|
|
}
|
|
|
|
ensure_dirs() {
|
|
mkdir -p "$DCRUP_TC" "$DCRUP_BIN" "$DCRUP_META"
|
|
}
|
|
|
|
active_file() { echo "$DCRUP_META/active"; }
|
|
|
|
read_active() {
|
|
if [[ -f "$(active_file)" ]]; then
|
|
cat "$(active_file)"
|
|
fi
|
|
}
|
|
|
|
write_active() {
|
|
printf '%s\n' "$1" >"$(active_file)"
|
|
}
|
|
|
|
link_default() {
|
|
local id="$1"
|
|
local src="$DCRUP_TC/$id/dcr"
|
|
[[ -x "$src" ]] || die "toolchain not installed: $id"
|
|
ln -sfn "$src" "$DCRUP_BIN/dcr"
|
|
write_active "$id"
|
|
ok "default → $id ($DCRUP_BIN/dcr)"
|
|
}
|
|
|
|
fetch_json() {
|
|
need_cmd curl
|
|
curl -fsSL "$1"
|
|
}
|
|
|
|
json_tag() {
|
|
printf '%s' "$1" | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n1
|
|
}
|
|
|
|
set_mirror() {
|
|
case "$1" in
|
|
auto|cf|gh|sf|ya) DCRUP_MIRROR="$1" ;;
|
|
*) die "invalid --mirror: $1 (use auto|cf|gh|sf|ya)" ;;
|
|
esac
|
|
}
|
|
|
|
mirror_url() {
|
|
local mirror="$1" tag="$2" asset="$3"
|
|
case "$mirror" in
|
|
cf) printf 'https://cdn-global.dcr-tool.ru/%s/%s' "$tag" "$asset" ;;
|
|
gh) printf 'https://github.com/dexoron/dcr/releases/download/%s/%s' "$tag" "$asset" ;;
|
|
sf) printf 'https://sourceforge.net/projects/dcr-tool/files/%s/%s/download' "$tag" "$asset" ;;
|
|
ya) printf 'https://cdn-ru.dcr-tool.ru/%s/%s' "$tag" "$asset" ;;
|
|
*) return 1 ;;
|
|
esac
|
|
}
|
|
|
|
mirror_chain() { echo "cf gh sf ya"; }
|
|
|
|
mirrors_to_try() {
|
|
case "$DCRUP_MIRROR" in
|
|
auto) mirror_chain ;;
|
|
cf|gh|sf|ya) echo "$DCRUP_MIRROR" ;;
|
|
*) die "invalid mirror: $DCRUP_MIRROR (use auto|cf|gh|sf|ya)" ;;
|
|
esac
|
|
}
|
|
|
|
download_from_mirrors() {
|
|
local tag="$1" asset="$2" dest="$3"
|
|
local tmp="$dest/dcr.download" m url size
|
|
USED_MIRROR=""
|
|
for m in $(mirrors_to_try); do
|
|
url="$(mirror_url "$m" "$tag" "$asset")"
|
|
log "trying mirror $m …"
|
|
rm -f "$tmp"
|
|
if curl -fL --retry 2 --retry-delay 1 --connect-timeout 10 --max-time 180 \
|
|
-A "dcrup" "$url" -o "$tmp"; then
|
|
size="$(wc -c <"$tmp" | tr -d ' ')"
|
|
if [[ "${size:-0}" -gt 100000 ]]; then
|
|
mv "$tmp" "$dest/dcr"
|
|
USED_MIRROR="$m"
|
|
return 0
|
|
fi
|
|
warn "mirror $m returned a too-small file (${size:-0} bytes)"
|
|
else
|
|
warn "mirror $m failed"
|
|
fi
|
|
rm -f "$tmp"
|
|
done
|
|
return 1
|
|
}
|
|
|
|
latest_stable_json() {
|
|
fetch_json "$API_LATEST"
|
|
}
|
|
|
|
latest_dev_json() {
|
|
need_cmd curl
|
|
local json result
|
|
json="$(fetch_json "$API_ALL")"
|
|
if command -v jq >/dev/null 2>&1; then
|
|
result="$(printf '%s' "$json" | jq -e -c '[.[] | select(.prerelease == true)][0]')" || true
|
|
elif command -v python3 >/dev/null 2>&1; then
|
|
result="$(printf '%s' "$json" | python3 -c '
|
|
import sys, json
|
|
rels = json.load(sys.stdin)
|
|
pre = [r for r in rels if r.get("prerelease")]
|
|
print(json.dumps(pre[0]) if pre else "", end="")
|
|
')"
|
|
else
|
|
die "dev channel needs jq or python3 to parse GitHub API"
|
|
fi
|
|
[[ -n "$result" && "$result" != "null" ]] || die "no prerelease (dev) found"
|
|
printf '%s' "$result"
|
|
}
|
|
|
|
release_json_for_spec() {
|
|
if [[ "$SPEC_FLOATING" -eq 1 ]]; then
|
|
case "$SPEC_CHANNEL" in
|
|
stable) latest_stable_json ;;
|
|
dev) latest_dev_json ;;
|
|
night) die "night has no GitHub release binary" ;;
|
|
esac
|
|
else
|
|
fetch_json "https://api.github.com/repos/dexoron/dcr/releases/tags/v${SPEC_VERSION}"
|
|
fi
|
|
}
|
|
|
|
install_prebuilt() {
|
|
local triple asset tag version id dest mirror
|
|
need_cmd curl
|
|
triple="$(detect_triple)"
|
|
json="$(release_json_for_spec)"
|
|
tag="$(json_tag "$json")"
|
|
[[ -n "$tag" ]] || die "failed to parse release tag"
|
|
version="$(normalize_version "$tag")"
|
|
asset="dcr-${triple}-${version}"
|
|
case "$triple" in
|
|
*windows*) asset="${asset}.exe" ;;
|
|
esac
|
|
|
|
id="$(toolchain_id "$version")"
|
|
dest="$DCRUP_TC/$id"
|
|
if [[ -x "$dest/dcr" && "${FORCE:-0}" != "1" ]]; then
|
|
ok "already installed: $id"
|
|
link_default "$id"
|
|
return 0
|
|
fi
|
|
|
|
mkdir -p "$dest"
|
|
log "downloading $asset (mirror=$DCRUP_MIRROR) …"
|
|
download_from_mirrors "$tag" "$asset" "$dest" \
|
|
|| die "no mirror reachable for $asset (try: --mirror cf|gh|sf|ya)"
|
|
mirror="$USED_MIRROR"
|
|
log "mirror → $mirror"
|
|
chmod +x "$dest/dcr"
|
|
printf '%s\n' \
|
|
"channel=$SPEC_CHANNEL" \
|
|
"version=$version" \
|
|
"tag=$tag" \
|
|
"source=release" \
|
|
"triple=$triple" \
|
|
"mirror=$mirror" \
|
|
"libc=${DCRUP_LIBC:-gnu}" \
|
|
>"$dest/dcrup-meta"
|
|
ok "installed prebuilt $id ($triple via $mirror)"
|
|
link_default "$id"
|
|
}
|
|
|
|
install_build() {
|
|
local tmp id dest sha version branch_or_tag
|
|
need_cmd git
|
|
need_cmd cargo
|
|
|
|
tmp="$(mktemp -d "${TMPDIR:-/tmp}/dcrup.XXXXXX")"
|
|
cleanup_tmp() { rm -rf "$tmp"; }
|
|
trap cleanup_tmp EXIT
|
|
|
|
if [[ "$SPEC_CHANNEL" == "night" ]]; then
|
|
log "cloning $REPO_URL (branch dev) for night …"
|
|
git clone --depth 1 --branch dev "$REPO_URL" "$tmp/src" 2>/dev/null \
|
|
|| git clone --depth 1 "$REPO_URL" "$tmp/src"
|
|
sha="$(git -C "$tmp/src" rev-parse --short HEAD)"
|
|
version="night"
|
|
id="$(toolchain_id "$sha")"
|
|
elif [[ "$SPEC_FLOATING" -eq 1 ]]; then
|
|
local json tag
|
|
json="$(release_json_for_spec)"
|
|
tag="$(json_tag "$json")"
|
|
[[ -n "$tag" ]] || die "failed to resolve floating channel tag"
|
|
version="$(normalize_version "$tag")"
|
|
id="$(toolchain_id "$version")"
|
|
log "cloning $REPO_URL @ $tag …"
|
|
git clone --depth 1 --branch "$tag" "$REPO_URL" "$tmp/src" 2>/dev/null \
|
|
|| {
|
|
git clone --depth 1 "$REPO_URL" "$tmp/src"
|
|
git -C "$tmp/src" fetch --depth 1 origin "refs/tags/${tag}:refs/tags/${tag}"
|
|
git -C "$tmp/src" checkout "$tag"
|
|
}
|
|
sha="$(git -C "$tmp/src" rev-parse --short HEAD)"
|
|
else
|
|
version="$SPEC_VERSION"
|
|
id="$(toolchain_id)"
|
|
local tag="v${SPEC_VERSION}"
|
|
log "cloning $REPO_URL @ $tag …"
|
|
git clone --depth 1 --branch "$tag" "$REPO_URL" "$tmp/src" 2>/dev/null \
|
|
|| {
|
|
git clone --depth 1 "$REPO_URL" "$tmp/src"
|
|
git -C "$tmp/src" fetch --depth 1 origin "refs/tags/${tag}:refs/tags/${tag}"
|
|
git -C "$tmp/src" checkout "$tag"
|
|
}
|
|
sha="$(git -C "$tmp/src" rev-parse --short HEAD)"
|
|
fi
|
|
|
|
dest="$DCRUP_TC/$id"
|
|
if [[ -x "$dest/dcr" && "${FORCE:-0}" != "1" ]]; then
|
|
ok "already installed: $id"
|
|
link_default "$id"
|
|
return 0
|
|
fi
|
|
|
|
log "building release (features: $FEATURES) …"
|
|
(
|
|
cd "$tmp/src"
|
|
# shellcheck disable=SC2086
|
|
cargo build --release --features $FEATURES
|
|
)
|
|
mkdir -p "$dest"
|
|
cp "$tmp/src/target/release/dcr" "$dest/dcr"
|
|
chmod +x "$dest/dcr"
|
|
printf '%s\n' "channel=$SPEC_CHANNEL" "version=$version" "git=$sha" "source=build" "features=$FEATURES" >"$dest/dcrup-meta"
|
|
ok "installed build $id"
|
|
link_default "$id"
|
|
trap - EXIT
|
|
cleanup_tmp
|
|
}
|
|
|
|
cmd_install() {
|
|
local mode="release" FORCE=0
|
|
local spec=""
|
|
local libc_cli=""
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--build) mode="build"; shift ;;
|
|
--release) mode="release"; shift ;;
|
|
--force) FORCE=1; shift ;;
|
|
--libc)
|
|
[[ $# -ge 2 ]] || die "--libc needs gnu|musl|auto"
|
|
libc_cli="$2"
|
|
shift 2
|
|
;;
|
|
--libc=*)
|
|
libc_cli="${1#--libc=}"
|
|
shift
|
|
;;
|
|
--mirror)
|
|
[[ $# -ge 2 ]] || die "--mirror needs auto|cf|gh|sf|ya"
|
|
set_mirror "$2"
|
|
shift 2
|
|
;;
|
|
--mirror=*)
|
|
set_mirror "${1#--mirror=}"
|
|
shift
|
|
;;
|
|
-h|--help) usage; exit 0 ;;
|
|
-*) die "unknown flag: $1" ;;
|
|
*)
|
|
[[ -z "$spec" ]] || die "unexpected argument: $1"
|
|
spec="$1"
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
[[ -n "$spec" ]] || die "usage: dcrup install <spec> [--build|--release] [--force] [--libc gnu|musl|auto] [--mirror auto|cf|gh|sf|ya]"
|
|
parse_spec "$spec"
|
|
ensure_dirs
|
|
|
|
if [[ -n "$libc_cli" ]]; then
|
|
case "$libc_cli" in
|
|
gnu|glibc|musl|auto) DCRUP_LIBC="$libc_cli" ;;
|
|
*) die "invalid --libc: $libc_cli (use gnu|musl|auto)" ;;
|
|
esac
|
|
fi
|
|
export DCRUP_LIBC="${DCRUP_LIBC:-gnu}"
|
|
|
|
if [[ "$SPEC_CHANNEL" == "night" ]]; then
|
|
mode="build"
|
|
fi
|
|
|
|
export FORCE
|
|
log "install spec=$SPEC_RAW channel=$SPEC_CHANNEL version=${SPEC_VERSION:-∅} mode=$mode libc=$DCRUP_LIBC mirror=$DCRUP_MIRROR"
|
|
if [[ "$mode" == "build" ]]; then
|
|
install_build
|
|
else
|
|
install_prebuilt
|
|
fi
|
|
check_path
|
|
}
|
|
|
|
cmd_default() {
|
|
[[ $# -eq 1 ]] || die "usage: dcrup default <spec>"
|
|
parse_spec "$1"
|
|
ensure_dirs
|
|
local id
|
|
if [[ "$SPEC_CHANNEL" == "night" || "$SPEC_FLOATING" -eq 1 ]]; then
|
|
id="$(ls -1 "$DCRUP_TC" 2>/dev/null | grep -E "^${SPEC_CHANNEL}-" | sort | tail -n1 || true)"
|
|
[[ -n "$id" ]] || die "no installed toolchain for channel $SPEC_CHANNEL (run: dcrup install $SPEC_CHANNEL)"
|
|
else
|
|
id="$(toolchain_id)"
|
|
[[ -d "$DCRUP_TC/$id" ]] || die "not installed: $id (run: dcrup install $1)"
|
|
fi
|
|
link_default "$id"
|
|
}
|
|
|
|
cmd_update() {
|
|
ensure_dirs
|
|
local active
|
|
active="$(read_active)"
|
|
[[ -n "$active" ]] || die "no active toolchain (run: dcrup install stable)"
|
|
case "$active" in
|
|
night-*)
|
|
log "updating night (rebuild HEAD) …"
|
|
FORCE=1 cmd_install night --build --force
|
|
;;
|
|
stable-*|dev-*)
|
|
local ch="${active%%-*}"
|
|
log "updating floating channel $ch …"
|
|
FORCE=1 cmd_install "$ch" --force
|
|
;;
|
|
*-stable|*-dev)
|
|
ok "pinned toolchain $active — not floating; install a newer version explicitly"
|
|
;;
|
|
*)
|
|
warn "unknown active id $active; try: dcrup install stable"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
cmd_list() {
|
|
ensure_dirs
|
|
local active
|
|
active="$(read_active)"
|
|
if [[ ! -d "$DCRUP_TC" ]] || [[ -z "$(ls -A "$DCRUP_TC" 2>/dev/null || true)" ]]; then
|
|
warn "no toolchains installed"
|
|
return 0
|
|
fi
|
|
local d base
|
|
for d in "$DCRUP_TC"/*; do
|
|
[[ -d "$d" ]] || continue
|
|
base="$(basename "$d")"
|
|
if [[ "$base" == "$active" ]]; then
|
|
printf ' * %s\n' "$base"
|
|
else
|
|
printf ' %s\n' "$base"
|
|
fi
|
|
done
|
|
}
|
|
|
|
cmd_show() {
|
|
ensure_dirs
|
|
local active
|
|
active="$(read_active)"
|
|
echo "DCRUP_HOME=$DCRUP_HOME"
|
|
echo "DCRUP_BIN=$DCRUP_BIN"
|
|
echo "active=${active:-none}"
|
|
if [[ -n "$active" && -f "$DCRUP_TC/$active/dcrup-meta" ]]; then
|
|
echo "--- meta ---"
|
|
cat "$DCRUP_TC/$active/dcrup-meta"
|
|
fi
|
|
if [[ -x "$DCRUP_BIN/dcr" ]]; then
|
|
echo "--- dcr --version ---"
|
|
"$DCRUP_BIN/dcr" --version 2>/dev/null || true
|
|
fi
|
|
}
|
|
|
|
cmd_which() {
|
|
if [[ -L "$DCRUP_BIN/dcr" || -e "$DCRUP_BIN/dcr" ]]; then
|
|
readlink -f "$DCRUP_BIN/dcr" 2>/dev/null || readlink "$DCRUP_BIN/dcr" 2>/dev/null || echo "$DCRUP_BIN/dcr"
|
|
else
|
|
die "dcr not linked (run: dcrup install stable)"
|
|
fi
|
|
}
|
|
|
|
cmd_uninstall() {
|
|
ensure_dirs
|
|
if [[ "${1:-}" == "--all" ]]; then
|
|
rm -rf "$DCRUP_TC"
|
|
rm -f "$DCRUP_BIN/dcr" "$(active_file)"
|
|
ok "removed all toolchains"
|
|
return 0
|
|
fi
|
|
[[ $# -eq 1 ]] || die "usage: dcrup uninstall <spec>|--all"
|
|
parse_spec "$1"
|
|
local id
|
|
if [[ "$SPEC_FLOATING" -eq 1 || "$SPEC_CHANNEL" == "night" ]]; then
|
|
id="$(ls -1 "$DCRUP_TC" 2>/dev/null | grep -E "^${SPEC_CHANNEL}-" | sort | tail -n1 || true)"
|
|
else
|
|
id="$(toolchain_id)"
|
|
fi
|
|
[[ -n "$id" && -d "$DCRUP_TC/$id" ]] || die "not installed: $1"
|
|
rm -rf "$DCRUP_TC/$id"
|
|
if [[ "$(read_active)" == "$id" ]]; then
|
|
rm -f "$DCRUP_BIN/dcr" "$(active_file)"
|
|
warn "removed active toolchain; run: dcrup install stable"
|
|
fi
|
|
ok "removed $id"
|
|
}
|
|
|
|
check_path() {
|
|
case ":$PATH:" in
|
|
*":$DCRUP_BIN:"*) ;;
|
|
*)
|
|
warn "$DCRUP_BIN is not in PATH"
|
|
echo "Add to ~/.bashrc / ~/.zshrc / ~/.profile:"
|
|
echo " export PATH=\"$DCRUP_BIN:\$PATH\""
|
|
;;
|
|
esac
|
|
}
|
|
|
|
cmd_self_install() {
|
|
local dest="$DCRUP_BIN"
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--to) dest="$2"; shift 2 ;;
|
|
*) die "usage: dcrup self-install [--to DIR]" ;;
|
|
esac
|
|
done
|
|
ensure_dirs
|
|
mkdir -p "$dest"
|
|
local self
|
|
self="$(readlink -f "$0" 2>/dev/null || realpath "$0" 2>/dev/null || echo "$0")"
|
|
cp "$self" "$dest/dcrup"
|
|
chmod +x "$dest/dcrup"
|
|
ok "dcrup installed to $dest/dcrup"
|
|
check_path
|
|
echo "Then: dcrup install stable"
|
|
}
|
|
|
|
main() {
|
|
local cmd="${1:-}"
|
|
shift || true
|
|
case "$cmd" in
|
|
""|-h|--help|help) usage ;;
|
|
install) cmd_install "$@" ;;
|
|
default) cmd_default "$@" ;;
|
|
update) cmd_update "$@" ;;
|
|
list) cmd_list "$@" ;;
|
|
show) cmd_show "$@" ;;
|
|
which) cmd_which "$@" ;;
|
|
uninstall) cmd_uninstall "$@" ;;
|
|
self-install) cmd_self_install "$@" ;;
|
|
*) die "unknown command: $cmd (try: dcrup help)" ;;
|
|
esac
|
|
}
|
|
|
|
main "$@"
|