diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a1661d9..cacb427 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1312,4 +1312,18 @@ jobs: aws s3 sync dist/ "s3://${{ secrets.S3_BUCKET_NAME }}/${TAG}/" \ --endpoint-url https://storage.yandexcloud.net \ - --region ru-central1 \ No newline at end of file + --region ru-central1 + + - name: Upload Everything to Cloudflare R2 + env: + AWS_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }} + AWS_EC2_METADATA_DISABLED: true + shell: bash + run: | + set -euo pipefail + TAG="${{ needs.setup.outputs.tag }}" + + aws s3 sync dist/ "s3://${{ secrets.R2_BUCKET_NAME }}/${TAG}/" \ + --endpoint-url https://${{ secrets.R2_ACCOUNT_ID }}.r2.cloudflarestorage.com \ + --region auto \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 09c18b7..703e324 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ # Changelog +## [Unreleased] + +### RU + +**Добавлено:** + +- **Зеркала загрузок в `dcrup`** — `--mirror auto|cf|gh|sf|ya` и `DCRUP_MIRROR`. + По умолчанию `auto`: **cf → gh → sf → ya** (CloudFlare CDN, GitHub, SourceForge, Yandex CDN). + +**Удалено:** + +- **`install.sh` / `install.ps1` / `install_bsd.sh`** — устарели, заменены `dcrup`. + +### EN + +**Added:** + +- **Download mirrors in `dcrup`** — `--mirror auto|cf|gh|sf|ya` and `DCRUP_MIRROR`. + Default `auto` tries **cf → gh → sf → ya** (CloudFlare CDN, GitHub, SourceForge, Yandex CDN). + +**Removed:** + +- **`install.sh` / `install.ps1` / `install_bsd.sh`** — superseded by `dcrup`. + ## [v0.8.5] - 2026-08-08 "Фиксация версии dcr-version и предупреждения совместимости / Config Version Pinning & Compatibility Warnings" ### RU diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 44b179a..1934ac8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,6 +11,7 @@ Thanks for your interest in the project. ```bash git clone https://github.com/dexoron/dcr.git +# or a source mirror: GitVerse / SourceCraft / SourceForge / GitLab (see README) cd dcr cargo check ``` diff --git a/FAQ.md b/FAQ.md index 66e3d26..3a48470 100644 --- a/FAQ.md +++ b/FAQ.md @@ -61,8 +61,19 @@ Available installation methods may vary by project version. Recommended path: - check instructions in `README.md`; +- use `dcrup install stable` (default mirror chain: **cf → gh → sf → ya**); +- pin a host with `--mirror cf|gh|sf|ya` or `DCRUP_MIRROR` if needed; - if there is no prebuilt package for your platform, build from source using `cargo build --release`. +## How do I choose a download mirror? + +`dcrup` defaults to `--mirror auto`: CloudFlare CDN, then GitHub, then SourceForge, then Yandex CDN. + +```sh +dcrup install stable --mirror cf +export DCRUP_MIRROR=ya +``` + ## How can I get started quickly? Minimal workflow: diff --git a/README.md b/README.md index ca86bf0..806a8e7 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,9 @@ cargo install dcr ```sh curl -fsSL https://sh.dcr-tool.ru | sh -s -- self-install export PATH="$HOME/.dcr/bin:$PATH" -dcrup install stable +dcrup install stable # auto: cf → gh → sf → ya +# dcrup install stable --mirror cf # CloudFlare CDN +# dcrup install stable --mirror ya # Yandex CDN (RU) ``` @@ -98,7 +100,9 @@ irm https://ps1.dcr-tool.ru | iex # irm https://ps1.dcr-tool.ru -OutFile dcrup.ps1 # powershell -File .\dcrup.ps1 self-install # $env:Path += ";$env:USERPROFILE\.dcr\bin" -dcrup install stable +dcrup install stable # auto: cf → gh → sf → ya +# dcrup install stable --mirror cf # CloudFlare CDN +# dcrup install stable --mirror ya # Yandex CDN (RU) ``` @@ -218,14 +222,25 @@ Full docs at **[dcr.dexoron.su](https://dcr.dexoron.su)** or in the [`docs/`](do ## Repository Mirrors -The primary repository is hosted on GitHub. The following mirrors are available for source code and releases: +The primary repository is hosted on GitHub. Source and release mirrors: | Region | Mirror | Contents | |---|---|---| -| Russia | [GitVerse](https://gitverse.ru/dcr_labs/dcr) **(recommended)** | Source code | +| Worldwide | [GitHub](https://github.com/dexoron/dcr) | Source code and releases | +| Worldwide | [SourceForge](https://sourceforge.net/projects/dcr-tool/) | Source code and releases | +| Russia | [GitVerse](https://gitverse.ru/dcr_labs/dcr) | Source code | | Russia | [SourceCraft](https://sourcecraft.dev/dexoron-dev/dcr) | Source code | -| Worldwide | [SourceForge](https://sourceforge.net/projects/dcr-tool/) **(recommended)** | Source code and releases | -| Worldwide | [GitLab](https://gitlab.com/dexoron-dev/dcr-tool/dcr) | Source code and releases | + +Release CDN (used by `dcrup`): + +| Code | Host | Role | +|---|---|---| +| `cf` | [cdn-global.dcr-tool.ru](https://cdn-global.dcr-tool.ru) (CloudFlare) | Worldwide CDN | +| `gh` | GitHub Releases | Primary host | +| `sf` | SourceForge | Worldwide fallback | +| `ya` | [cdn-ru.dcr-tool.ru](https://cdn-ru.dcr-tool.ru) (Yandex) | Paid RU fallback for restrictions | + +`dcrup install` defaults to `--mirror auto` and tries **cf → gh → sf → ya**. Override with `--mirror cf|gh|sf|ya` or `DCRUP_MIRROR`. --- diff --git a/dcrup.ps1 b/dcrup.ps1 index a02786e..094b9a9 100644 --- a/dcrup.ps1 +++ b/dcrup.ps1 @@ -6,6 +6,7 @@ $DcrupBin = if ($env:DCRUP_BIN) { $env:DCRUP_BIN } else { Join-Path $DcrupHom $DcrupTc = Join-Path $DcrupHome 'toolchains' $DcrupMeta = Join-Path $DcrupHome 'meta' $RepoUrl = if ($env:DCRUP_REPO) { $env:DCRUP_REPO } else { 'https://github.com/dexoron/dcr' } +$DcrupMirror = if ($env:DCRUP_MIRROR) { $env:DCRUP_MIRROR } else { 'auto' } $ApiLatest = 'https://api.github.com/repos/dexoron/dcr/releases/latest' $ApiAll = 'https://api.github.com/repos/dexoron/dcr/releases' $Features = if ($env:DCR_FEATURES) { $env:DCR_FEATURES } else { 'archive' } @@ -20,7 +21,7 @@ function Show-Usage { dcrup — install and switch DCR versions (Windows) Usage: - dcrup install [--build|--release] [--force] + dcrup install [--build|--release] [--force] [--mirror auto|cf|gh|sf|ya] dcrup default dcrup update dcrup list @@ -38,15 +39,24 @@ Spec: night → always build from branch "dev" HEAD Modes: - --release download GitHub Release binary (default for stable/dev) + --release download prebuilt binary (default for stable/dev) --build cargo build --release --features archive night always --build (prebuilt not available) +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_MIRROR auto|cf|gh|sf|ya (default: auto) '@ | Write-Host } @@ -123,6 +133,53 @@ function Link-Default([string]$id) { Ok "default → $id ($dst)" } +function Set-Mirror([string]$value) { + if ($value -notin @('auto', 'cf', 'gh', 'sf', 'ya')) { + Die "invalid --mirror: $value (use auto|cf|gh|sf|ya)" + } + $script:DcrupMirror = $value +} + +function Get-MirrorUrl([string]$mirror, [string]$tag, [string]$asset) { + switch ($mirror) { + 'cf' { return "https://cdn-global.dcr-tool.ru/$tag/$asset" } + 'gh' { return "https://github.com/dexoron/dcr/releases/download/$tag/$asset" } + 'sf' { return "https://sourceforge.net/projects/dcr-tool/files/$tag/$asset/download" } + 'ya' { return "https://cdn-ru.dcr-tool.ru/$tag/$asset" } + default { Die "invalid mirror: $mirror" } + } +} + +function Get-MirrorsToTry { + switch ($script:DcrupMirror) { + 'auto' { return @('cf', 'gh', 'sf', 'ya') } + { $_ -in @('cf', 'gh', 'sf', 'ya') } { return @($script:DcrupMirror) } + default { Die "invalid mirror: $($script:DcrupMirror) (use auto|cf|gh|sf|ya)" } + } +} + +function Download-FromMirrors([string]$tag, [string]$asset, [string]$destFile) { + $tmp = "$destFile.download" + foreach ($m in (Get-MirrorsToTry)) { + $url = Get-MirrorUrl $m $tag $asset + Info "trying mirror $m …" + Remove-Item $tmp -ErrorAction SilentlyContinue + try { + Invoke-WebRequest -Uri $url -OutFile $tmp -UserAgent 'dcrup' + $size = (Get-Item $tmp).Length + if ($size -gt 100000) { + Move-Item $tmp $destFile -Force + return $m + } + Warn "mirror $m returned a too-small file ($size bytes)" + } catch { + Warn "mirror $m failed" + } + Remove-Item $tmp -ErrorAction SilentlyContinue + } + return $null +} + function Fetch-Release($channel, $version) { if ($version) { return Invoke-RestMethod -Uri "https://api.github.com/repos/dexoron/dcr/releases/tags/v$version" @@ -142,8 +199,6 @@ function Install-Prebuilt([switch]$Force) { $tag = $rel.tag_name $ver = Normalize-Version $tag $assetName = "dcr-$triple-$ver.exe" - $asset = $rel.assets | Where-Object { $_.name -eq $assetName } | Select-Object -First 1 - if (-not $asset) { Die "asset not found: $assetName" } $id = if ($script:SpecFloating) { Toolchain-Id $ver } else { Toolchain-Id } $dest = Join-Path $DcrupTc $id @@ -155,16 +210,19 @@ function Install-Prebuilt([switch]$Force) { } Ensure-Dirs New-Item -ItemType Directory -Force -Path $dest | Out-Null - Info "downloading $assetName …" - Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $bin + Info "downloading $assetName (mirror=$($script:DcrupMirror)) …" + $mirror = Download-FromMirrors $tag $assetName $bin + if (-not $mirror) { Die "no mirror reachable for $assetName (try: --mirror cf|gh|sf|ya)" } + Info "mirror → $mirror" @" channel=$($script:SpecChannel) version=$ver tag=$tag source=release triple=$triple +mirror=$mirror "@ | Set-Content (Join-Path $dest 'dcrup-meta') - Ok "installed prebuilt $id" + Ok "installed prebuilt $id ($triple via $mirror)" Link-Default $id } @@ -270,23 +328,32 @@ function Cmd-Install { $mode = 'release' $force = $false $spec = $null - foreach ($a in $Args) { + $i = 0 + while ($i -lt $Args.Count) { + $a = $Args[$i] switch -Regex ($a) { - '^--build$' { $mode = 'build'; continue } - '^--release$' { $mode = 'release'; continue } - '^--force$' { $force = $true; continue } + '^--build$' { $mode = 'build' } + '^--release$' { $mode = 'release' } + '^--force$' { $force = $true } + '^--mirror$' { + if ($i + 1 -ge $Args.Count) { Die '--mirror needs auto|cf|gh|sf|ya' } + $i++ + Set-Mirror $Args[$i] + } + '^--mirror=(.+)$' { Set-Mirror $Matches[1] } '^-' { Die "unknown flag: $a" } default { if ($spec) { Die "unexpected: $a" } $spec = $a } } + $i++ } - if (-not $spec) { Die 'usage: dcrup install [--build|--release] [--force]' } + if (-not $spec) { Die 'usage: dcrup install [--build|--release] [--force] [--mirror auto|cf|gh|sf|ya]' } Parse-Spec $spec Ensure-Dirs if ($script:SpecChannel -eq 'night') { $mode = 'build' } - Info "install spec=$spec channel=$($script:SpecChannel) mode=$mode" + Info "install spec=$spec channel=$($script:SpecChannel) mode=$mode mirror=$($script:DcrupMirror)" if ($mode -eq 'build') { Install-Build -Force:$force } else { Install-Prebuilt -Force:$force } Ensure-UserPath Install-CmdShim diff --git a/dcrup.sh b/dcrup.sh index 33cc7e4..7f0bc7a 100755 --- a/dcrup.sh +++ b/dcrup.sh @@ -6,6 +6,7 @@ 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}" @@ -26,7 +27,7 @@ usage() { dcrup — install and switch DCR versions Usage: - dcrup install [--build|--release] [--force] [--libc gnu|musl|auto] + dcrup install [--build|--release] [--force] [--libc gnu|musl|auto] [--mirror auto|cf|gh|sf|ya] dcrup default dcrup update dcrup list @@ -44,7 +45,7 @@ Spec: night → always build from branch "dev" HEAD Modes: - --release download GitHub Release binary (default for stable/dev) + --release download prebuilt binary (default for stable/dev) --build cargo build --release --features archive night always --build (prebuilt not available) @@ -53,12 +54,21 @@ Linux libc (prebuilt triple only): --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 } @@ -239,9 +249,57 @@ json_tag() { printf '%s' "$1" | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n1 } -json_asset_url() { - local json="$1" asset="$2" - printf '%s' "$json" | sed -n "s#.*\"browser_download_url\"[[:space:]]*:[[:space:]]*\"\([^\"]*/${asset}\)\"#\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() { @@ -281,7 +339,7 @@ release_json_for_spec() { } install_prebuilt() { - local triple asset tag version url json id dest + local triple asset tag version id dest mirror need_cmd curl triple="$(detect_triple)" json="$(release_json_for_spec)" @@ -292,8 +350,6 @@ install_prebuilt() { case "$triple" in *windows*) asset="${asset}.exe" ;; esac - url="$(json_asset_url "$json" "$asset")" - [[ -n "$url" ]] || die "asset not found: $asset (tag $tag)" id="$(toolchain_id "$version")" dest="$DCRUP_TC/$id" @@ -303,9 +359,12 @@ install_prebuilt() { return 0 fi - log "downloading $asset …" mkdir -p "$dest" - curl -fL "$url" -o "$dest/dcr" + 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" \ @@ -313,9 +372,10 @@ install_prebuilt() { "tag=$tag" \ "source=release" \ "triple=$triple" \ + "mirror=$mirror" \ "libc=${DCRUP_LIBC:-gnu}" \ >"$dest/dcrup-meta" - ok "installed prebuilt $id ($triple)" + ok "installed prebuilt $id ($triple via $mirror)" link_default "$id" } @@ -405,6 +465,15 @@ cmd_install() { 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" ;; *) @@ -414,7 +483,7 @@ cmd_install() { ;; esac done - [[ -n "$spec" ]] || die "usage: dcrup install [--build|--release] [--force] [--libc gnu|musl|auto]" + [[ -n "$spec" ]] || die "usage: dcrup install [--build|--release] [--force] [--libc gnu|musl|auto] [--mirror auto|cf|gh|sf|ya]" parse_spec "$spec" ensure_dirs @@ -431,7 +500,7 @@ cmd_install() { fi export FORCE - log "install spec=$SPEC_RAW channel=$SPEC_CHANNEL version=${SPEC_VERSION:-∅} mode=$mode libc=$DCRUP_LIBC" + 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 diff --git a/docs/README.mdx b/docs/README.mdx index f4e4d7f..fb048f9 100644 --- a/docs/README.mdx +++ b/docs/README.mdx @@ -11,7 +11,8 @@ sidebar_label: Introduction # Installation (dcrup) curl -fsSL https://sh.dcr-tool.ru | sh -s -- self-install export PATH="$HOME/.dcr/bin:$PATH" -dcrup install stable +dcrup install stable # auto: cf → gh → sf → ya +# dcrup install stable --mirror cf # CloudFlare / GitHub / SourceForge / Yandex # Create a project dcr new my-app diff --git a/docs/changelog.mdx b/docs/changelog.mdx index f80dfd9..f306e58 100644 --- a/docs/changelog.mdx +++ b/docs/changelog.mdx @@ -4,6 +4,12 @@ sidebar_label: Changelog # Changelog +## Unreleased + +- **Download mirrors in `dcrup`** — `--mirror auto|cf|gh|sf|ya` and `DCRUP_MIRROR`. + Default `auto` tries **cf → gh → sf → ya** (CloudFlare CDN, GitHub, SourceForge, Yandex CDN). +- **Removed `install.sh` / `install.ps1` / `install_bsd.sh`** — superseded by `dcrup`. + ## 0.8.5 (2026-08-08) - **`package.dcr-version`** — optional CLI version pin in `dcr.toml`. diff --git a/docs/contributing.mdx b/docs/contributing.mdx index 8883c5b..8a71166 100644 --- a/docs/contributing.mdx +++ b/docs/contributing.mdx @@ -8,6 +8,7 @@ sidebar_label: Contributing ```bash git clone https://github.com/dexoron/dcr +# or a source mirror: GitVerse / SourceCraft / SourceForge / GitLab (see README) cd dcr cargo build ``` diff --git a/docs/faq.mdx b/docs/faq.mdx index 4680f99..20673a4 100644 --- a/docs/faq.mdx +++ b/docs/faq.mdx @@ -61,6 +61,15 @@ Use `kind = "flat-bin"` (NASM `-f bin`) and optional `[archive]` for a FAT disk See [OS-dev recipe](/docs/recipes/os-flat-bin-archive). +## How do I choose a download mirror? + +`dcrup install` uses `--mirror auto` by default and tries **cf → gh → sf → ya**. + +```bash +dcrup install stable --mirror cf +export DCRUP_MIRROR=ya +``` + ## Lock file `dcr.lock` is created during builds (`dcr build`) when registry dependencies are present. To force an update — delete `dcr.lock` and run `dcr build`. diff --git a/docs/getting-started/installation.mdx b/docs/getting-started/installation.mdx index edfb38d..9b9a26f 100644 --- a/docs/getting-started/installation.mdx +++ b/docs/getting-started/installation.mdx @@ -45,10 +45,12 @@ After `self-install`, the command is **`dcrup`** (no `.sh` / `.ps1`): shims live ### Common dcrup commands ```sh -dcrup install stable # latest stable prebuilt +dcrup install stable # latest stable prebuilt (auto: cf → gh → sf → ya) dcrup install 0.8.2 # pin → 0.8.2@stable dcrup install 0.8.2@dev dcrup install stable --libc musl # Linux: musl asset (default: gnu) +dcrup install stable --mirror cf # CloudFlare CDN +dcrup install stable --mirror ya # Yandex CDN (RU fallback) dcrup install stable --build # cargo build --features archive dcrup install night # always build from branch dev HEAD dcrup default 0.8.2 @@ -60,6 +62,22 @@ dcrup which Layout: `~/.dcr/toolchains//dcr` and `~/.dcr/bin/dcr` → active version. +### Download mirrors + +Prebuilt installs try **cf → gh → sf → ya** unless you pin a host. + +| Code | URL | Notes | +|------|-----|--------| +| `cf` | `https://cdn-global.dcr-tool.ru//` | CloudFlare CDN (worldwide) | +| `gh` | `https://github.com/dexoron/dcr/releases/download//` | GitHub Releases | +| `sf` | `https://sourceforge.net/projects/dcr-tool/files///download` | SourceForge | +| `ya` | `https://cdn-ru.dcr-tool.ru//` | Yandex CDN (RU fallback) | + +```sh +dcrup install stable --mirror auto # default +export DCRUP_MIRROR=cf # persist for this shell +``` + --- ## Arch Linux (AUR) diff --git a/docs/reference/environment-variables.mdx b/docs/reference/environment-variables.mdx index 1c70f9e..406fdbc 100644 --- a/docs/reference/environment-variables.mdx +++ b/docs/reference/environment-variables.mdx @@ -57,3 +57,27 @@ export DCR_INDEX_PATH=/custom/path/index.json ``` Default: `~/.dcr/index.json`. + +## DCRUP_MIRROR + +Download mirror for `dcrup` (prebuilt binaries only). + +```bash +export DCRUP_MIRROR=auto # cf → gh → sf → ya (default) +export DCRUP_MIRROR=cf # CloudFlare CDN +export DCRUP_MIRROR=gh # GitHub Releases +export DCRUP_MIRROR=sf # SourceForge +export DCRUP_MIRROR=ya # Yandex CDN (RU fallback) +``` + +CLI override: `dcrup install stable --mirror cf`. + +## DCRUP_HOME / DCRUP_BIN / DCRUP_REPO + +Installer layout and source clone URL: + +```bash +export DCRUP_HOME=~/.dcr +export DCRUP_BIN=~/.dcr/bin +export DCRUP_REPO=https://github.com/dexoron/dcr +``` diff --git a/install.ps1 b/install.ps1 deleted file mode 100644 index 11eaca9..0000000 --- a/install.ps1 +++ /dev/null @@ -1,160 +0,0 @@ -$ErrorActionPreference = 'Stop' - -$RepoUrl = 'https://github.com/dexoron/dcr' -$ApiLatest = 'https://api.github.com/repos/dexoron/dcr/releases/latest' -$ApiAll = 'https://api.github.com/repos/dexoron/dcr/releases' -$InstallPath = Join-Path $env:LOCALAPPDATA 'dcr' -$BinPath = Join-Path $env:USERPROFILE '.local\bin' -$BinaryPath = Join-Path $InstallPath 'dcr.exe' - -function Info($msg) { Write-Host "[INFO] $msg" -ForegroundColor Cyan } -function Ok($msg) { Write-Host "[OK] $msg" -ForegroundColor Green } -function Warn($msg) { Write-Host "[WARN] $msg" -ForegroundColor Yellow } -function Fail($msg) { Write-Host "[ERROR] $msg" -ForegroundColor Red; exit 1 } - -function Require-Cmd($name) { - if (-not (Get-Command $name -ErrorAction SilentlyContinue)) { - Fail "Not found: $name" - } -} - -function Select-Channel { - Write-Host "Choose channel:" - Write-Host " 1) Latest stable release (default)" - Write-Host " 2) Latest dev (pre-release)" - $choice = Read-Host "Enter 1 or 2 [1]" - if ([string]::IsNullOrWhiteSpace($choice)) { $choice = '1' } - - switch ($choice) { - '1' { return 'stable' } - '2' { return 'dev' } - default { Fail 'Unknown option' } - } -} - -function Select-Mode { - Write-Host "Choose installation mode:" - Write-Host " 1) Download prebuilt binary from GitHub Release (recommended)" - Write-Host " 2) Build from git" - $choice = Read-Host "Enter 1 or 2 [1]" - if ([string]::IsNullOrWhiteSpace($choice)) { $choice = '1' } - - switch ($choice) { - '1' { return 'release' } - '2' { return 'build' } - default { Fail 'Unknown option' } - } -} - -function Get-Target { - $arch = $env:PROCESSOR_ARCHITECTURE - if ($env:PROCESSOR_ARCHITEW6432) { - $arch = $env:PROCESSOR_ARCHITEW6432 - } - switch ($arch) { - 'AMD64' { return 'x86_64-pc-windows-msvc' } - 'ARM64' { return 'aarch64-pc-windows-msvc' } - 'x86' { return 'i686-pc-windows-msvc' } - default { Fail "Unsupported Windows architecture: $arch" } - } -} - -function Fetch-ReleaseJson($channel) { - if ($channel -eq 'dev') { - Info "Looking for latest dev (pre-release)..." - $releases = Invoke-RestMethod -Method Get -Uri $ApiAll - $pre = $releases | Where-Object { $_.prerelease -eq $true } | Select-Object -First 1 - if (-not $pre) { Fail "No dev (pre-release) found on GitHub" } - return $pre - } else { - return Invoke-RestMethod -Method Get -Uri $ApiLatest - } -} - -function Install-FromRelease { - param([string]$target, [string]$channel) - - New-Item -ItemType Directory -Path $InstallPath -Force | Out-Null - - $release = Fetch-ReleaseJson $channel - $tag = $release.tag_name - $version = $tag.TrimStart('v') - - # Имя бинарника: dcr--.exe - $assetName = "dcr-$target-$version.exe" - - Info "Fetching release $tag (channel: $channel)..." - - $asset = $release.assets | Where-Object { $_.name -eq $assetName } | Select-Object -First 1 - if (-not $asset) { - Fail "Asset $assetName not found in release $tag" - } - - Info "Downloading $assetName..." - Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $BinaryPath - Ok "Binary downloaded: $assetName" -} - -function Install-FromSource { - param([string]$target, [string]$channel) - - Require-Cmd 'git' - Require-Cmd 'cargo' - - $tmp = Join-Path $env:TEMP 'dcr-install' - if (Test-Path $tmp) { Remove-Item -Recurse -Force $tmp } - - Info 'Cloning repository...' - if ($channel -eq 'dev') { - # Пробуем ветку dev - $result = git clone --depth 1 --branch dev $RepoUrl $tmp 2>&1 - if ($LASTEXITCODE -ne 0) { - git clone --depth 1 $RepoUrl $tmp | Out-Null - } - } else { - git clone --depth 1 $RepoUrl $tmp | Out-Null - } - - Info 'Building release binary...' - Push-Location $tmp - cargo build --release --target $target - Pop-Location - - New-Item -ItemType Directory -Path $InstallPath -Force | Out-Null - Copy-Item (Join-Path $tmp "target\$target\release\dcr.exe") $BinaryPath -Force - Ok 'Binary installed from source' - - Remove-Item -Recurse -Force $tmp -} - -function Setup-Path { - New-Item -ItemType Directory -Path $BinPath -Force | Out-Null - $linkPath = Join-Path $BinPath 'dcr.exe' - Copy-Item $BinaryPath $linkPath -Force - - $userPath = [Environment]::GetEnvironmentVariable('Path', 'User') - if (-not $userPath) { $userPath = '' } - - if (-not ($userPath -split ';' | Where-Object { $_ -eq $BinPath })) { - $newPath = if ($userPath) { "$userPath;$BinPath" } else { $BinPath } - [Environment]::SetEnvironmentVariable('Path', $newPath, 'User') - $env:Path = "$env:Path;$BinPath" - Warn "Added path to PATH: $BinPath" - } - - Ok "dcr command is available via $linkPath" -} - -Info 'Starting DCR installation' -$channel = Select-Channel -$mode = Select-Mode -$target = Get-Target - -if ($mode -eq 'build') { - Install-FromSource -target $target -channel $channel -} else { - Install-FromRelease -target $target -channel $channel -} - -Setup-Path -Ok 'Installation completed successfully' \ No newline at end of file diff --git a/install.sh b/install.sh deleted file mode 100755 index b600c3b..0000000 --- a/install.sh +++ /dev/null @@ -1,253 +0,0 @@ -#!/usr/bin/env bash -set -Eeuo pipefail - -TMPDIR="/tmp/dcr-install" -INSTALL_PATH="$HOME/.local/share/dcr" -BINPATH="$HOME/.local/bin" -MANPATH="${XDG_DATA_HOME:-$HOME/.local/share}/man" -LOGFILE="$HOME/.cache/dcr-install.log" -REPO_URL="https://github.com/dexoron/dcr" -GITHUB_API_LATEST="https://api.github.com/repos/dexoron/dcr/releases/latest" -GITHUB_API_ALL="https://api.github.com/repos/dexoron/dcr/releases" - -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' - -mkdir -p "$(dirname "$LOGFILE")" -exec > >(tee -a "$LOGFILE") 2>&1 - -log() { echo -e "${BLUE}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1"; } -success() { echo -e "${GREEN}✔ $1${NC}"; } -warn() { echo -e "${YELLOW}⚠ $1${NC}"; } -error() { echo -e "${RED}✖ $1${NC}"; } - -trap 'error "Error on line $LINENO"; exit 1' ERR - -INSTALL_MODE="" -CHANNEL="" - -check_os() { - case "$(uname -s)" in - Linux|Darwin|FreeBSD|OpenBSD|NetBSD) ;; - *) error "Only Linux, macOS, and BSD systems are supported"; exit 1 ;; - esac -} - -detect_target() { - local os arch - os="$(uname -s)" - arch="$(uname -m)" - - case "$os:$arch" in - Linux:x86_64) TARGET_TRIPLE="x86_64-unknown-linux-gnu" ;; - Linux:aarch64|Linux:arm64) TARGET_TRIPLE="aarch64-unknown-linux-gnu" ;; - Linux:i686|Linux:i386) TARGET_TRIPLE="i686-unknown-linux-gnu" ;; - Linux:armv7l|Linux:armv7) TARGET_TRIPLE="armv7-unknown-linux-gnueabihf" ;; - Linux:riscv64) TARGET_TRIPLE="riscv64gc-unknown-linux-gnu" ;; - Darwin:x86_64) TARGET_TRIPLE="x86_64-apple-darwin" ;; - Darwin:arm64|Darwin:aarch64) TARGET_TRIPLE="aarch64-apple-darwin" ;; - FreeBSD:x86_64|FreeBSD:amd64) TARGET_TRIPLE="x86_64-unknown-freebsd" ;; - FreeBSD:aarch64|FreeBSD:arm64) TARGET_TRIPLE="aarch64-unknown-freebsd" ;; - FreeBSD:i686|FreeBSD:i386) TARGET_TRIPLE="i686-unknown-freebsd" ;; - OpenBSD:x86_64|OpenBSD:amd64) TARGET_TRIPLE="x86_64-unknown-openbsd" ;; - OpenBSD:aarch64|OpenBSD:arm64) TARGET_TRIPLE="aarch64-unknown-openbsd" ;; - OpenBSD:i686|OpenBSD:i386) TARGET_TRIPLE="i686-unknown-openbsd" ;; - NetBSD:x86_64|NetBSD:amd64) TARGET_TRIPLE="x86_64-unknown-netbsd" ;; - NetBSD:aarch64|NetBSD:arm64) TARGET_TRIPLE="aarch64-unknown-netbsd" ;; - NetBSD:i686|NetBSD:i386) TARGET_TRIPLE="i686-unknown-netbsd" ;; - - *) error "Unsupported platform: $os/$arch"; exit 1 ;; - esac -} - -check_common_dependencies() { - command -v curl >/dev/null 2>&1 || { error "curl is not installed"; exit 1; } - if [[ "$CHANNEL" == "dev" ]]; then - if ! command -v python3 >/dev/null 2>&1 && ! command -v jq >/dev/null 2>&1; then - error "For dev installations, either 'python3' or 'jq' must be installed to parse GitHub API response." - exit 1 - fi - fi -} - -check_build_dependencies() { - command -v git >/dev/null 2>&1 || { error "git is not installed"; exit 1; } - command -v cargo >/dev/null 2>&1 || { error "cargo is not installed"; exit 1; } -} - -select_channel() { - echo "Choose channel:" - echo " 1) Latest stable release (default)" - echo " 2) Latest dev (pre-release)" - read -r -p "Enter 1 or 2 [1]: " choice < /dev/tty - - case "${choice:-1}" in - 1) CHANNEL="stable" ;; - 2) CHANNEL="dev" ;; - *) error "Unknown option"; exit 1 ;; - esac -} - -select_install_mode() { - echo "Choose installation mode:" - echo " 1) Download prebuilt binary from GitHub Release (recommended)" - echo " 2) Build from git" - read -r -p "Enter 1 or 2 [1]: " choice < /dev/tty - - case "${choice:-1}" in - 1) INSTALL_MODE="release" ;; - 2) INSTALL_MODE="build" ;; - *) error "Unknown option"; exit 1 ;; - esac -} - -# Returns JSON of the requested release to stdout -fetch_release_json() { - if [[ "$CHANNEL" == "dev" ]]; then - log "Looking for latest dev (pre-release)..." - local json result - json="$(curl -fsSL "$GITHUB_API_ALL")" - if command -v jq >/dev/null 2>&1; then - result="$(printf '%s' "$json" | jq -e -c 'map(select(.prerelease == true))[0]')" - else - result="$(printf '%s' "$json" | python3 - <<'EOF' -import sys, json -releases = json.load(sys.stdin) -pre = [r for r in releases if r.get("prerelease", False)] -if not pre: - print("{}", end="") -else: - print(json.dumps(pre[0]), end="") -EOF -)" - fi - - if [[ -z "$result" || "$result" == "{}" || "$result" == "null" ]]; then - error "No dev (pre-release) found on GitHub" - exit 1 - fi - printf '%s' "$result" - else - curl -fsSL "$GITHUB_API_LATEST" - fi -} - -download_binary() { - local release_json tag version asset_name download_url - - release_json="$(fetch_release_json)" - - tag="$(printf '%s\n' "$release_json" | \ - sed -n 's/.*"tag_name": "\([^"]*\)".*/\1/p' | head -n1)" - if [[ -z "$tag" ]]; then - error "Failed to determine release version" - exit 1 - fi - - # Version without leading 'v' - version="${tag#v}" - # Binary name: dcr-- - asset_name="dcr-${TARGET_TRIPLE}-${version}" - - log "Fetching release ${tag} (channel: ${CHANNEL})..." - - download_url="$(printf '%s\n' "$release_json" | \ - sed -n "s#.*\"browser_download_url\": \"\([^\"]*/${asset_name}\)\".*#\1#p" | head -n1)" - - if [[ -z "$download_url" ]]; then - error "Asset ${asset_name} not found in release ${tag}" - exit 1 - fi - - mkdir -p "$INSTALL_PATH" - curl -fL "$download_url" -o "$INSTALL_PATH/dcr" - chmod +x "$INSTALL_PATH/dcr" - success "Binary ${asset_name} downloaded (${tag})" -} - -prepare_sources() { - log "Fetching sources..." - rm -rf "$TMPDIR" - git clone --depth 1 "$REPO_URL" "$TMPDIR" - if [[ "$CHANNEL" == "dev" ]]; then - # Clone dev branch if it exists - git clone --depth 1 --branch dev "$REPO_URL" "$TMPDIR" 2>/dev/null || \ - git clone --depth 1 "$REPO_URL" "$TMPDIR" - fi - success "Sources fetched" -} - -build_binary() { - log "Building release binary..." - (cd "$TMPDIR" && cargo build --release) - success "Build completed" -} - -install_built_binary() { - mkdir -p "$INSTALL_PATH" - cp "$TMPDIR/target/release/dcr" "$INSTALL_PATH/dcr" - chmod +x "$INSTALL_PATH/dcr" - success "Binary installed from source" -} - -install_link() { - log "Creating symlink..." - mkdir -p "$BINPATH" - ln -sf "$INSTALL_PATH/dcr" "$BINPATH/dcr" - success "Command 'dcr' added to $BINPATH" -} - -install_man() { - log "Installing man pages..." - local man_src="$TMPDIR/man/man1" - if [[ -d "$man_src" ]]; then - mkdir -p "$MANPATH/man1" - cp "$man_src"/*.1 "$MANPATH/man1/" - success "Man pages installed to $MANPATH/man1" - fi -} - -check_path() { - if ! echo "$PATH" | grep -q "$BINPATH"; then - warn "Directory $BINPATH not found in PATH" - echo "Add this to ~/.bashrc or ~/.zshrc:" - echo "export PATH=\"$BINPATH:\$PATH\"" - fi -} - -cleanup() { - rm -rf "$TMPDIR" 2>/dev/null || true -} - -main() { - log "Starting DCR installation" - - check_os - detect_target - select_channel - check_common_dependencies - select_install_mode - cleanup - - if [[ "$INSTALL_MODE" == "build" ]]; then - check_build_dependencies - prepare_sources - build_binary - install_built_binary - else - download_binary - fi - - install_link - install_man - check_path - cleanup - - success "Installation completed successfully" - log "Log saved to $LOGFILE" -} - -main "$@" diff --git a/install_bsd.sh b/install_bsd.sh deleted file mode 100755 index e793c9b..0000000 --- a/install_bsd.sh +++ /dev/null @@ -1,241 +0,0 @@ -#!/bin/sh -set -eu - -TMPDIR="/tmp/dcr-install" -INSTALL_PATH="$HOME/.local/share/dcr" -BINPATH="$HOME/.local/bin" -MANPATH="${XDG_DATA_HOME:-$HOME/.local/share}/man" -LOGFILE="$HOME/.cache/dcr-install.log" -REPO_URL="https://github.com/dexoron/dcr" -GITHUB_API_LATEST="https://api.github.com/repos/dexoron/dcr/releases/latest" -GITHUB_API_ALL="https://api.github.com/repos/dexoron/dcr/releases" - -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' - -mkdir -p "$(dirname "$LOGFILE")" - -log() { printf "${BLUE}[%s]${NC} %s\n" "$(date '+%Y-%m-%d %H:%M:%S')" "$1" | tee -a "$LOGFILE"; } -success() { printf "${GREEN}✔ %s${NC}\n" "$1" | tee -a "$LOGFILE"; } -warn() { printf "${YELLOW}⚠ %s${NC}\n" "$1" | tee -a "$LOGFILE"; } -error() { printf "${RED}✖ %s${NC}\n" "$1" | tee -a "$LOGFILE" >&2; } - -INSTALL_MODE="" -CHANNEL="" - -check_os() { - case "$(uname -s)" in - FreeBSD|OpenBSD|NetBSD|DragonFly) ;; - *) error "Only BSD systems (FreeBSD, OpenBSD, NetBSD, DragonFly) are supported by this script"; exit 1 ;; - esac -} - -detect_target() { - local os arch - os="$(uname -s)" - arch="$(uname -m)" - - case "$os:$arch" in - FreeBSD:x86_64|FreeBSD:amd64) TARGET_TRIPLE="x86_64-unknown-freebsd" ;; - FreeBSD:aarch64|FreeBSD:arm64) TARGET_TRIPLE="aarch64-unknown-freebsd" ;; - FreeBSD:i686|FreeBSD:i386) TARGET_TRIPLE="i686-unknown-freebsd" ;; - OpenBSD:x86_64|OpenBSD:amd64) TARGET_TRIPLE="x86_64-unknown-openbsd" ;; - OpenBSD:aarch64|OpenBSD:arm64) TARGET_TRIPLE="aarch64-unknown-openbsd" ;; - OpenBSD:i686|OpenBSD:i386) TARGET_TRIPLE="i686-unknown-openbsd" ;; - NetBSD:x86_64|NetBSD:amd64) TARGET_TRIPLE="x86_64-unknown-netbsd" ;; - NetBSD:aarch64|NetBSD:arm64) TARGET_TRIPLE="aarch64-unknown-netbsd" ;; - NetBSD:i686|NetBSD:i386) TARGET_TRIPLE="i686-unknown-netbsd" ;; - DragonFly:x86_64|DragonFly:amd64) TARGET_TRIPLE="x86_64-unknown-dragonfly" ;; - *) error "Unsupported BSD platform: $os/$arch"; exit 1 ;; - esac -} - -check_common_dependencies() { - command -v curl >/dev/null 2>&1 || { error "curl is not installed"; exit 1; } - if [ "$CHANNEL" = "dev" ]; then - if ! command -v python3 >/dev/null 2>&1 && ! command -v jq >/dev/null 2>&1; then - error "For dev installations, either 'python3' or 'jq' must be installed to parse GitHub API response." - exit 1 - fi - fi -} - -check_build_dependencies() { - command -v git >/dev/null 2>&1 || { error "git is not installed"; exit 1; } - command -v cargo >/dev/null 2>&1 || { error "cargo is not installed"; exit 1; } -} - -select_channel() { - echo "Choose channel:" - echo " 1) Latest stable release (default)" - echo " 2) Latest dev (pre-release)" - printf "Enter 1 or 2 [1]: " - read -r choice - - case "${choice:-1}" in - 1) CHANNEL="stable" ;; - 2) CHANNEL="dev" ;; - *) error "Unknown option"; exit 1 ;; - esac -} - -select_install_mode() { - echo "Choose installation mode:" - echo " 1) Download prebuilt binary from GitHub Release (recommended)" - echo " 2) Build from git" - printf "Enter 1 or 2 [1]: " - read -r choice - - case "${choice:-1}" in - 1) INSTALL_MODE="release" ;; - 2) INSTALL_MODE="build" ;; - *) error "Unknown option"; exit 1 ;; - esac -} - -fetch_release_json() { - if [ "$CHANNEL" = "dev" ]; then - log "Looking for latest dev (pre-release)..." - local json result - json="$(curl -fsSL "$GITHUB_API_ALL")" - if command -v jq >/dev/null 2>&1; then - result="$(printf '%s' "$json" | jq -e -c 'map(select(.prerelease == true))[0]')" - else - result="$(printf '%s' "$json" | python3 - <<'EOF' -import sys, json -releases = json.load(sys.stdin) -pre = [r for r in releases if r.get("prerelease", False)] -if not pre: - print("{}", end="") -else: - print(json.dumps(pre[0]), end="") -EOF -)" - fi - - if [ -z "$result" ] || [ "$result" = "{}" ] || [ "$result" = "null" ]; then - error "No dev (pre-release) found on GitHub" - exit 1 - fi - printf '%s' "$result" - else - curl -fsSL "$GITHUB_API_LATEST" - fi -} - -download_binary() { - local release_json tag version asset_name download_url - - release_json="$(fetch_release_json)" - - tag="$(printf '%s\n' "$release_json" | \ - sed -n 's/.*"tag_name": "\([^"]*\)".*/\1/p' | head -n1)" - if [ -z "$tag" ]; then - error "Failed to determine release version" - exit 1 - fi - - version="${tag#v}" - asset_name="dcr-${TARGET_TRIPLE}-${version}" - - log "Fetching release ${tag} (channel: ${CHANNEL})..." - - download_url="$(printf '%s\n' "$release_json" | \ - sed -n "s#.*\"browser_download_url\": \"\([^\"]*/${asset_name}\)\".*#\1#p" | head -n1)" - - if [ -z "$download_url" ]; then - error "Asset ${asset_name} not found in release ${tag}" - exit 1 - fi - - mkdir -p "$INSTALL_PATH" - curl -fL "$download_url" -o "$INSTALL_PATH/dcr" - chmod +x "$INSTALL_PATH/dcr" - success "Binary ${asset_name} downloaded (${tag})" -} - -prepare_sources() { - log "Fetching sources..." - rm -rf "$TMPDIR" - git clone --depth 1 "$REPO_URL" "$TMPDIR" - if [ "$CHANNEL" = "dev" ]; then - git clone --depth 1 --branch dev "$REPO_URL" "$TMPDIR" 2>/dev/null || \ - git clone --depth 1 "$REPO_URL" "$TMPDIR" - fi - success "Sources fetched" -} - -build_binary() { - log "Building release binary..." - (cd "$TMPDIR" && cargo build --release) - success "Build completed" -} - -install_built_binary() { - mkdir -p "$INSTALL_PATH" - cp "$TMPDIR/target/release/dcr" "$INSTALL_PATH/dcr" - chmod +x "$INSTALL_PATH/dcr" - success "Binary installed from source" -} - -install_link() { - log "Creating symlink..." - mkdir -p "$BINPATH" - ln -sf "$INSTALL_PATH/dcr" "$BINPATH/dcr" - success "Command 'dcr' added to $BINPATH" -} - -install_man() { - log "Installing man pages..." - man_src="$TMPDIR/man/man1" - if [ -d "$man_src" ]; then - mkdir -p "$MANPATH/man1" - cp "$man_src"/*.1 "$MANPATH/man1/" - success "Man pages installed to $MANPATH/man1" - fi -} - -check_path() { - if ! echo "$PATH" | grep -q "$BINPATH"; then - warn "Directory $BINPATH not found in PATH" - echo "Add this to ~/.bashrc, ~/.zshrc or ~/.profile:" - echo "export PATH=\"$BINPATH:\$PATH\"" - fi -} - -cleanup() { - rm -rf "$TMPDIR" 2>/dev/null || true -} - -main() { - log "Starting DCR installation for BSD" - - check_os - select_channel - check_common_dependencies - detect_target - select_install_mode - cleanup - - if [ "$INSTALL_MODE" = "build" ]; then - check_build_dependencies - prepare_sources - build_binary - install_built_binary - else - download_binary - fi - - install_link - install_man - check_path - cleanup - - success "Installation completed successfully" - log "Log saved to $LOGFILE" -} - -main "$@"