From e255037090553cc765548a9497afab60400144f4 Mon Sep 17 00:00:00 2001 From: Tutku Ucan Date: Mon, 31 Aug 2026 23:17:56 +0300 Subject: [PATCH] feat: one-line install via GitHub Pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Installing meant cloning the repo and building it with cargo, which asks for a Rust toolchain before you can see whether you want the tool at all. The release workflow already publishes binaries for four targets, so the pieces to skip that were there — nothing was serving them. Add install.sh, which resolves the latest release, picks the tarball matching the machine's architecture and libc, verifies it against the release's SHA256SUMS, and installs to ~/.local/bin (or /usr/local/bin as root), adding that to PATH when it is missing. Plain POSIX sh, curl or wget, no jq. Serve it, plus a small landing page, from GitHub Pages via a new workflow so the documented one-liner has somewhere to point: curl -fsSL https://tuna4ll.github.io/ratfetch/install.sh | sh The source builds stay in the README under "Manual setup" — they are still the answer for architectures without a prebuilt binary, and for hacking on it. --- .github/workflows/pages.yml | 50 ++++++++++++ README.md | 32 +++++++- install.sh | 153 ++++++++++++++++++++++++++++++++++++ site/index.html | 125 +++++++++++++++++++++++++++++ 4 files changed, 359 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/pages.yml create mode 100755 install.sh create mode 100644 site/index.html diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml new file mode 100644 index 0000000..317c6cc --- /dev/null +++ b/.github/workflows/pages.yml @@ -0,0 +1,50 @@ +name: pages + +on: + push: + branches: [main] + paths: + - "site/**" + - "install.sh" + - ".github/workflows/pages.yml" + workflow_dispatch: + +# Never publish a stale build over a newer one, but let an in-flight deploy +# finish rather than cancelling it half-way. +concurrency: + group: pages + cancel-in-progress: false + +jobs: + deploy: + name: build and deploy the site + runs-on: ubuntu-latest + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deploy.outputs.page_url }} + steps: + - uses: actions/checkout@v5 + + - name: Shell-check the installer + run: | + sh -n install.sh + if command -v shellcheck >/dev/null; then shellcheck -s sh install.sh; fi + + - name: Assemble the site + run: | + mkdir -p _site + cp -r site/. _site/ + # Served at /ratfetch/install.sh — the URL the README advertises. + cp install.sh _site/install.sh + + - uses: actions/configure-pages@v5 + + - uses: actions/upload-pages-artifact@v3 + with: + path: _site + + - id: deploy + uses: actions/deploy-pages@v4 diff --git a/README.md b/README.md index 0cb7a1e..34ef9cf 100644 --- a/README.md +++ b/README.md @@ -28,13 +28,43 @@ Linux only — the collectors are built on `/proc` and `/sys`. ## Install +```sh +curl -fsSL https://tuna4ll.github.io/ratfetch/install.sh | sh +``` + +That picks the right prebuilt binary for your architecture and libc, verifies +its checksum against the release's `SHA256SUMS`, and installs it to +`~/.local/bin` (or `/usr/local/bin` when run as root). `RATFETCH_VERSION`, +`RATFETCH_INSTALL_DIR` and `RATFETCH_NO_MODIFY_PATH` override the defaults. +The script is [`install.sh`](install.sh) in this repo — read it before piping +it to a shell, as you should with any installer. + +Prebuilt for `x86_64` and `aarch64`, gnu and musl. + +### Manual setup + +Any other architecture, or if you would rather build it yourself. Needs Rust +1.88 or newer. + +```sh +cargo install --git https://github.com/tuna4ll/ratfetch +``` + +From a checkout, which is also how you build it to hack on: + ```sh git clone https://github.com/tuna4ll/ratfetch cd ratfetch cargo install --path . ``` -Needs Rust 1.88 or newer. +Both put the binary in `~/.cargo/bin`. To keep it out of the cargo tree +entirely, build and place it yourself: + +```sh +cargo build --release +install -m 755 target/release/ratfetch ~/.local/bin/ +``` ## Use diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..99a6239 --- /dev/null +++ b/install.sh @@ -0,0 +1,153 @@ +#!/bin/sh +# ratfetch installer. +# +# curl -fsSL https://tuna4ll.github.io/ratfetch/install.sh | sh +# +# Downloads the prebuilt binary for this machine from the latest GitHub +# release, verifies its checksum, and drops it in a bin directory on PATH. +# +# Knobs (all optional): +# RATFETCH_VERSION=v0.1.0 install a specific tag instead of the latest +# RATFETCH_INSTALL_DIR=DIR where the binary lands +# RATFETCH_NO_MODIFY_PATH=1 never touch the shell profile + +set -eu + +REPO="tuna4ll/ratfetch" +VERSION="${RATFETCH_VERSION:-}" +INSTALL_DIR="${RATFETCH_INSTALL_DIR:-}" + +# ANSI only when stderr is a terminal, so piped output stays clean. +if [ -t 2 ]; then + bold=$(printf '\033[1m'); dim=$(printf '\033[2m') + red=$(printf '\033[31m'); green=$(printf '\033[32m'); reset=$(printf '\033[0m') +else + bold=''; dim=''; red=''; green=''; reset='' +fi + +say() { printf '%s\n' "${dim}::${reset} $*" >&2; } +ok() { printf '%s\n' "${green}✓${reset} $*" >&2; } +die() { printf '%s\n' "${red}error:${reset} $*" >&2; exit 1; } + +need() { command -v "$1" >/dev/null 2>&1 || die "\`$1\` is required but not installed."; } + +# --- what are we running on ------------------------------------------------- + +[ "$(uname -s)" = "Linux" ] || die "ratfetch is Linux only — the collectors read /proc and /sys." + +case "$(uname -m)" in + x86_64 | amd64) arch=x86_64 ;; + aarch64 | arm64) arch=aarch64 ;; + *) die "unsupported architecture: $(uname -m). Build from source: cargo install --git https://github.com/$REPO" ;; +esac + +# musl systems (Alpine, Void musl, …) cannot run the gnu build; glibc systems +# can run either, and the gnu build is the better citizen there. +libc=gnu +if ldd --version 2>&1 | grep -qi musl; then + libc=musl +else + for loader in /lib/ld-musl-*; do + [ -e "$loader" ] && libc=musl + done +fi + +target="${arch}-unknown-linux-${libc}" + +# --- how do we fetch -------------------------------------------------------- + +if command -v curl >/dev/null 2>&1; then + fetch() { curl -fsSL "$1"; } + fetch_to() { curl -fsSL -o "$2" "$1"; } +elif command -v wget >/dev/null 2>&1; then + fetch() { wget -qO- "$1"; } + fetch_to() { wget -qO "$2" "$1"; } +else + die "neither curl nor wget found." +fi + +need tar +need mktemp + +# --- which version ---------------------------------------------------------- + +if [ -z "$VERSION" ]; then + say "resolving the latest release" + # One grep over the release JSON is enough; pulling in jq for a single + # field would be a heavier dependency than the whole installer. + # Buffered into a variable first: piping curl straight into grep -m1 kills + # the transfer mid-write and prints a spurious "failure writing output". + latest=$(fetch "https://api.github.com/repos/$REPO/releases/latest" || true) + VERSION=$(printf '%s\n' "$latest" | grep '"tag_name"' | head -1 | cut -d'"' -f4) + [ -n "$VERSION" ] || die "could not resolve the latest release. Set RATFETCH_VERSION=vX.Y.Z." +fi + +name="ratfetch-${VERSION}-${target}" +base="https://github.com/$REPO/releases/download/$VERSION" + +say "installing ${bold}ratfetch ${VERSION}${reset} for ${bold}${target}${reset}" + +# --- download and verify ---------------------------------------------------- + +tmp=$(mktemp -d) +trap 'rm -rf "$tmp"' EXIT INT TERM + +fetch_to "$base/${name}.tar.gz" "$tmp/${name}.tar.gz" \ + || die "no build published for ${target} in ${VERSION}." + +if fetch_to "$base/SHA256SUMS" "$tmp/SHA256SUMS" 2>/dev/null; then + expected=$(grep " ${name}.tar.gz\$" "$tmp/SHA256SUMS" | cut -d' ' -f1 || true) + if [ -n "$expected" ] && command -v sha256sum >/dev/null 2>&1; then + actual=$(sha256sum "$tmp/${name}.tar.gz" | cut -d' ' -f1) + [ "$expected" = "$actual" ] || die "checksum mismatch for ${name}.tar.gz — refusing to install." + ok "checksum verified" + else + say "skipping checksum verification (no entry or no sha256sum)" + fi +fi + +tar -xzf "$tmp/${name}.tar.gz" -C "$tmp" +[ -x "$tmp/$name/ratfetch" ] || die "the archive did not contain a ratfetch binary." + +# --- pick a destination ----------------------------------------------------- + +if [ -z "$INSTALL_DIR" ]; then + if [ "$(id -u)" -eq 0 ]; then + INSTALL_DIR=/usr/local/bin + else + INSTALL_DIR="${XDG_BIN_HOME:-$HOME/.local/bin}" + fi +fi + +mkdir -p "$INSTALL_DIR" || die "cannot create $INSTALL_DIR." +install -m 755 "$tmp/$name/ratfetch" "$INSTALL_DIR/ratfetch" \ + || die "cannot write to $INSTALL_DIR. Set RATFETCH_INSTALL_DIR to somewhere writable." + +ok "installed ${bold}$INSTALL_DIR/ratfetch${reset}" + +# --- PATH ------------------------------------------------------------------- + +case ":$PATH:" in + *":$INSTALL_DIR:"*) on_path=1 ;; + *) on_path=0 ;; +esac + +if [ "$on_path" -eq 0 ] && [ "${RATFETCH_NO_MODIFY_PATH:-0}" != "1" ]; then + line="export PATH=\"$INSTALL_DIR:\$PATH\"" + added='' + for profile in "$HOME/.bashrc" "$HOME/.zshrc"; do + [ -f "$profile" ] || continue + grep -qF "$line" "$profile" && continue + printf '\n# added by the ratfetch installer\n%s\n' "$line" >> "$profile" + added="$added $(basename "$profile")" + done + if [ -n "$added" ]; then + ok "added $INSTALL_DIR to PATH in$added — open a new shell, or run: $line" + else + say "$INSTALL_DIR is not on your PATH. Add it with: $line" + fi +elif [ "$on_path" -eq 0 ]; then + say "$INSTALL_DIR is not on your PATH. Add it with: export PATH=\"$INSTALL_DIR:\$PATH\"" +fi + +printf '\n%s\n' "${green}ratfetch ${VERSION} is ready.${reset} Run ${bold}ratfetch${reset} to start, or ${bold}ratfetch --once${reset} for a single frame." >&2 diff --git a/site/index.html b/site/index.html new file mode 100644 index 0000000..f8a5626 --- /dev/null +++ b/site/index.html @@ -0,0 +1,125 @@ + + + + + +ratfetch — a system fetch that does not stop at one frame + + + + +
+

