eish 0.1.0

Generate self-contained installation scripts (bash, fish, PowerShell) for GitHub release binaries
docs.rs failed to build eish-0.1.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.

eish

Generate self-contained installation scripts for binaries published as GitHub release assets.

eish inspects a release, works out which asset belongs to which platform, and renders an install.sh, install.fish or install.ps1 with that mapping baked in. The generated script needs nothing but curl/wget, tar and unzip — it never calls the GitHub API, so it keeps working when the API is rate limited or the machine is behind a flaky network.

cargo install --path .

eish quickjs-ng/quickjs --name qjs > install.sh
eish quickjs-ng/quickjs@v0.16.2 --shell powershell --name qjs > install.ps1
eish quickjs-ng/quickjs --shell fish --proxy xget --name qjs > install.fish

Usage

eish <SPEC> [OPTIONS]

  <SPEC>                  owner/repo, owner/repo@tag, or a full GitHub URL
  -s, --shell <SHELL>     bash | fish | powershell     [default: bash]
      --proxy <PROXY>     github | gh-proxy | xget |
                          jsdelivr | statically       [default: github]
      --tag <TAG>         tag to install, overrides `@tag`
  -b, --binary <BINARY>   executable name inside the archive
      --name <NAME>       install this program, when the release holds several
      --target <TARGET>   target triple the script defaults to
      --dir <DIR>         default install directory     [default: ~/.ei]
      --type <TYPE>       release | file                [default: release]
  -o, --output <PATH>     write to a file instead of stdout
      --asset <FILE>      bundle an asset explicitly (repeatable)
      --list              list the supported platforms and exit
  -v, --verbose           explain what eish is doing
  -q, --quiet             errors only

eish --help lists the rest (--ref, --release-json, --api-base, --min-disk-space).

Everything except the script goes to stderr, so stdout stays clean to pipe:

eish ahaoboy/es5 | bash                # generate and install in one step
eish ahaoboy/es5 --list                # which platforms are covered

A plain run is silent. -v explains each step and -vv adds detail.

Common cases

# Pin a version
eish owner/repo@v1.2.3 > install.sh

# Install from a file you already have, with no network access
curl -LO https://github.com/quickjs-ng/quickjs/releases/latest/download/qjs-linux-x86_64
eish quickjs-ng/quickjs --name qjs > install.sh
./install.sh --file ./qjs-linux-x86_64

# Generate without touching the network at all
eish owner/repo --asset tool-linux-amd64 --asset tool-macos-arm64 > install.sh

A release can hold several programs, and an installer can only install one. So eish refuses rather than guessing, and the error lists the programs to choose from — best-covered first, with how many platforms each one supports:

eish quickjs-ng/quickjs --name qjs  > install.sh
eish quickjs-ng/quickjs --name qjsc > install-qjsc.sh

A release with a single program needs no --name. The match is on the program a file is for, not a prefix — qjsc's assets start with qjs but belong only to qjsc. A name that appears in no asset is rejected, and so is a --file whose name belongs to a program you did not choose; both messages list the names that would work.

The generated script

It opens with the command that produced it, so a file found in someone's CI can be traced back and regenerated:

#!/usr/bin/env bash
#
# Installer for quickjs-ng/quickjs
#
# This file was generated by eish <VERSION> <COMMIT> and is not meant to be
# edited: the next time it is regenerated, any change made here is lost.
#
# The complete command that produced this file:
#
#   eish quickjs-ng/quickjs --proxy xget --name qjs

The command is the real one, taken from the arguments eish was called with — including things the script itself has no trace of, such as --release-json. It is safe to commit: credentials come from the environment or a helper, never from the command line.

The version line carries the commit too (as 0.2.0 a1b2c3d), so a script can be traced to the exact build that wrote it rather than just the release. A -modified suffix means the build came from an uncommitted tree.

At install time it detects the platform (OS, architecture and libc), looks it up in an embedded table, falls back to a compatible build if the exact one was not published, then downloads, unpacks, installs into ~/.ei and updates PATH.

Every option has a matching environment variable — EI_DIR, EI_PROXY, EI_TARGET, EI_FILE, … — and --help documents them:

EI_DIR=/usr/local/bin ./install.sh

Credentials

GitHub allows 60 anonymous API requests per hour per IP. There is no --token flag — a secret on the command line ends up in your shell history and in ps output. Instead eish uses credentials you already have:

  1. GITHUB_TOKEN or GH_TOKEN
  2. gh auth token (GitHub CLI)
  3. git credential fill (Git Credential Manager)

So either run gh auth login, or set GITHUB_TOKEN in CI. -v reports which source was used.

Supported

Formats: .tar.gz, .tgz, .tar.xz, .txz, .tar.bz2, .tbz2, .zip, .gz, .exe, and bare binaries such as qjs-linux-x86_64. Checksums, .msi, .deb and similar are ignored.

Targets: Linux (glibc and musl), macOS, Windows, Android and the BSDs, across x86_64, aarch64, armv7, arm, i686, riscv64gc, loongarch64, powerpc64le and s390x. Asset names are matched by the guess-target crate, so informal names like jq-linux-amd64 work as well as full Rust triples.

Library

use eish::{Client, InstallSpec, Proxy, Shell};

let mut spec = InstallSpec::new("easy-install", "easy-install")
    .with_shell(Shell::Bash)
    .with_proxy(Proxy::Xget);

let release = Client::new().release("easy-install", "easy-install", None)?;
spec.apply_release_checked(&release)?;
std::fs::write("install.sh", spec.render()?)?;

The cli feature (on by default) builds the binary and pulls in clap. For the library alone: eish = { version = "0.1", default-features = false }.

Development

cargo test
cargo clippy --all-targets -- -D warnings
cargo fmt --all -- --check

License

MIT OR Apache-2.0.