grm is an experimental package manager for GitHub Releases. It is probably only good for installing packages which are distributed as binaries (for example the ones written in Go, Rust). The following popular packages can be installed with grm:
- mozilla/geckodriver
- gohugoio/hugo
- go-acme/lego
- zyedidia/micro
- ...
grm installs selected release binaries to /usr/local/bin/ by default and installs RPM/DEB assets through the system package manager. One repository can provide several binaries or a mix of binaries and system packages.
$ ./grm
A package manager for GitHub releases
Usage:
grm [command]
Available Commands:
aliases Print table of known package aliases
help Help about any command
info Show information about a package
install Install a package from GitHub releases
list List installed packages
lock Lock a package
release Create a release in GitHub
remove Remove a package
set Modify settings
settings Print settings
unlock Unlock a package
update Update installed packages
version Print version
Flags:
-c, --config string Path to the config file (default ~/.config/grm/grm.yaml)
-d, --debug Debug-level logging on stderr.
-h, --help help for grm
--no-progress Disable progress bar
--token string GitHub API token
--trace Trace-level logs to /tmp/grm.log (truncated each run).
--version Print the version and exit
-y, --yes Confirm all
Use "grm [command] --help" for more information about a command.grm install gohugoio/hugo==v0.63.0 -f Linux-64
Use the ~= operator to filter releases by a version prefix or glob pattern.
The most recent matching release is selected automatically.
# Install the most recent v0.63.x release
grm install gohugoio/hugo~=v0.63
# Install any v0.6x release (glob)
grm install gohugoio/hugo~=v0.6*
# Install any versioned stable release (glob with character class)
grm install gohugoio/hugo~=v[0-9]*-stableThe asset prompt accepts comma-separated numbers, ranges, or all. Compatible
RPM assets appear first when rpm is available. You can select a CLI archive
and a GUI RPM from the same release together.
After unpacking an archive, grm asks which binaries to install. With --yes,
it installs every eligible binary in each selected archive. For asset selection,
--yes chooses the first suitable asset; use repeated --asset flags to select
several assets without a prompt.
# Install both binaries from Yazi's selected archive on a new install
grm install sxyazi/yazi --yes
# Expand an existing single-binary Yazi installation
grm install sxyazi/yazi --binary ya --binary yazi --yes
# Select a CLI archive and a GUI RPM explicitly
grm install jsnjack/bunk \
--asset 'bunk_linux_amd64.tar.gz' \
--asset 'bunk-gui-*.x86_64.rpm'
# Select individual archive binaries, optionally renaming them
grm install sxyazi/yazi --binary ya --binary 'yazi=my-yazi'
# Scope a binary selector to one of several archives
grm install owner/repo \
--asset 'client_*linux_amd64.tar.gz' \
--asset 'tools_*linux_amd64.tar.gz' \
--binary 'client_*.tar.gz::client' \
--binary 'tools_*.tar.gz::admin=repo-admin'
grm list --longEach --asset name or glob must match exactly one release asset. A --binary
selector matches an archive-relative path or basename; quote globs so the shell
does not expand them. A global binary selector applies to every selected binary
asset; use asset-glob::path-glob to scope it when archives have different
contents. --rename remains available when installing exactly one binary;
passing the saved name again does not reinstall the package.
Asset and binary choices, including renames, are saved for later installs and updates. Version strings in asset and member paths are replaced with globs so those choices can follow subsequent releases. Missing or ambiguous remembered choices produce an error with instructions to select again. Newly appearing archive binaries are not added to remembered selections automatically.
Passing --asset replaces the saved asset selection; passing --binary
replaces the binary selection in the assets it applies to. Changing --filter
starts asset selection again; passing the saved filter again keeps the
selection, so a repeated install command does not reinstall the package. These
flags work even when the release version is already installed. The installation
plan lists all outputs and any previously tracked components that will be
removed when the new selection succeeds. grm asks for confirmation only when the
plan removes components, so an install with one suitable asset and one binary
runs without prompts.
All components share a repository's release and lock. update updates them
together; remove removes every tracked binary and system package. Downloads
and conflict checks finish before installation. Completed operations are saved
individually, and failed batches stay marked incomplete so a later install or
update can retry them. System package operations are not rolled back.
Existing configs work without a manual conversion. Reading a config leaves it
unchanged. On the next install or update, old binary installs keep one binary
and its installed name, and old DEB/RPM installs keep their package type and
name. Renamed legacy archive installs retain the old first-binary selection.
Use --asset or --binary to expand an existing selection. Missing binaries
or changed system package names stop migration before installation.
Migration preserves settings, filters, and locks. New and migrated installs use
selections and components records; older grm versions cannot manage these
records if you downgrade. For new archive selections, --yes installs all
eligible binaries; existing selections stay unchanged.
Set bin_dir to an absolute path, for example a directory in your home folder:
grm set bin_dir ~/.local/bingrm creates the directory if it does not exist. It uses sudo for binary files
only when the current user cannot write to the directory, or to its nearest
existing parent when the directory has not been created yet. Binaries that are
already installed move to the new directory when they are next updated or
reinstalled with --refresh. Set bin_dir to an empty value to use
/usr/local/bin/ again.
To install one package into its own directory, pass --bin-dir to install.
grm saves the directory with the package, so later installs, update and
remove use it without the flag, and other packages stay in bin_dir:
grm install jsnjack/wakeci --bin-dir ~/.local/binPassing the saved directory again changes nothing. Passing another directory
moves the package's binaries there, even when its version is current, and
--bin-dir '' moves them back to bin_dir. grm list counts binaries per
directory, and grm list --long shows each package's saved directory. The
setting requires grm 2.3.0 or later.
Some programs, such as wakeci, replace their own binary with a newer release.
grm's record then still names the old version. When install or update
finds a newer release, grm first compares each installed binary with the
SHA-256 digest that GitHub lists for its release asset. If every binary
matches, grm updates its record and does not download the release again.
This works only for assets that are the binary itself: an archive's digest
covers the archive, so archives and system packages are reinstalled as usual.
Once installed, grm can update itself:
grm install jsnjack/grmMake sure you have
curlandjqinstalled (sudo dnf install curl jq)
curl -s https://api.github.com/repos/jsnjack/grm/releases/latest | jq -r .assets[0].browser_download_url | xargs curl -LOs && chmod +x grm && sudo mv grm /usr/local/bin/