ratfetch

+

A system fetch that does not stop at one frame. Linux, terminal, live.

+ +
+ $ + curl -fsSL https://tuna4ll.github.io/ratfetch/install.sh | sh + +
+

+ Detects your architecture and libc, verifies the release checksum, and installs into + ~/.local/bin (or /usr/local/bin as root). + Prefer to read it first? install.sh. +

+ +

What it does

+ + + ratfetch running in a terminal: logo, info table, meters, graphs and a process table + +

Other ways to install

+
# a specific version, or a different directory
+RATFETCH_VERSION=v0.1.0 sh -c "$(curl -fsSL https://tuna4ll.github.io/ratfetch/install.sh)"
+RATFETCH_INSTALL_DIR=~/bin sh -c "$(curl -fsSL https://tuna4ll.github.io/ratfetch/install.sh)"
+
+# manual setup, from source — needs Rust 1.88+
+cargo install --git https://github.com/tuna4ll/ratfetch
+
+# or from a checkout
+git clone https://github.com/tuna4ll/ratfetch
+cd ratfetch && cargo install --path .
+ +

Then

+
ratfetch                      # the live TUI
+ratfetch --once               # one frame, like a classic fetch tool
+ratfetch --theme gruvbox-dark
+ratfetch --generate-config     # a fully commented config.toml
+ + +
+ + +