Tutorial
For this tutorial we’re going to package up jq, a supremely useful tool for filtering and transforming JSON.
Writing package manifests for Hermit should be fairly familiar to anyone who has had experience with package managers like Homebrew, though it should be significantly more straightforward assuming the package provides cross-platform binaries for download.
This tutorial covers a fairly simple package definition, but more complex examples exist such as graalvm. Please refer to the hermit-packages repository for many more examples.
Clone and Activate the Manifest Repository¶
git clone https://github.com/cashapp/hermit-packages
cd hermit-packages
. ./bin/activate-hermit
Hint
The Hermit manifest repository is itself a Hermit environment configured to use itself as the source of packages. This makes testing very convenient.
Find the Releases¶
The releases for jq are conveniently in a single page and by downloading one of the links we can see that they’re directly downloadable binaries. Convenient.
Create a Basic Manifest¶
Create an empty jq.hcl
file in the hermit-packages
directory. The first
thing you’ll want is a description, for which typically just copy the project
description from their site or GitHub repository:
description = "jq is like sed for JSON data - you can use it to slice and filter and map and transform structured data with the same ease that sed, awk, grep and friends let you play with text."
Hint
The hermit
CLI includes a best-effort command to create a stub manifest.
hermit manifest create https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64`
Currently there a few limitations:
- It only works for binaries in GitHub releases.
- The download link must include
${os}
and either${arch}
or${xarch}
.
Hopefully these limitations will be removed over time.
Add a Version¶
version
blocks tell Hermit what versions of a package
are available for download and are specified as blocks. We’ll start with an
empty one for jq-1.6
:
version "1.6" {}
Add Download URLs for Each OS¶
Looking at the links we can see that there are downloads for Linux and OSX:
- https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64
- https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64
So we’ll add blocks for the respective operating systems (linux
and darwin
) and populate the
source
attribute, which tells Hermit where to download packages from:
version "1.6" {
linux {
source = "https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64"
}
darwin {
source = "https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64"
}
}
DRY our URLs¶
The raw URLs will work fine, but if we add more versions later it would be
nice not to have to duplicate this configuration. To do that we can pull the
OS blocks out to the top level and use Hermit’s
variable interpolation
support to substitute the ${version}
variable:
description = "jq is like sed for JSON data - you can use it to slice and filter and map and transform structured data with the same ease that sed, awk, grep and friends let you play with text."
linux {
source = "https://github.com/stedolan/jq/releases/download/jq-${version}/jq-linux64"
}
darwin {
source = "https://github.com/stedolan/jq/releases/download/jq-${version}/jq-osx-amd64"
}
version "1.6" {}
When selecting a version/channel, Hermit will look for sources in the matching block and fallback to the top-level.
Specifying the Binaries¶
At this point Hermit knows where to download our binaries from, but not what
to do with them. The binaries will also have different names(jq-linux64
and
jq-osx-amd64
) depending on which OS we’re on. We need to rename this
binaries to the canonical jq
. To solve this we’re going to need to use a
trigger to apply an action when unpacking, specifically the
rename action.
linux {
source = "https://github.com/stedolan/jq/releases/download/jq-${version}/jq-linux64"
on unpack {
rename { from = "${root}/jq-linux64" to = "${root}/jq" }
}
}
darwin {
source = "https://github.com/stedolan/jq/releases/download/jq-${version}/jq-osx-amd64"
on unpack {
rename { from = "${root}/jq-osx-amd64" to = "${root}/jq" }
}
}
And tell Hermit which binaries to link when installed:
binaries = ["jq"]
{{< hint ok >}}
The binaries
attribute supports globs, which will be expanded at unpack time.
{{< /hint >}}
Testing the Package¶
Hermit packages can include a testing
attribute which is a command to run to
test whether the package is functioning. This will typically just be
something like:
test = "jq --version"
The Hermit packages CI will run these tests periodically.
To test your package run:
$ hermit test jq --trace
debug:jq-1.6:exec: /Users/user/Library/Caches/hermit/pkg/jq-1.6/jq --version
debug: jq-1.6
The End Result¶
And we’re done.
description = "jq is like sed for JSON data - you can use it to slice and filter and map and transform structured data with the same ease that sed, awk, grep and friends let you play with text."
binaries = ["jq"]
test = "jq --version"
linux {
source = "https://github.com/stedolan/jq/releases/download/jq-${version}/jq-linux64"
on unpack {
rename { from = "${root}/jq-linux64" to = "${root}/jq" }
}
}
darwin {
source = "https://github.com/stedolan/jq/releases/download/jq-${version}/jq-osx-amd64"
on unpack {
rename { from = "${root}/jq-osx-amd64" to = "${root}/jq" }
}
}
version "1.6" {}
Local Manual Testing¶
As mentioned above, hermit-packages
is also a Hermit environment. Now we
have our manifest we can attempt to install it with:
$ hermit install jq
$ jq --version
jq-1.6
Distribute the Package¶
At this point you can (and should!) contribute the package back to the community via a PR.