README
¶
gokit
Small collection of reusable Go helpers and release utilities used across projects.
This repository contains a few focused packages and helper scripts that make it
easy to parse/compare semantic versions, implement a secure self-update flow
(signed checksums + ed25519 verification), and load simple .env files.
Requires Go 1.26+ (see go.mod).
Table of contents
Contents
- semver/ — parse and compare semantic versions.
- update/ — helpers to detect releases on GitHub, verify signed
checksums.txt, download artifacts and atomically replace the running executable. - osutil/ — small OS-related utilities:
- osutil/select.go — cross-platform selection helpers (
OpenFileSelection,OpenFilesSelection,OpenDirSelection,OpenDirsSelection). - osutil/clipboard.go — cross-platform clipboard helper (
CopyTextToClipboard). - env/ — environment helpers (
LoadDotEnv). - osutil/replace.go — atomic file replacement helpers (
AtomicReplace,CopyFile,IsCrossDeviceErr).
- osutil/select.go — cross-platform selection helpers (
- scripts/ — build and signing helpers (
build-all.sh, signing and key derivation tools). - _examples/ — runnable examples:
- _examples/select_eg.go — demonstrates the selection helpers.
Quick examples
Parse a version and read a parsed signature (if present)
package main
import (
"fmt"
"log"
"github.com/Fepozopo/gokit/semver"
)
func main() {
v, err := semver.Parse("v1.2.3+sig.sha256.deadbeef")
if err != nil {
log.Fatal(err)
}
fmt.Println("version:", v.String())
if v.HasSignature() {
fmt.Printf("signature: algo=%s hex=%s\n", v.Signature.Algo, v.Signature.Hex)
}
}
Check for updates and apply them (basic pattern)
package main
import (
"log"
"github.com/Fepozopo/gokit/update"
)
func main() {
currentVersion := "v0.1.0" // replace with actual version (set at build time)
repo := "owner/repo" // replace with actual repo
// example hex public key(s) for signature verification; keep the seed private
trustedPubKeysHex := []string{"a3f1c2d4e5b6a7980f1e2d3c4b5a6978c9d0e1f2a3b4c5d6e7f8091a2b3c4d5e"}
res, err := update.CheckForUpdates(currentVersion, repo)
if err != nil {
log.Fatal(err)
}
if !res.Available {
// The Err field contains sentinel errors callers may inspect,
// e.g. update.ErrNoReleases, update.ErrNoAsset, update.ErrMissingChecksums
if res.Err != nil {
log.Printf("no update available: %v", res.Err)
} else {
log.Println("already up-to-date")
}
return
}
// When `verify` is true the update will verify checksums.txt with the provided trusted public keys (recommended).
if err := update.Update(repo, res.Latest, true, trustedPubKeysHex); err != nil {
log.Fatalf("update failed: %v", err)
}
}
Load a .env file into environment variables
import "github.com/Fepozopo/gokit/env"
if err := env.LoadDotEnv(".env"); err != nil {
// handle error or ignore (LoadDotEnv returns an error if file can't be read)
}
Copy text to the system clipboard
package main
import (
"fmt"
"log"
"github.com/Fepozopo/gokit/osutil"
)
func main() {
text := "Hello from gokit!"
if err := osutil.CopyTextToClipboard(text); err != nil {
log.Fatalf("copy to clipboard failed: %v", err)
}
fmt.Println("Text copied to clipboard")
}
File/Directory selection utility
A small, dependency-free helper that opens the system's native file picker and
returns the selected path(s). The implementation is in gokit/osutil/select.go.
Behavior by platform:
- macOS: uses
osascript(AppleScript) to showchoose filedialogs. - Windows: uses PowerShell (
System.Windows.Forms.OpenFileDialog). - Linux: tries
zenity, thenkdialog. If neither is available the package falls back to a console prompt. If neither is available the helpers return osutil.ErrNoGUISelection (exported sentinel).
Exported helpers:
-
OpenFileSelection(title string) (string, error)— single-file selection. Returns an empty string + nil error if the user cancels. -
OpenFilesSelection(title string) ([]string, error)— multi-file selection. Returns a nil slice + nil error on cancel. -
OpenDirSelection(title string) (string, error)— single-directory selection. Returns an empty string + nil error if the user cancels. -
OpenDirsSelection(title string) ([]string, error)— multi-directory selection. Returns an nil slice + nil error on cancel.
Notes / requirements:
- The helper intentionally has no third-party dependencies and shells out to
platform tools. Ensure those backends are available for GUI dialogs:
- macOS:
osascript(standard) - Windows:
powershell - Linux:
zenityorkdialog
- macOS:
- If no GUI helper is present on Linux the functions return
osutil.ErrNoGUISelection, which callers can detect. - Cancelling a dialog returns an empty result and a nil error (so callers can treat cancellation separately from real errors).
- On macOS the AppleScript is passed via
osascript -e. If you encounter issues with very long/complex scripts the implementation can be adjusted to write the AppleScript to a temporary file and callosascript /tmp/script.
To run the included example:
go run ./_examples/select_eg.go
Build & release workflow
scripts/build-all.sh— build artifacts for supported platforms and producechecksums.txt. If an ed25519 seed is present the script may sign checksums.scripts/sign_checksums/— signer helper.scripts/derive_pub/— derive public key helper.
- Generate an ed25519 seed (keep it private):
openssl rand -out ed25519_seed.bin 32
- Derive the hex public key (do not commit the seed):
SEED_B64=$(base64 < ed25519_seed.bin)
go run scripts/derive_pub/derive_pub.go "$SEED_B64"
# prints 64-hex public key
Notes on update checking
CheckForUpdatesreturns anUpdateCheckResultwith fieldsAvailable,Latest, andErr. InspectUpdateCheckResult.Errfor programmatic hints (sentinel errors exported from theupdatepackage):ErrNoReleases,ErrNoAsset,ErrMissing_CHECKSUMS, andErrCurrentVersionInvalid.- The update code honors the
GITHUB_TOKENenvironment variable for authenticated requests. Export a token to increase rate limits or to access private releases:
export GITHUB_TOKEN="ghp_..."
Build artifacts:
./scripts/build-all.sh
Notes on atomic replacement
- The repository now provides
osutil.AtomicReplace,osutil.CopyFileandosutil.IsCrossDeviceErr(see osutil/replace.go). - The
updatepackage was refactored to useosutil.AtomicReplacewhen installing updates; this centralizes cross-device fallback and reduces duplication. - Tests for the replace/copy helpers are included under
osutil/.
The build script writes checksums.txt. If ed25519_seed.bin exists the script will run the signer to produce checksums.txt.sig which is a single-line hex-encoded ed25519 signature over the checksums file. You can sign manually:
go run scripts/sign_checksums/sign_checksums.go checksums.txt ed25519_seed.bin
# writes checksums.txt.sig (hex-encoded ed25519 signature)
Upload built binaries plus checksums.txt and checksums.txt.sig to a GitHub Release.
Testing
Run unit tests:
go test ./...
License
MIT. See LICENSE for details.