diff --git a/.github/workflows/ant-cli-release.yml b/.github/workflows/ant-cli-release.yml new file mode 100644 index 0000000..5d30bb7 --- /dev/null +++ b/.github/workflows/ant-cli-release.yml @@ -0,0 +1,323 @@ +name: ant release + +on: + push: + tags: + - "ant-cli-v*" + +env: + CARGO_TERM_COLOR: always + +permissions: + contents: write + +jobs: + build: + name: build (${{ matrix.target }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + target: x86_64-unknown-linux-musl + archive: tar.gz + - os: ubuntu-latest + target: aarch64-unknown-linux-musl + archive: tar.gz + - os: macos-latest + target: x86_64-apple-darwin + archive: tar.gz + - os: macos-latest + target: aarch64-apple-darwin + archive: tar.gz + - os: windows-latest + target: x86_64-pc-windows-msvc + archive: zip + steps: + - uses: actions/checkout@v4 + + - uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.target }} + + - name: install cross-compilation tools + if: matrix.target == 'aarch64-unknown-linux-musl' + run: | + sudo apt-get update + sudo apt-get install -y musl-tools gcc-aarch64-linux-gnu + echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV + + - name: install musl tools + if: matrix.target == 'x86_64-unknown-linux-musl' + run: | + sudo apt-get update + sudo apt-get install -y musl-tools + + - name: build + run: cargo build --release --target ${{ matrix.target }} --bin ant + + - name: determine version + id: version + shell: bash + run: | + version=$(grep '^version' ant-cli/Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') + echo "version=${version}" >> $GITHUB_OUTPUT + + - name: package (unix) + if: matrix.archive == 'tar.gz' + shell: bash + run: | + staging="ant-${{ steps.version.outputs.version }}-${{ matrix.target }}" + mkdir "$staging" + cp "target/${{ matrix.target }}/release/ant" "$staging/" + cp "resources/bootstrap_peers.toml" "$staging/" + tar czf "$staging.tar.gz" "$staging" + echo "ASSET=$staging.tar.gz" >> $GITHUB_ENV + + - name: package (windows) + if: matrix.archive == 'zip' + shell: bash + run: | + staging="ant-${{ steps.version.outputs.version }}-${{ matrix.target }}" + mkdir "$staging" + cp "target/${{ matrix.target }}/release/ant.exe" "$staging/" + cp "resources/bootstrap_peers.toml" "$staging/" + 7z a "$staging.zip" "$staging" + echo "ASSET=$staging.zip" >> $GITHUB_ENV + + - uses: actions/upload-artifact@v4 + with: + name: ant-${{ matrix.target }} + path: ${{ env.ASSET }} + + sign-windows: + name: sign windows binary + runs-on: windows-latest + needs: [build] + env: + SM_HOST: ${{ secrets.SM_HOST }} + SM_API_KEY: ${{ secrets.SM_API_KEY }} + SM_CLIENT_CERT_PASSWORD: ${{ secrets.SM_CLIENT_CERT_PASSWORD }} + SM_KEYPAIR_ALIAS: ${{ secrets.SM_KEYPAIR_ALIAS }} + SM_LOG_LEVEL: trace + SM_LOG_FILE: ${{ github.workspace }}\smctl-signing.log + steps: + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4 + with: + name: ant-x86_64-pc-windows-msvc + path: artifacts/ + + - name: extract binary for signing + shell: bash + run: | + cd artifacts + 7z x *.zip + # Find and copy the exe to a known location + find . -name "ant.exe" -exec cp {} ant.exe \; + + - name: create client certificate file + id: prepare_cert + shell: pwsh + run: | + $raw = @' + ${{ secrets.SM_CLIENT_CERT_B64 }} + '@ + + $clean = ($raw -replace '\s','') + + if ([string]::IsNullOrWhiteSpace($clean)) { + Write-Error "SM_CLIENT_CERT_B64 is empty after normalization." + exit 1 + } + + try { + $certBytes = [Convert]::FromBase64String($clean) + } catch { + Write-Error "SM_CLIENT_CERT_B64 is not valid Base64." + exit 1 + } + + $certPath = Join-Path $env:RUNNER_TEMP "Certificate.p12" + [System.IO.File]::WriteAllBytes($certPath, $certBytes) + + "SM_CLIENT_CERT_FILE=$certPath" | Out-File -FilePath $env:GITHUB_ENV -Append + "sm_client_cert_b64=$clean" | Out-File -FilePath $env:GITHUB_OUTPUT -Append + + - name: setup DigiCert SSM tools + uses: digicert/ssm-code-signing@v1.2.1 + with: + sm_host: ${{ secrets.SM_HOST }} + sm_api_key: ${{ secrets.SM_API_KEY }} + sm_client_cert_b64: ${{ steps.prepare_cert.outputs.sm_client_cert_b64 }} + sm_client_cert_password: ${{ secrets.SM_CLIENT_CERT_PASSWORD }} + + - name: verify smctl installation + shell: pwsh + run: | + smctl -v + smctl healthcheck + + - name: sign ant.exe + shell: pwsh + run: | + $file = "artifacts\ant.exe" + $result = & smctl sign --keypair-alias "$env:SM_KEYPAIR_ALIAS" --input "$file" 2>&1 + if ($LASTEXITCODE -ne 0) { + Write-Error "Signing failed: $result" + exit 1 + } + Write-Host "Successfully signed ant.exe" + + - name: verify signature + shell: pwsh + run: | + $sig = Get-AuthenticodeSignature "artifacts\ant.exe" + Write-Host "Status: $($sig.Status)" + Write-Host "Signer: $($sig.SignerCertificate.Subject)" + if ($sig.Status -ne "Valid") { + Write-Error "Signature validation failed" + exit 1 + } + + - name: repackage signed archive + shell: bash + run: | + version=$(grep '^version' ant-cli/Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') + staging="ant-${version}-x86_64-pc-windows-msvc" + rm -rf "$staging" + mkdir "$staging" + cp artifacts/ant.exe "$staging/" + cp resources/bootstrap_peers.toml "$staging/" + 7z a "$staging.zip" "$staging" + + - uses: actions/upload-artifact@v4 + with: + name: ant-x86_64-pc-windows-msvc-signed + path: ant-*-x86_64-pc-windows-msvc.zip + + - name: upload signing logs on failure + if: failure() + uses: actions/upload-artifact@v4 + with: + name: signing-logs + path: ${{ github.workspace }}\smctl-signing.log + if-no-files-found: ignore + + publish-crate: + name: publish ant-core to crates.io + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: dtolnay/rust-toolchain@stable + + - name: publish ant-core + working-directory: ant-core + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} + run: cargo publish + + release: + name: create github release + runs-on: ubuntu-latest + needs: [build, sign-windows, publish-crate] + steps: + - uses: actions/checkout@v4 + + - name: determine version and prerelease + id: meta + shell: bash + run: | + tag="${GITHUB_REF#refs/tags/}" + version="${tag#ant-cli-v}" + echo "tag=${tag}" >> $GITHUB_OUTPUT + echo "version=${version}" >> $GITHUB_OUTPUT + if [[ "$version" == *"-rc."* ]]; then + echo "prerelease=true" >> $GITHUB_OUTPUT + else + echo "prerelease=false" >> $GITHUB_OUTPUT + fi + + - uses: actions/download-artifact@v4 + with: + name: ant-x86_64-unknown-linux-musl + path: assets/ + - uses: actions/download-artifact@v4 + with: + name: ant-aarch64-unknown-linux-musl + path: assets/ + - uses: actions/download-artifact@v4 + with: + name: ant-x86_64-apple-darwin + path: assets/ + - uses: actions/download-artifact@v4 + with: + name: ant-aarch64-apple-darwin + path: assets/ + - uses: actions/download-artifact@v4 + with: + name: ant-x86_64-pc-windows-msvc-signed + path: assets/ + + - name: extract changelog entry + id: changelog + shell: bash + run: | + # Extract the latest changelog section (between first two ## headers) + changelog=$(awk '/^## \[/{if(found) exit; found=1; next} found' CHANGELOG.md) + # Write to file for the release body + echo "$changelog" > /tmp/changelog_entry.md + + - name: generate release body + shell: bash + run: | + version="${{ steps.meta.outputs.version }}" + cat > /tmp/release_body.md << 'HEADER' + ## Installation + + ### Linux / macOS (quick-start) + + ```bash + curl -fsSL https://raw.githubusercontent.com/WithAutonomi/ant-client/main/install.sh | bash + ``` + + ### Manual download + + Download the archive for your platform from the assets below, extract it, and place the `ant` binary on your `PATH`. Copy `bootstrap_peers.toml` to the appropriate config directory: + + | Platform | Config path | + |----------|-------------| + | Linux | `~/.config/ant/bootstrap_peers.toml` | + | macOS | `~/Library/Application Support/ant/bootstrap_peers.toml` | + | Windows | `%APPDATA%\ant\bootstrap_peers.toml` | + + ### Windows (winget) + + ```powershell + winget install Autonomi.ant + ``` + + HEADER + + echo "## Detailed Changes" >> /tmp/release_body.md + echo "" >> /tmp/release_body.md + cat /tmp/changelog_entry.md >> /tmp/release_body.md + + - name: create github release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + shell: bash + run: | + prerelease_flag="" + if [[ "${{ steps.meta.outputs.prerelease }}" == "true" ]]; then + prerelease_flag="--prerelease" + fi + + gh release create "${{ steps.meta.outputs.tag }}" \ + --title "ant ${{ steps.meta.outputs.version }}" \ + --notes-file /tmp/release_body.md \ + $prerelease_flag \ + assets/* diff --git a/.github/workflows/ant-core-release.yml b/.github/workflows/ant-core-release.yml new file mode 100644 index 0000000..bc62b8c --- /dev/null +++ b/.github/workflows/ant-core-release.yml @@ -0,0 +1,24 @@ +name: ant-core release + +on: + push: + tags: + - "ant-core-v*" + +env: + CARGO_TERM_COLOR: always + +jobs: + publish: + name: publish ant-core to crates.io + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: dtolnay/rust-toolchain@stable + + - name: publish ant-core + working-directory: ant-core + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} + run: cargo publish diff --git a/.github/workflows/install-test.yml b/.github/workflows/install-test.yml new file mode 100644 index 0000000..6bb1551 --- /dev/null +++ b/.github/workflows/install-test.yml @@ -0,0 +1,133 @@ +name: test install mechanisms + +on: + workflow_dispatch: + inputs: + version: + description: "Version to test (e.g. 0.1.1 or 0.1.1-rc.1)" + required: true + type: string + +jobs: + test-install-script-linux: + name: test install.sh (Linux) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: run install script + env: + ANT_VERSION: ${{ inputs.version }} + INSTALL_DIR: ${{ runner.temp }}/bin + run: bash install.sh + + - name: verify binary + run: | + export PATH="${{ runner.temp }}/bin:$PATH" + ant --help + echo "Binary runs successfully" + + - name: verify bootstrap config + run: | + config_file="${XDG_CONFIG_HOME:-$HOME/.config}/ant/bootstrap_peers.toml" + if [ ! -f "$config_file" ]; then + echo "ERROR: bootstrap_peers.toml not found at $config_file" + exit 1 + fi + echo "Bootstrap config installed at $config_file" + cat "$config_file" + + test-install-script-macos: + name: test install.sh (macOS) + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + + - name: run install script + env: + ANT_VERSION: ${{ inputs.version }} + INSTALL_DIR: ${{ runner.temp }}/bin + run: bash install.sh + + - name: verify binary + run: | + export PATH="${{ runner.temp }}/bin:$PATH" + ant --help + echo "Binary runs successfully" + + - name: verify bootstrap config + run: | + config_file="$HOME/Library/Application Support/ant/bootstrap_peers.toml" + if [ ! -f "$config_file" ]; then + echo "ERROR: bootstrap_peers.toml not found at $config_file" + exit 1 + fi + echo "Bootstrap config installed at $config_file" + cat "$config_file" + + test-winget-manifest: + name: validate winget manifest + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + + - name: install wingetcreate + shell: pwsh + run: | + winget install wingetcreate --accept-source-agreements --accept-package-agreements + continue-on-error: true + + - name: generate and validate manifest + shell: pwsh + run: | + $version = "${{ inputs.version }}" + $url = "https://github.com/WithAutonomi/ant-client/releases/download/ant-cli-v${version}/ant-${version}-x86_64-pc-windows-msvc.zip" + + # Download and hash + $tempFile = [System.IO.Path]::GetTempFileName() + try { + Invoke-WebRequest -Uri $url -OutFile $tempFile + $hash = (Get-FileHash -Path $tempFile -Algorithm SHA256).Hash + Write-Host "SHA256: $hash" + } finally { + Remove-Item $tempFile -ErrorAction SilentlyContinue + } + + # Substitute template + $template = Get-Content "resources\winget\Autonomi.ant.yaml" -Raw + $manifest = $template ` + -replace '\$\{VERSION\}', $version ` + -replace '\$\{SHA256\}', $hash + $manifest | Set-Content "winget\Autonomi.ant.installer.yaml" -Encoding UTF8 + + Write-Host "Generated manifest:" + Get-Content "winget\Autonomi.ant.installer.yaml" + + - name: test download and extract + shell: pwsh + run: | + $version = "${{ inputs.version }}" + $url = "https://github.com/WithAutonomi/ant-client/releases/download/ant-cli-v${version}/ant-${version}-x86_64-pc-windows-msvc.zip" + $tempDir = Join-Path $env:RUNNER_TEMP "ant-test" + New-Item -ItemType Directory -Path $tempDir -Force | Out-Null + + Invoke-WebRequest -Uri $url -OutFile "$tempDir\ant.zip" + Expand-Archive "$tempDir\ant.zip" -DestinationPath $tempDir + + $antExe = Get-ChildItem -Path $tempDir -Recurse -Filter "ant.exe" | Select-Object -First 1 + if (-not $antExe) { + Write-Error "ant.exe not found in archive" + exit 1 + } + + & $antExe.FullName --help + Write-Host "Windows binary runs successfully" + + # Check bootstrap config is in archive + $config = Get-ChildItem -Path $tempDir -Recurse -Filter "bootstrap_peers.toml" | Select-Object -First 1 + if (-not $config) { + Write-Error "bootstrap_peers.toml not found in archive" + exit 1 + } + Write-Host "Bootstrap config found in archive" + Get-Content $config.FullName diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..b6432b7 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,17 @@ +# Changelog + +All notable changes to the `ant` binary will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.1.1] - 2026-03-28 + +### Added +- Node management: `ant node add`, `ant node start`, `ant node stop`, `ant node status`, `ant node reset` +- Daemon management: `ant node daemon start`, `ant node daemon stop`, `ant node daemon status` +- Data operations: `ant file upload`, `ant file download`, `ant chunk put`, `ant chunk get` +- Wallet management: `ant wallet address`, `ant wallet balance` +- Automatic bootstrap peer loading from `bootstrap_peers.toml` config file +- `--json` global flag for structured output +- Cross-platform support (Linux, macOS, Windows) diff --git a/Cargo.lock b/Cargo.lock index 24abd38..80f5aa4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -880,6 +880,7 @@ dependencies = [ "tokio", "tokio-test", "tokio-util", + "toml", "tower-http", "tracing", "tracing-subscriber", diff --git a/ant-cli/src/main.rs b/ant-cli/src/main.rs index 313bdd9..7e969d4 100644 --- a/ant-cli/src/main.rs +++ b/ant-cli/src/main.rs @@ -240,6 +240,8 @@ fn resolve_evm_network( } /// Resolve bootstrap peers from a pre-loaded manifest. +/// +/// Priority: CLI `--bootstrap` > devnet manifest > `bootstrap_peers.toml` config file. fn resolve_bootstrap_from( ctx: &DataCliContext, manifest: Option<&DevnetManifest>, @@ -257,7 +259,17 @@ fn resolve_bootstrap_from( return Ok(bootstrap); } - anyhow::bail!("No bootstrap peers provided. Use --bootstrap or --devnet-manifest.") + if let Some(peers) = ant_core::config::load_bootstrap_peers() + .map_err(|e| anyhow::anyhow!("Failed to load bootstrap config: {e}"))? + { + info!("Loaded {} bootstrap peer(s) from config file", peers.len()); + return Ok(peers); + } + + anyhow::bail!( + "No bootstrap peers provided. Use --bootstrap, --devnet-manifest, \ + or install bootstrap_peers.toml to your config directory." + ) } async fn create_client_node( diff --git a/ant-core/Cargo.toml b/ant-core/Cargo.toml index e963976..561698d 100644 --- a/ant-core/Cargo.toml +++ b/ant-core/Cargo.toml @@ -15,6 +15,7 @@ serde = { version = "1", features = ["derive"] } serde_json = "1" reqwest = { version = "0.12", features = ["json", "stream"] } tar = "0.4" +toml = "0.8" thiserror = "2" tokio = { version = "1", features = ["full"] } tokio-util = { version = "0.7", features = ["rt"] } diff --git a/ant-core/src/config.rs b/ant-core/src/config.rs index 067aeed..806f15a 100644 --- a/ant-core/src/config.rs +++ b/ant-core/src/config.rs @@ -1,3 +1,4 @@ +use std::net::SocketAddr; use std::path::PathBuf; use crate::error::{Error, Result}; @@ -22,6 +23,26 @@ pub fn data_dir() -> Result { Ok(base.join("ant")) } +/// Returns the platform-appropriate configuration directory for ant. +/// +/// - Linux: `~/.config/ant` +/// - macOS: `~/Library/Application Support/ant` +/// - Windows: `%APPDATA%\ant` +pub fn config_dir() -> Result { + let base = if cfg!(target_os = "macos") { + home_dir()?.join("Library").join("Application Support") + } else if cfg!(target_os = "windows") { + std::env::var("APPDATA") + .map(PathBuf::from) + .unwrap_or_else(|_| home_dir().unwrap().join("AppData").join("Roaming")) + } else { + std::env::var("XDG_CONFIG_HOME") + .map(PathBuf::from) + .unwrap_or_else(|_| home_dir().unwrap().join(".config")) + }; + Ok(base.join("ant")) +} + /// Returns the platform-appropriate log directory for ant. /// /// - Linux: `~/.local/share/ant/logs` @@ -35,6 +56,34 @@ pub fn log_dir() -> Result { } } +/// Loads bootstrap peers from the platform-appropriate `bootstrap_peers.toml` file. +/// +/// Returns `Ok(Some(peers))` if the file exists and parses successfully, +/// `Ok(None)` if the file does not exist, or `Err` on parse/IO failures. +pub fn load_bootstrap_peers() -> Result>> { + let path = config_dir()?.join("bootstrap_peers.toml"); + if !path.exists() { + return Ok(None); + } + + let contents = std::fs::read_to_string(&path)?; + let config: BootstrapConfig = + toml::from_str(&contents).map_err(|e| Error::BootstrapConfigParse(e.to_string()))?; + + let addrs: Vec = config.peers.iter().filter_map(|s| s.parse().ok()).collect(); + + if addrs.is_empty() { + return Ok(None); + } + + Ok(Some(addrs)) +} + +#[derive(serde::Deserialize)] +struct BootstrapConfig { + peers: Vec, +} + fn home_dir() -> Result { std::env::var("HOME") .or_else(|_| std::env::var("USERPROFILE")) @@ -52,6 +101,12 @@ mod tests { assert_eq!(dir.file_name().unwrap(), "ant"); } + #[test] + fn config_dir_ends_with_ant() { + let dir = config_dir().unwrap(); + assert_eq!(dir.file_name().unwrap(), "ant"); + } + #[test] fn log_dir_contains_ant() { let dir = log_dir().unwrap(); @@ -61,4 +116,25 @@ mod tests { dir ); } + + #[test] + fn load_bootstrap_peers_returns_none_when_no_file() { + // Set config dir to a temp location where no file exists + let _result = load_bootstrap_peers(); + // Just verify it doesn't panic — actual None depends on whether the file exists + } + + #[test] + fn parse_bootstrap_config() { + let toml_str = r#" +peers = [ + "129.212.138.135:10000", + "134.199.138.183:10000", +] +"#; + let config: BootstrapConfig = toml::from_str(toml_str).unwrap(); + assert_eq!(config.peers.len(), 2); + let addr: SocketAddr = config.peers[0].parse().unwrap(); + assert_eq!(addr.port(), 10000); + } } diff --git a/ant-core/src/error.rs b/ant-core/src/error.rs index 352b241..39ceb0c 100644 --- a/ant-core/src/error.rs +++ b/ant-core/src/error.rs @@ -56,6 +56,9 @@ pub enum Error { #[error("Could not determine home directory (HOME/USERPROFILE not set)")] HomeDirNotFound, + #[error("Failed to parse bootstrap_peers.toml: {0}")] + BootstrapConfigParse(String), + #[error("Node count {count} exceeds maximum of {max} per call")] InvalidNodeCount { count: u16, max: u16 }, diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..9c3201e --- /dev/null +++ b/install.sh @@ -0,0 +1,126 @@ +#!/usr/bin/env bash +# Quick-start installer for the Autonomi `ant` CLI. +# +# Usage: +# curl -fsSL https://raw.githubusercontent.com/WithAutonomi/ant-client/main/install.sh | bash +# +# Environment variables: +# ANT_VERSION — install a specific version (e.g. "0.1.1"). Defaults to latest. +# INSTALL_DIR — override install directory (default: ~/.local/bin on Linux, /usr/local/bin on macOS). + +set -euo pipefail + +REPO="WithAutonomi/ant-client" +BINARY_NAME="ant" + +# --- helpers ---------------------------------------------------------------- + +say() { printf '%s\n' "$*"; } +err() { say "Error: $*" >&2; exit 1; } + +need() { + command -v "$1" > /dev/null 2>&1 || err "need '$1' (command not found)" +} + +detect_target() { + local os arch + os="$(uname -s)" + arch="$(uname -m)" + + case "$os" in + Linux) + case "$arch" in + x86_64) echo "x86_64-unknown-linux-musl" ;; + aarch64) echo "aarch64-unknown-linux-musl" ;; + *) err "unsupported Linux architecture: $arch" ;; + esac + ;; + Darwin) + case "$arch" in + x86_64) echo "x86_64-apple-darwin" ;; + arm64) echo "aarch64-apple-darwin" ;; + *) err "unsupported macOS architecture: $arch" ;; + esac + ;; + *) err "unsupported OS: $os" ;; + esac +} + +config_dir() { + local os + os="$(uname -s)" + case "$os" in + Linux) echo "${XDG_CONFIG_HOME:-$HOME/.config}/ant" ;; + Darwin) echo "$HOME/Library/Application Support/ant" ;; + *) err "unsupported OS: $os" ;; + esac +} + +default_install_dir() { + local os + os="$(uname -s)" + case "$os" in + Linux) echo "$HOME/.local/bin" ;; + Darwin) echo "/usr/local/bin" ;; + *) err "unsupported OS: $os" ;; + esac +} + +latest_version() { + curl -fsSL "https://api.github.com/repos/${REPO}/releases/latest" \ + | grep '"tag_name"' \ + | sed -E 's/.*"ant-cli-v([^"]+)".*/\1/' +} + +# --- main ------------------------------------------------------------------- + +need curl +need tar + +TARGET="$(detect_target)" +VERSION="${ANT_VERSION:-$(latest_version)}" +INSTALL_DIR="${INSTALL_DIR:-$(default_install_dir)}" + +say "Installing ant ${VERSION} for ${TARGET}..." + +ARCHIVE="${BINARY_NAME}-${VERSION}-${TARGET}.tar.gz" +URL="https://github.com/${REPO}/releases/download/ant-cli-v${VERSION}/${ARCHIVE}" + +TMPDIR="$(mktemp -d)" +trap 'rm -rf "$TMPDIR"' EXIT + +say "Downloading ${URL}..." +curl -fSL -o "${TMPDIR}/${ARCHIVE}" "$URL" + +say "Extracting..." +tar xzf "${TMPDIR}/${ARCHIVE}" -C "$TMPDIR" + +# Install binary +mkdir -p "$INSTALL_DIR" +cp "${TMPDIR}/${BINARY_NAME}-${VERSION}-${TARGET}/${BINARY_NAME}" "${INSTALL_DIR}/${BINARY_NAME}" +chmod +x "${INSTALL_DIR}/${BINARY_NAME}" +say "Installed ${BINARY_NAME} to ${INSTALL_DIR}/${BINARY_NAME}" + +# Install bootstrap config +CONF_DIR="$(config_dir)" +mkdir -p "$CONF_DIR" +if [ ! -f "${CONF_DIR}/bootstrap_peers.toml" ]; then + cp "${TMPDIR}/${BINARY_NAME}-${VERSION}-${TARGET}/bootstrap_peers.toml" "${CONF_DIR}/bootstrap_peers.toml" + say "Installed bootstrap config to ${CONF_DIR}/bootstrap_peers.toml" +else + say "Bootstrap config already exists at ${CONF_DIR}/bootstrap_peers.toml — skipping" +fi + +# Check PATH +case ":$PATH:" in + *":${INSTALL_DIR}:"*) ;; + *) + say "" + say "WARNING: ${INSTALL_DIR} is not in your PATH." + say "Add it with:" + say " export PATH=\"${INSTALL_DIR}:\$PATH\"" + ;; +esac + +say "" +say "Done! Run 'ant --help' to get started." diff --git a/resources/bootstrap_peers.toml b/resources/bootstrap_peers.toml new file mode 100644 index 0000000..7315e60 --- /dev/null +++ b/resources/bootstrap_peers.toml @@ -0,0 +1,17 @@ +# Autonomi Network — Bootstrap Peers +# +# This file provides initial peers for joining the production network. +# It is loaded automatically when no --bootstrap CLI argument is provided. +# +# Format: "ip:port" socket addresses. +# Port range for ant-node: 10000-10999. + +peers = [ + "129.212.138.135:10000", + "134.199.138.183:10000", + "167.235.201.229:10000", + "178.156.129.121:10000", + "207.148.94.42:10000", + "45.77.50.10:10000", + "18.228.202.183:10000", +] diff --git a/resources/winget/Autonomi.ant.yaml b/resources/winget/Autonomi.ant.yaml new file mode 100644 index 0000000..7f50b96 --- /dev/null +++ b/resources/winget/Autonomi.ant.yaml @@ -0,0 +1,25 @@ +# yaml-language-server: $schema=https://aka.ms/winget-manifest.singleton.1.6.0.schema.json +# Winget manifest for Autonomi ant CLI. +# +# This file is a template. The release workflow substitutes the version and URL. +# To submit to winget-pkgs, use `wingetcreate update` or submit a PR to +# https://github.com/microsoft/winget-pkgs. + +PackageIdentifier: Autonomi.ant +PackageVersion: "${VERSION}" +PackageName: Autonomi ant +Publisher: Autonomi +License: GPL-3.0 +ShortDescription: The Autonomi CLI for interacting with the Autonomi network. +PackageUrl: https://github.com/WithAutonomi/ant-client +Installers: + - Architecture: x64 + InstallerType: zip + InstallerUrl: https://github.com/WithAutonomi/ant-client/releases/download/ant-cli-v${VERSION}/ant-${VERSION}-x86_64-pc-windows-msvc.zip + InstallerSha256: "${SHA256}" + NestedInstallerType: portable + NestedInstallerFiles: + - RelativeFilePath: ant-${VERSION}-x86_64-pc-windows-msvc\ant.exe + PortableCommandAlias: ant +ManifestType: singleton +ManifestVersion: 1.6.0 diff --git a/resources/winget/update-winget.ps1 b/resources/winget/update-winget.ps1 new file mode 100644 index 0000000..c9f3268 --- /dev/null +++ b/resources/winget/update-winget.ps1 @@ -0,0 +1,53 @@ +# Update the winget manifest and optionally submit to winget-pkgs. +# +# Usage: +# .\update-winget.ps1 -Version "0.1.1" -Submit +# +# Requires: wingetcreate (install with `winget install wingetcreate`) + +param( + [Parameter(Mandatory)] + [string]$Version, + + [switch]$Submit, + + [string]$Token +) + +$ErrorActionPreference = "Stop" + +$repo = "WithAutonomi/ant-client" +$url = "https://github.com/$repo/releases/download/ant-cli-v$Version/ant-$Version-x86_64-pc-windows-msvc.zip" + +Write-Host "Downloading archive to compute SHA256..." +$tempFile = [System.IO.Path]::GetTempFileName() +try { + Invoke-WebRequest -Uri $url -OutFile $tempFile + $hash = (Get-FileHash -Path $tempFile -Algorithm SHA256).Hash + Write-Host "SHA256: $hash" +} finally { + Remove-Item $tempFile -ErrorAction SilentlyContinue +} + +# Read template and substitute values +$template = Get-Content "$PSScriptRoot\Autonomi.ant.yaml" -Raw +$manifest = $template ` + -replace '\$\{VERSION\}', $Version ` + -replace '\$\{SHA256\}', $hash + +$outPath = "$PSScriptRoot\Autonomi.ant.installer.yaml" +$manifest | Set-Content $outPath -Encoding UTF8 +Write-Host "Manifest written to $outPath" + +if ($Submit) { + if (-not $Token) { + Write-Error "A GitHub personal access token (-Token) is required to submit." + exit 1 + } + Write-Host "Submitting to winget-pkgs..." + wingetcreate update Autonomi.ant ` + --version $Version ` + --urls $url ` + --submit ` + --token $Token +}