diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3363d2b..7ccba7e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -82,4 +82,5 @@ jobs: files: | vyn-* scripts/install.sh + scripts/uninstall.sh generate_release_notes: true diff --git a/Dockerfile.cli b/Dockerfile.cli new file mode 100644 index 0000000..58bb7af --- /dev/null +++ b/Dockerfile.cli @@ -0,0 +1,21 @@ +# syntax=docker/dockerfile:1 +# Builds the vyn CLI binary inside Docker and copies it to /output. +# Usage: +# docker build -f Dockerfile.cli -t vyn-cli-builder . +# docker run --rm -v "$HOME/.local/bin:/output" vyn-cli-builder +# The binary will be placed at $HOME/.local/bin/vyn (ensure that dir is in PATH). + +FROM rust:1-alpine AS builder +RUN apk add --no-cache musl-dev pkgconf openssl-dev openssl-libs-static + +WORKDIR /app +COPY Cargo.toml Cargo.lock ./ +COPY crates ./crates +COPY proto ./proto + +RUN cargo build --release --bin vyn + +FROM alpine:3 AS export +COPY --from=builder /app/target/release/vyn /vyn + +ENTRYPOINT ["/bin/sh", "-c", "cp /vyn /output/vyn && echo 'vyn installed to /output/vyn' && /output/vyn --version"] diff --git a/README.md b/README.md index aca6524..bc51274 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ - [Option A: Install from crates.io (recommended)](#option-a-install-from-cratesio-recommended) - [Option B: Pre-built binary](#option-b-pre-built-binary) - [Option C: Build from source](#option-c-build-from-source) + - [Uninstall](#uninstall) - [Quick Start](#quick-start) - [Configuration](#configuration) - [Relay Deployment](#relay-deployment) @@ -82,6 +83,8 @@ Download `vyn-x86_64-pc-windows-msvc.zip` from [releases](https://github.com/arn ### Option C: Build from source +**With Rust toolchain** + ```bash git clone https://github.com/arnonsang/vyn.git cd vyn @@ -89,6 +92,45 @@ cargo install --path crates/vyn-cli vyn --help ``` +**Via Docker** + +Compiles from source inside Docker and copies the binary to your host. + +```bash +git clone https://github.com/arnonsang/vyn.git +cd vyn +docker build -f Dockerfile.cli -t vyn-cli-builder . +docker run --rm -v "$HOME/.local/bin:/output" vyn-cli-builder +``` + +Make sure `~/.local/bin` is in your `PATH`, then verify: + +```bash +vyn --help +``` + +To update, re-pull and rebuild: + +```bash +git -C vyn pull +docker build -f Dockerfile.cli -t vyn-cli-builder . +docker run --rm -v "$HOME/.local/bin:/output" vyn-cli-builder +``` + +### Uninstall + +Detects how `vyn` was installed and removes the binary and global config. + +```bash +curl -fsSL https://github.com/arnonsang/vyn/releases/latest/download/uninstall.sh | sh +``` + +or with wget: + +```bash +wget -qO- https://github.com/arnonsang/vyn/releases/latest/download/uninstall.sh | sh +``` + ## Quick Start ```bash diff --git a/crates/vyn-cli/src/main.rs b/crates/vyn-cli/src/main.rs index 56e96f9..34cb485 100644 --- a/crates/vyn-cli/src/main.rs +++ b/crates/vyn-cli/src/main.rs @@ -223,7 +223,7 @@ fn detect_and_store_install_method() { let exe_str = exe.to_string_lossy().to_lowercase(); if exe_str.contains(".cargo/bin") || exe_str.contains(".cargo\\bin") { Some("cargo".to_string()) - } else if exe_str.contains("/usr/local/bin") { + } else if exe_str.contains("/usr/local/bin") || exe_str.contains("/.local/bin") { Some("binary".to_string()) } else { None diff --git a/scripts/uninstall.sh b/scripts/uninstall.sh new file mode 100755 index 0000000..7bdbd99 --- /dev/null +++ b/scripts/uninstall.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env sh +set -e + +BIN="vyn" +VYN_GLOBAL_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/vyn" +GLOBAL_TOML="$VYN_GLOBAL_DIR/global.toml" + +# Read install_method from global.toml if present +install_method="" +if [ -f "$GLOBAL_TOML" ]; then + install_method="$(grep '^install_method' "$GLOBAL_TOML" | sed 's/.*= *"\(.*\)"/\1/')" +fi + +# Fall back to detecting from binary path +if [ -z "$install_method" ]; then + BIN_PATH="$(command -v "$BIN" 2>/dev/null || true)" + if [ -n "$BIN_PATH" ]; then + case "$BIN_PATH" in + */.cargo/bin/*) install_method="cargo" ;; + */.local/bin/*|*/usr/local/bin/*) install_method="binary" ;; + esac + fi +fi + +echo "Detected install method: ${install_method:-unknown}" + +remove_binary() { + target="$1" + if [ -f "$target" ]; then + if [ -w "$target" ]; then + rm "$target" + else + sudo rm "$target" + fi + echo "Removed $target" + else + echo "Binary not found at $target, skipping." + fi +} + +case "$install_method" in + binary) + # Try common binary install paths + for dir in "/usr/local/bin" "$HOME/.local/bin"; do + if [ -f "$dir/$BIN" ]; then + remove_binary "$dir/$BIN" + break + fi + done + ;; + cargo) + if command -v cargo >/dev/null 2>&1; then + cargo uninstall vyn-cli + else + # cargo not on PATH, find and remove manually + remove_binary "$HOME/.cargo/bin/$BIN" + fi + ;; + *) + # Unknown method: find the binary wherever it is + BIN_PATH="$(command -v "$BIN" 2>/dev/null || true)" + if [ -n "$BIN_PATH" ]; then + remove_binary "$BIN_PATH" + else + echo "Could not locate $BIN binary. Remove it manually." + fi + ;; +esac + +# Remove global config +if [ -d "$VYN_GLOBAL_DIR" ]; then + rm -rf "$VYN_GLOBAL_DIR" + echo "Removed $VYN_GLOBAL_DIR" +fi + +echo "vyn uninstalled."