gokit

module
v0.6.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 22, 2026 License: MIT

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).
  • scripts/ — build and signing helpers (build-all.sh, signing and key derivation tools).
  • _examples/ — runnable examples:

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 show choose file dialogs.
  • Windows: uses PowerShell (System.Windows.Forms.OpenFileDialog).
  • Linux: tries zenity, then kdialog. 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: zenity or kdialog
  • 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 call osascript /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 produce checksums.txt. If an ed25519 seed is present the script may sign checksums.
  • scripts/sign_checksums/ — signer helper.
  • scripts/derive_pub/ — derive public key helper.
  1. Generate an ed25519 seed (keep it private):
openssl rand -out ed25519_seed.bin 32
  1. 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

  • CheckForUpdates returns an UpdateCheckResult with fields Available, Latest, and Err. Inspect UpdateCheckResult.Err for programmatic hints (sentinel errors exported from the update package): ErrNoReleases, ErrNoAsset, ErrMissing_CHECKSUMS, and ErrCurrentVersionInvalid.
  • The update code honors the GITHUB_TOKEN environment 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.CopyFile and osutil.IsCrossDeviceErr (see osutil/replace.go).
  • The update package was refactored to use osutil.AtomicReplace when 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.

Directories

Path Synopsis
scripts
derive_pub command
sign_checksums command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL