Documentation
¶
Overview ¶
Package binkit provisions, verifies, pins, and updates external CLI binaries that a Go program depends on but cannot build itself.
The Go toolchain can manage Go-built tools via "go tool", but nothing in the toolchain helps with a Rust or C binary you shell out to. binkit fills that gap: it downloads a pinned release from GitHub, verifies it against a recorded SHA-256, caches it by version, and returns a path.
Pinning ¶
Pins live in a lock file — tools.json by convention — which belongs in the consuming project's repository. Resolver.Ensure reads the pin and never resolves "latest", never calls the GitHub API, and therefore never depends on API rate limits or a token. Only Resolver.Update changes a pin.
Design ¶
binkit knows nothing about any particular tool. A Tool is plain data supplied by the caller; ready-made definitions live in the separate catalog subpackage, which this package deliberately does not import. Ensure returns a path and never executes anything — what to run is the caller's decision.
Index ¶
Constants ¶
const ( // DefaultCheckEvery is the minimum interval between upstream update checks. DefaultCheckEvery = 7 * 24 * time.Hour // EnvNoUpdateCheck disables update checks when set to any non-empty value. EnvNoUpdateCheck = "BINKIT_NO_UPDATE_CHECK" )
const (
// EnvCacheDir overrides the cache location.
EnvCacheDir = "BINKIT_CACHE"
)
Environment variables binkit consults.
Variables ¶
var ( ErrInvalidTool = errors.New("binkit: invalid tool definition") ErrNotPinned = errors.New("binkit: tool is not pinned") ErrNoDigest = errors.New("binkit: no pinned digest for this platform") ErrDigestMismatch = errors.New("binkit: digest mismatch") ErrUnsupportedPlatform = errors.New("binkit: tool is not published for this platform") ErrUnsupportedArchive = errors.New("binkit: unsupported archive format") ErrBinaryNotInArchive = errors.New("binkit: binary not found in archive") ErrAssetNotFound = errors.New("binkit: release has no such asset") )
Errors reported by this package. All are wrapped, so match with errors.Is.
var DefaultPlatforms = []Platform{
{OS: "linux", Arch: "amd64"},
{OS: "linux", Arch: "arm64"},
{OS: "darwin", Arch: "amd64"},
{OS: "darwin", Arch: "arm64"},
{OS: "windows", Arch: "amd64"},
{OS: "windows", Arch: "arm64"},
}
DefaultPlatforms is the set Resolver.Update records digests for. A tool that does not publish for one of these is skipped, so an over-broad list costs nothing.
Functions ¶
This section is empty.
Types ¶
type LockEntry ¶
type LockEntry struct {
Version string `json:"version"`
Repo string `json:"repo"`
Digests map[string]string `json:"digests,omitzero"`
}
LockEntry is one tool's pinned state.
Digests are keyed by "GOOS/GOARCH" and hold the SHA-256 of the *release asset*, not of the extracted binary. They are captured for every platform the tool supports at pin time, so a lock file generated on Linux still yields a verified install on macOS.
type LockFile ¶
LockFile maps tool name to pin. It belongs in the consuming project's repository and is meant to be committed — it is what makes a build reproducible.
type Resolver ¶
type Resolver struct {
// CacheDir overrides the cache location. Falls back to $BINKIT_CACHE, then to
// <user cache dir>/binkit.
CacheDir string
// Lock is the path to the lock file. Defaults to "tools.json".
Lock string
// HTTP is the client used for all requests. Defaults to [http.DefaultClient].
HTTP *http.Client
// Platforms are the platforms Update records digests for. Defaults to
// [DefaultPlatforms].
Platforms []Platform
// Now returns the current time. Defaults to [time.Now].
Now func() time.Time
// Stderr receives update notices. Defaults to [os.Stderr]. Notices never go to
// stdout, and are suppressed entirely when the default stderr is not a terminal —
// a CI log has no one to read them.
Stderr io.Writer
// CheckEvery is the minimum interval between upstream update checks. Defaults to
// [DefaultCheckEvery].
CheckEvery time.Duration
// NoCheck disables update checks. The BINKIT_NO_UPDATE_CHECK environment variable
// does the same for an end user.
NoCheck bool
// UpdateHint returns the command that updates the named tool, shown as a second
// line of the update notice. binkit cannot know a consuming CLI's flags, so
// without this the notice reports versions only.
UpdateHint func(toolName string) string
// contains filtered or unexported fields
}
Resolver installs tools. The zero value is usable: it caches under the user cache directory and reads tools.json from the working directory.
A Resolver is safe for concurrent use and must not be copied after first use.
func (*Resolver) Ensure ¶
Ensure returns the path to the pinned version of t, downloading and verifying it if it is not already cached.
It never reaches the network when the tool is already cached, and never contacts the GitHub API at all — a pinned version downloads by direct URL. A tool with no pin is an error rather than an implicit "fetch latest": changing what a build runs should be a deliberate, reviewable act.
func (*Resolver) Update ¶
Update resolves a version — the latest release when version is empty — installs it, and rewrites the lock file.
Digests are recorded for every platform in Resolver.Platforms from the single release response, so one run on Linux produces a lock file that verifies correctly on macOS and Windows too.
type Tool ¶
type Tool struct {
// Name keys the cache and the lock file, and forms the per-tool environment
// override. Required.
Name string
// Repo is the GitHub "owner/name" hosting the releases. Required.
Repo string
// Tag maps a version to its release tag. Optional; defaults to "v" + version.
Tag func(version string) string
// Asset returns the release asset filename for a version and platform. Returning
// an error means the tool is not published for that platform, which Update treats
// as "skip" rather than as a failure. Required.
Asset func(version, goos, goarch string) (string, error)
// BinaryPath returns the path of the executable inside the archive. Required.
BinaryPath func(version, goos, goarch string) string
}
Tool describes an external binary and where to obtain it. It is data, not behaviour: the two function fields exist only because asset naming varies per project and cannot be expressed as a format string in general.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package catalog holds ready-made binkit.Tool definitions for tools people commonly need, so a consuming project does not have to re-derive release asset naming.
|
Package catalog holds ready-made binkit.Tool definitions for tools people commonly need, so a consuming project does not have to re-derive release asset naming. |