pocket

package module
v0.0.0-...-67c4f29 Latest Latest
Warning

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

Go to latest
Published: Jan 15, 2026 License: MIT Imports: 26 Imported by: 0

README

pocket

A cross-platform build system inspired by Sage. Define functions, compose them with Serial/Parallel, and let pocket handle tool installation.

[!NOTE]

You don't need Go installed to use Pocket. The ./pok shim automatically downloads Go to .pocket/ if needed.

[!WARNING]

Under heavy development. Breaking changes will occur until the initial release.

Features

  • Cross-platform: Works on Windows, macOS, and Linux (no Makefiles)
  • Function-based: Define functions with pocket.Func(), compose with Serial()/Parallel()
  • Dependency management: Functions can depend on other functions with automatic deduplication
  • Tool management: Downloads and caches tools in .pocket/
  • Path filtering: Run different functions in different directories

Quickstart

Bootstrap

Run in your project root (requires Go for this step only):

go run github.com/fredrikaverpil/pocket/cmd/pocket@latest init

This creates .pocket/ and ./pok (the wrapper script).

Your first function

Edit .pocket/config.go:

package main

import (
    "context"
    "github.com/fredrikaverpil/pocket"
)

var Config = pocket.Config{
    ManualRun: []pocket.Runnable{Hello},
}

var Hello = pocket.Func("hello", "say hello", hello)

func hello(ctx context.Context) error {
    if pocket.Verbose(ctx) {
        pocket.Println(ctx, "Running hello function...")
    }
    pocket.Println(ctx, "Hello from pocket!")
    return nil
}
./pok -h        # list functions
./pok hello     # run function
./pok hello -h  # show help for function (options, usage)
./pok -v hello  # run with verbose output
./pok plan      # show execution tree (add -hidden to see install deps)
Composition

Create multiple functions and compose them in AutoRun with Serial() and Parallel() for controlled execution order:

var Config = pocket.Config{
    AutoRun: pocket.Serial(
        Format,              // first
        pocket.Parallel(     // then these in parallel
            Lint,
            Test,
        ),
        Build,               // last
    ),
}

Running ./pok without arguments executes the entire AutoRun tree.

Dependencies

Functions can depend on other functions. Dependencies are deduplicated automatically - each function runs at most once per execution.

var Install = pocket.Func("install:tool", "install tool", install).Hidden()
var Lint = pocket.Func("lint", "run linter", lint)

func lint(ctx context.Context) error {
    // Ensure tool is installed (runs once, even if called multiple times)
    pocket.Serial(Install)
    return pocket.Exec(ctx, "tool", "lint", "./...")
}

Concepts

Functions

Everything in Pocket is a function created with pocket.Func():

var MyFunc = pocket.Func("name", "description", implementation)

func implementation(ctx context.Context) error {
    // do work
    return nil
}

Functions can be:

  • Visible: Shown in ./pok -h and callable from CLI
  • Hidden: Not shown in help, used as dependencies (.Hidden())
Executing Commands

Use pocket.Exec() to run system commands in your pocket.Func functions:

func format(ctx context.Context) error {
    return pocket.Exec(ctx, "go", "fmt", "./...")
}

Commands run with proper output handling and respect the current path context.

Serial and Parallel

Use Serial and Parallel to compose functions:

pocket.Serial(fn1, fn2, fn3)    // run in sequence
pocket.Parallel(fn1, fn2, fn3)  // run concurrently

With dependencies - compose install dependencies into your function:

var Lint = pocket.Func("lint", "run linter", pocket.Serial(
    linter.Install,  // runs first
    lint,            // then the actual linting
))

func lint(ctx context.Context) error {
    return pocket.Exec(ctx, linter.Name, "run", "./...")
}

[!NOTE]

Be careful when using pocket.Parallel(). Only parallelize functions that don't conflict - typically read-only operations like linting or testing. Functions that mutate files (formatters, code generators) should run in serial before other functions read those files.

Tools vs Tasks

Pocket conceptually distinguishes between tools (installers) and tasks (runners). Tools are responsible for downloading and installing binaries; tasks use those binaries to do work.

1. Tool Package

A tool package ensures a binary is available. It exports:

  • Name - the binary name (used with pocket.Exec)
  • Install - a hidden function that downloads/installs the binary
  • Config (optional) - configuration file lookup settings
// tools/ruff/ruff.go
package ruff

const Name = "ruff"
const Version = "0.14.0"

var Install = pocket.Func("install:ruff", "install ruff", install).Hidden()

var Config = pocket.ToolConfig{
    UserFiles:   []string{"ruff.toml", ".ruff.toml", "pyproject.toml"},
    DefaultFile: "ruff.toml",
    DefaultData: defaultConfig,
}

func install(ctx context.Context) error {
    // Download and install ruff to .pocket/bin/
    // ...
}
2. Task Package

A task package provides related functions that use tools:

// tasks/python/lint.go
package python

var Lint = pocket.Func("py-lint", "lint Python files", pocket.Serial(
    ruff.Install,  // ensure tool is installed first
    lint,
))

func lint(ctx context.Context) error {
    return pocket.Exec(ctx, ruff.Name, "check", ".")  // run via Name constant
}

The Workflow() function composes tasks, and Detect() enables auto-discovery:

// tasks/python/workflow.go
package python

func Workflow() pocket.Runnable {
    return pocket.Serial(Format, Lint)
}

func Detect() func() []string {
    return func() []string { return pocket.DetectByFile("pyproject.toml") }
}
Summary
Type Purpose Exports Example
Tool Installs binary Name, Install, optional Config ruff, golangcilint
Task Uses tools FuncDefs + Workflow() + Detect() python, golang
Config Usage

The config ties everything together:

var Config = pocket.Config{
    // AutoRun executes on ./pok (no arguments)
    AutoRun: pocket.Serial(
        // Use task collections with auto-detection
        pocket.Paths(golang.Workflow()).DetectBy(golang.Detect()),
        pocket.Paths(markdown.Workflow()).DetectBy(markdown.Detect()),
    ),

    // ManualRun requires explicit ./pok <name>
    ManualRun: []pocket.Runnable{
        Deploy,
        Release,
    },
}

var Deploy = pocket.Func("deploy", "deploy to production", deploy)
var Release = pocket.Func("release", "create a release", release)

Running ./pok executes AutoRun. Running ./pok deploy executes the Deploy function.

Path Filtering

For e.g. monorepos, use Paths() to control where functions run:

// Run in specific directories
pocket.Paths(myFunc).In("services/api", "services/web")

// Auto-detect directories containing go.mod
pocket.Paths(golang.Workflow()).DetectBy(golang.Detect())

// Exclude directories
pocket.Paths(golang.Workflow()).DetectBy(golang.Detect()).Except("vendor")

// Combine detection with filtering
pocket.Paths(golang.Workflow()).DetectBy(golang.Detect()).In("services/.*").Except("testdata")
Skipping Tasks in Specific Paths

While Except() excludes entire workflows from directories, use SkipTask() to skip specific tasks within a workflow:

var Config = pocket.Config{
    AutoRun: pocket.Paths(golang.Workflow()).
        DetectBy(golang.Detect()).
        SkipTask(golang.Test, "tests/go", "tests/features").  // skip in specific dirs
        SkipTask(golang.Vulncheck),  // skip everywhere (no paths = skip all)
}

This runs the full Go workflow in detected directories, but skips go-test in tests/go and tests/features, and skips go-vulncheck everywhere.

Options

Functions can accept options:

type DeployOptions struct {
    Env    string `arg:"env" usage:"target environment"`
    DryRun bool   `arg:"dry-run" usage:"print without executing"`
}

var Deploy = pocket.Func("deploy", "deploy to environment", deploy).
    With(DeployOptions{Env: "staging"})

func deploy(ctx context.Context) error {
    opts := pocket.Options[DeployOptions](ctx)
    if opts.DryRun {
        pocket.Printf(ctx, "Would deploy to %s\n", opts.Env)
        return nil
    }
    // deploy...
    return nil
}
./pok deploy                     # uses default (staging)
./pok deploy -env=prod -dry-run  # override at runtime

Reference

Helper Functions
// Execution
pocket.Exec(ctx, "command", "arg1", "arg2")  // run command
pocket.Printf(ctx, "format %s", arg)          // formatted output
pocket.Println(ctx, "message")                // line output

// Paths
pocket.GitRoot()              // git repository root
pocket.FromGitRoot("subdir")  // path relative to git root
pocket.FromPocketDir("file")  // path relative to .pocket/
pocket.FromBinDir("tool")     // path relative to .pocket/bin/

// Context
pocket.Options[T](ctx)        // get typed options
pocket.Path(ctx)              // current path (for path-filtered functions)

// Detection
pocket.DetectByFile("go.mod")       // find dirs with file
pocket.DetectByExtension(".lua")    // find dirs with extension

// Installation
pocket.InstallGo(ctx, "pkg/path", "version")  // go install
pocket.ConfigPath("tool", config)              // find/create config file
Config Structure
var Config = pocket.Config{
    // AutoRun: runs on ./pok (no arguments)
    // Use SkipTask() to skip specific tasks in specific paths
    AutoRun: pocket.Paths(golang.Workflow()).
        DetectBy(golang.Detect()).
        SkipTask(golang.Test, "tests/go"),

    // ManualRun: requires ./pok <name>
    ManualRun: []pocket.Runnable{...},

    // Shim: configure wrapper scripts
    Shim: &pocket.ShimConfig{
        Name:       "pok",   // base name
        Posix:      true,    // ./pok
        Windows:    true,    // pok.cmd
        PowerShell: true,    // pok.ps1
    },
}

Documentation

  • Architecture - Internal design: execution model, shim generation, path resolution

Documentation

Index

Constants

View Source
const (
	// DirName is the name of the pocket directory.
	DirName = ".pocket"
	// ToolsDirName is the name of the tools subdirectory.
	ToolsDirName = "tools"
	// BinDirName is the name of the bin subdirectory (for symlinks).
	BinDirName = "bin"
)
View Source
const (
	Darwin  = "darwin"
	Linux   = "linux"
	Windows = "windows"
)

OS name constants matching runtime.GOOS values.

View Source
const (
	// Go-style architecture names (matching runtime.GOARCH).
	AMD64 = "amd64"
	ARM64 = "arm64"

	// Alternative naming conventions used by various tools.
	X8664   = "x86_64"
	AARCH64 = "aarch64"
	X64     = "x64"
)

Architecture constants in various naming conventions.

View Source
const WaitDelay = 5 * time.Second

WaitDelay is the grace period given to child processes to handle termination signals before being force-killed.

Variables

This section is empty.

Functions

func ArchToAMD64

func ArchToAMD64(arch string) string

ArchToAMD64 converts x86_64/aarch64 naming to Go-style architecture names.

x86_64 -> amd64
aarch64 -> arm64

Other values are returned unchanged.

func ArchToX64

func ArchToX64(arch string) string

ArchToX64 converts Go-style architecture names to x64/arm64 naming.

amd64 -> x64
arm64 -> arm64 (unchanged)

Other values are returned unchanged.

func ArchToX8664

func ArchToX8664(arch string) string

ArchToX8664 converts Go-style architecture names to x86_64/aarch64 naming.

amd64 -> x86_64
arm64 -> aarch64

Other values are returned unchanged.

func BinaryName

func BinaryName(name string) string

BinaryName returns the binary name with the correct extension for the current OS. On Windows, it appends ".exe" to the name.

func CWD

func CWD(ctx context.Context) string

CWD returns where the CLI was invoked (relative to git root).

func CollectModuleDirectories

func CollectModuleDirectories(r Runnable) []string

CollectModuleDirectories walks a Runnable tree and returns all unique directories where functions should run. This is used for multi-module shim generation.

func Command

func Command(ctx context.Context, name string, args ...string) *exec.Cmd

Command creates an exec.Cmd with PATH prepended with .pocket/bin, stdout/stderr connected to os.Stdout/os.Stderr, and graceful shutdown configured.

When the context is cancelled, the command receives SIGINT first (allowing graceful shutdown), then SIGKILL after WaitDelay.

If stdout is a TTY, color-forcing environment variables are added so that tools output ANSI colors even when their output is buffered (for parallel execution).

Note: For commands run from task actions, prefer TaskContext.Command() which automatically wires output to the task's output writers for proper parallel buffering.

To redirect output (e.g., for buffering in parallel execution), set cmd.Stdout and cmd.Stderr after creating the command.

func ConfigPath

func ConfigPath(toolName string, cfg ToolConfig) (string, error)

ConfigPath returns the path to a tool's config file. It checks for user config files in the repo root first, then falls back to writing the bundled default config.

Returns empty string and no error if cfg is empty.

Example:

var golangciConfig = pocket.ToolConfig{
    UserFiles:   []string{".golangci.yml", ".golangci.yaml"},
    DefaultFile: "golangci.yml",
    DefaultData: defaultConfig,
}

func lint(ctx context.Context) error {
    configPath, err := pocket.ConfigPath("golangci-lint", golangciConfig)
    if err != nil {
        return err
    }
    return pocket.Exec(ctx, "golangci-lint", "run", "-c", configPath)
}

func CopyFile

func CopyFile(src, dst string) error

CopyFile copies a file from src to dst.

func CreateSymlink(binaryPath string) (string, error)

CreateSymlink creates a symlink in .pocket/bin/ pointing to the given binary. On Windows, it copies the file instead since symlinks require admin privileges. Returns the path to the symlink (or copy on Windows).

func DefaultArchiveFormat

func DefaultArchiveFormat() string

DefaultArchiveFormat returns the typical archive format for the current OS. Returns "zip" on Windows, "tar.gz" on other platforms.

func DefaultArchiveFormatFor

func DefaultArchiveFormatFor(os string) string

DefaultArchiveFormatFor returns the typical archive format for the given OS. Returns "zip" for Windows, "tar.gz" for other platforms.

func DetectByExtension

func DetectByExtension(extensions ...string) []string

DetectByExtension finds directories containing files with any of the specified extensions. Returns paths relative to git root, sorted alphabetically. Excludes .pocket directory and hidden directories. Each directory is returned only once, even if multiple matching files are found.

func DetectByFile

func DetectByFile(filenames ...string) []string

DetectByFile finds directories containing any of the specified files (e.g., "go.mod"). Returns paths relative to git root, sorted alphabetically. Excludes .pocket directory and hidden directories. Each directory is returned only once, even if multiple marker files are found.

func Download

func Download(ctx context.Context, url string, opts ...DownloadOpt) error

Download fetches a URL and optionally extracts it. Progress and status messages are written to the context's output.

Example:

err := Download(ctx, url,
    WithDestDir(binDir),
    WithFormat("tar.gz"),
    WithExtract(WithRenameFile("tool-1.0.0/tool", "tool")),
    WithSymlink(),
)

func Errorf

func Errorf(ctx context.Context, format string, args ...any)

Errorf writes formatted output to stderr.

func Exec

func Exec(ctx context.Context, name string, args ...string) error

Exec runs an external command with output directed to the current context. The command runs in the current path directory.

func ExecIn

func ExecIn(ctx context.Context, dir, name string, args ...string) error

ExecIn runs an external command in a specific directory.

func ExtractTar

func ExtractTar(src, destDir string, opts ...ExtractOpt) error

ExtractTar extracts a .tar archive to destDir. If no options are provided, all files are extracted preserving directory structure. Use WithRenameFile or WithExtractFile to limit extraction to specific files.

func ExtractTarGz

func ExtractTarGz(src, destDir string, opts ...ExtractOpt) error

ExtractTarGz extracts a .tar.gz archive to destDir. If no options are provided, all files are extracted preserving directory structure. Use WithRenameFile or WithExtractFile to limit extraction to specific files.

func ExtractZip

func ExtractZip(src, destDir string, opts ...ExtractOpt) error

ExtractZip extracts a .zip archive to destDir. If no options are provided, all files are extracted preserving directory structure. Use WithRenameFile or WithExtractFile to limit extraction to specific files.

func FromBinDir

func FromBinDir(elem ...string) string

FromBinDir returns a path relative to the .pocket/bin directory. If no elements are provided, returns the bin directory itself.

func FromGitRoot

func FromGitRoot(elem ...string) string

FromGitRoot returns a path relative to the git root.

func FromLocal

func FromLocal(ctx context.Context, path string, opts ...DownloadOpt) error

FromLocal processes a local file (extract/copy) with the same options as Download. Useful for processing pre-downloaded or bundled archives.

func FromPocketDir

func FromPocketDir(elem ...string) string

FromPocketDir returns a path relative to the .pocket directory.

func FromToolsDir

func FromToolsDir(elem ...string) string

FromToolsDir returns a path relative to the .pocket/tools directory.

func GitRoot

func GitRoot() string

GitRoot returns the root directory of the git repository.

func GoVersionFromDir

func GoVersionFromDir(dir string) (string, error)

GoVersionFromDir reads the Go version from go.mod in the given directory. Returns the version string (e.g., "1.21") or an error if the file cannot be read or doesn't contain a go directive.

func HostArch

func HostArch() string

HostArch returns the current architecture (runtime.GOARCH).

func HostOS

func HostOS() string

HostOS returns the current operating system (runtime.GOOS).

func InstallCargoGit

func InstallCargoGit(ctx context.Context, repo, name, version string) error

InstallCargoGit installs a Rust binary using 'cargo install --git'. The binary is installed to .pocket/tools/cargo/<name>/<version>/ and symlinked to .pocket/bin/. Requires cargo to be installed on the system.

Example:

func installTool(ctx context.Context) error {
    return pocket.InstallCargoGit(ctx, "https://github.com/org/tool", "tool", "v1.0.0")
}

func InstallGo

func InstallGo(ctx context.Context, pkg, version string) error

InstallGo installs a Go binary using 'go install'. The binary is installed to .pocket/tools/go/<pkg>/<version>/ and symlinked to .pocket/bin/.

Example:

func installLinter(ctx context.Context) error {
    pocket.Printf(ctx, "Installing golangci-lint %s...\n", version)
    return pocket.InstallGo(ctx, "github.com/golangci/golangci-lint/cmd/golangci-lint", version)
}

func OSToTitle

func OSToTitle(os string) string

OSToTitle converts an OS name to title case.

darwin -> Darwin
linux -> Linux
windows -> Windows

func OSToUpper

func OSToUpper(os string) string

OSToUpper converts an OS name to uppercase.

darwin -> DARWIN
linux -> LINUX

func Options

func Options[T any](ctx context.Context) T

Options retrieves typed options from the context. It handles both struct and pointer types for T, always looking up the base struct type.

func Path

func Path(ctx context.Context) string

Path returns the current execution path (relative to git root).

func PrependPath

func PrependPath(env []string, dir string) []string

PrependPath prepends a directory to the PATH in the given environment.

func Printf

func Printf(ctx context.Context, format string, args ...any)

Printf writes formatted output to stdout.

func Println

func Println(ctx context.Context, args ...any)

Println writes a line to stdout.

func RegisterGenerateAll

func RegisterGenerateAll(fn GenerateAllFunc)

RegisterGenerateAll registers the scaffold.GenerateAll function. This is called by internal/scaffold.init() to avoid import cycles.

func RunConfig

func RunConfig(cfg Config)

RunConfig is the main entry point for running a pocket configuration. It parses CLI flags, discovers functions, and runs the appropriate ones.

Example usage in .pocket/main.go:

func main() {
    pocket.RunConfig(Config)
}

func TestContext

func TestContext(out *Output) context.Context

TestContext creates a context suitable for testing.

func VenvBinaryPath

func VenvBinaryPath(venvDir, name string) string

VenvBinaryPath returns the cross-platform path to a binary in a Python venv.

func Verbose

func Verbose(ctx context.Context) bool

Verbose returns whether verbose mode is enabled.

Types

type Config

type Config struct {
	// AutoRun defines the execution tree for ./pok (no arguments).
	// Use Serial() and Parallel() to control execution order.
	// All tasks in AutoRun execute when running ./pok without arguments.
	//
	// Example:
	//
	//	AutoRun: pocket.Serial(
	//	    pocket.Paths(golang.Workflow()).DetectBy(golang.Detect()),
	//	    pocket.Paths(python.Workflow()).DetectBy(python.Detect()),
	//	),
	AutoRun Runnable

	// ManualRun registers additional tasks that only run when explicitly
	// invoked with ./pok <taskname>. These tasks appear in ./pok -h under
	// "Manual Tasks" and support the same wrappers as AutoRun (Paths, etc.).
	//
	// Example:
	//
	//	ManualRun: []pocket.Runnable{
	//	    deployTask,
	//	    pocket.Paths(benchmarkTask).In("services/api"),
	//	},
	ManualRun []Runnable

	// Shim controls shim script generation.
	// By default, only Posix (./pok) is generated with name "pok".
	Shim *ShimConfig

	// SkipGenerate disables running "generate" at the start of the "all" task.
	// By default, "all" regenerates files before running tasks.
	// Set to true to skip regeneration.
	SkipGenerate bool

	// SkipGitDiff disables the git diff check at the end of the "all" task.
	// By default, "all" fails if there are uncommitted changes after running all tasks.
	// Set to true to disable this check.
	SkipGitDiff bool
}

Config defines the configuration for a project using pocket.

func (Config) WithDefaults

func (c Config) WithDefaults() Config

WithDefaults returns a copy of the config with default values applied.

type DownloadOpt

type DownloadOpt func(*downloadConfig)

DownloadOpt configures download and extraction behavior.

func WithDestDir

func WithDestDir(dir string) DownloadOpt

WithDestDir sets the destination directory for extraction.

func WithExtract

func WithExtract(opt ExtractOpt) DownloadOpt

WithExtract adds extraction options from the extract package. Use this to pass WithRenameFile, WithExtractFile, or WithFlatten options.

Example:

Download(ctx, url,
    WithExtract(WithRenameFile("tool-1.0.0/tool", "tool")),
    WithExtract(WithExtractFile("LICENSE")),
)

func WithFormat

func WithFormat(format string) DownloadOpt

WithFormat sets the archive format. Supported formats: "tar.gz", "tar", "zip", or "" for raw copy.

func WithHTTPHeader

func WithHTTPHeader(key, value string) DownloadOpt

WithHTTPHeader adds an HTTP header to the download request. Multiple calls accumulate headers.

func WithSkipIfExists

func WithSkipIfExists(path string) DownloadOpt

WithSkipIfExists skips the download if the specified file exists.

func WithSymlink() DownloadOpt

WithSymlink creates a symlink in .pocket/bin/ after extraction. The symlink points to the first extracted file.

type Engine

type Engine struct {
	// contains filtered or unexported fields
}

Engine orchestrates plan collection and execution.

func NewEngine

func NewEngine(root Runnable) *Engine

NewEngine creates an engine for the given runnable tree.

func (*Engine) Execute

func (e *Engine) Execute(ctx context.Context, out *Output, cwd string, verbose bool) error

Execute runs the tree with normal execution.

func (*Engine) Plan

func (e *Engine) Plan(ctx context.Context) (*ExecutionPlan, error)

Plan collects the complete execution plan without running anything.

type ExecutionPlan

type ExecutionPlan struct {
	// contains filtered or unexported fields
}

ExecutionPlan holds the complete plan collected during modeCollect.

func (*ExecutionPlan) AddFunc

func (p *ExecutionPlan) AddFunc(name, usage string, hidden, deduped bool)

AddFunc adds a function call to the plan.

func (*ExecutionPlan) Pop

func (p *ExecutionPlan) Pop()

Pop ends the current group.

func (*ExecutionPlan) PopFunc

func (p *ExecutionPlan) PopFunc()

PopFunc ends the current function's scope.

func (*ExecutionPlan) Print

func (p *ExecutionPlan) Print(ctx context.Context, showHidden, showDedup bool)

Print outputs the execution plan tree.

func (*ExecutionPlan) PushParallel

func (p *ExecutionPlan) PushParallel()

PushParallel starts a parallel group.

func (*ExecutionPlan) PushSerial

func (p *ExecutionPlan) PushSerial()

PushSerial starts a serial group.

func (*ExecutionPlan) Steps

func (p *ExecutionPlan) Steps() []*PlanStep

Steps returns the top-level steps in the plan.

type ExtractOpt

type ExtractOpt func(*extractConfig)

ExtractOpt configures extraction behavior.

func WithExtractFile

func WithExtractFile(name string) ExtractOpt

WithExtractFile extracts only the specified file (by base name). The file is extracted with its original name. Multiple calls accumulate files to extract.

func WithFlatten

func WithFlatten() ExtractOpt

WithFlatten flattens directory structure, extracting all files to destDir root. File names are preserved but directory paths are discarded.

func WithRenameFile

func WithRenameFile(srcPath, destName string) ExtractOpt

WithRenameFile extracts a specific file and optionally renames it. srcPath can be a full path within the archive or just the base name. If destName is empty, the original base name is preserved. Multiple calls accumulate files to extract.

Example:

ExtractTarGz(src, dest,
    WithRenameFile("golangci-lint-1.55.0-linux-amd64/golangci-lint", "golangci-lint"),
)

type FuncDef

type FuncDef struct {
	// contains filtered or unexported fields
}

FuncDef represents a named function that can be executed. Create with pocket.Func() - this is the only way to create runnable functions.

The body can be either:

  • A plain function: func(context.Context) error
  • A Runnable composition: pocket.Serial(...) or pocket.Parallel(...)

Example:

// Simple function
var Format = pocket.Func("go-format", "format Go code", func(ctx context.Context) error {
    return pocket.Exec(ctx, "go", "fmt", "./...")
})

// Function with dependencies
var Lint = pocket.Func("go-lint", "run linter", pocket.Serial(
    InstallLinter,
    func(ctx context.Context) error {
        return pocket.Exec(ctx, "golangci-lint", "run", "./...")
    },
))

// Hidden functions (e.g., tool installers)
var InstallLinter = pocket.Func("install:linter", "install linter", install).Hidden()

func Func

func Func(name, usage string, body any) *FuncDef

Func creates a new function definition. This is the only way to create functions that can be used with Serial/Parallel.

The name is used for CLI commands (e.g., "go-format" becomes ./pok go-format). The usage is displayed in help output. The body can be:

  • func(context.Context) error - a plain function
  • Runnable - a Serial/Parallel composition

func (*FuncDef) Hidden

func (f *FuncDef) Hidden() *FuncDef

Hidden returns a copy marked as hidden from CLI help. Hidden functions can still be executed but don't appear in ./pok -h. Use this for internal functions like tool installers.

func (*FuncDef) IsHidden

func (f *FuncDef) IsHidden() bool

IsHidden returns whether the function is hidden from CLI help.

func (*FuncDef) Name

func (f *FuncDef) Name() string

Name returns the function's CLI name.

func (*FuncDef) Opts

func (f *FuncDef) Opts() any

Opts returns the function's options, or nil if none.

func (*FuncDef) Run

func (f *FuncDef) Run(ctx context.Context) error

Run executes this function with the given context. This is useful for testing or programmatic execution.

func (*FuncDef) Usage

func (f *FuncDef) Usage() string

Usage returns the function's help text.

func (*FuncDef) With

func (f *FuncDef) With(opts any) *FuncDef

With returns a copy with options attached. Options are accessible via pocket.Options[T](ctx) in the function.

Example:

type FormatOptions struct {
    Config string
}

var Format = pocket.Func("format", "format code", formatImpl).
    With(FormatOptions{Config: ".golangci.yml"})

func formatImpl(ctx context.Context) error {
    opts := pocket.Options[FormatOptions](ctx)
    // use opts.Config
}

type GenerateAllFunc

type GenerateAllFunc func(cfg *Config) ([]string, error)

GenerateAllFunc is the function signature for scaffold.GenerateAll. This is set by internal/scaffold at init time to avoid import cycles.

type Output

type Output struct {
	Stdout io.Writer
	Stderr io.Writer
}

Output holds stdout and stderr writers for task output. This is passed through the Runnable chain to direct output appropriately.

func GetOutput

func GetOutput(ctx context.Context) *Output

GetOutput returns the current output writers.

func StdOutput

func StdOutput() *Output

StdOutput returns an Output that writes to os.Stdout and os.Stderr.

func (*Output) Printf

func (o *Output) Printf(format string, a ...any) (int, error)

Printf formats and prints to stdout.

func (*Output) Println

func (o *Output) Println(a ...any) (int, error)

Println prints to stdout with a newline.

type PathFilter

type PathFilter struct {
	// contains filtered or unexported fields
}

PathFilter wraps a Runnable with path filtering. It implements Runnable, so it can be used anywhere a Runnable is expected.

func Paths

func Paths(r Runnable) *PathFilter

Paths wraps a Runnable with path filtering capabilities. The returned *PathFilter can be configured with builder methods.

func (*PathFilter) DetectBy

func (p *PathFilter) DetectBy(fn func() []string) *PathFilter

DetectBy sets a custom detection function. The function should return directories relative to git root. Returns a new *PathFilter (immutable).

func (*PathFilter) Except

func (p *PathFilter) Except(patterns ...string) *PathFilter

Except adds exclude patterns (regexp). Directories matching any pattern are excluded from results. Returns a new *PathFilter (immutable).

func (*PathFilter) In

func (p *PathFilter) In(patterns ...string) *PathFilter

In adds include patterns (regexp). Directories matching any pattern are included. Returns a new *PathFilter (immutable).

func (*PathFilter) Resolve

func (p *PathFilter) Resolve() []string

Resolve returns all directories where this Runnable should run. It combines detection results with explicit includes, then filters by excludes. Results are sorted and deduplicated.

func (*PathFilter) ResolveFor

func (p *PathFilter) ResolveFor(cwd string) []string

ResolveFor returns the resolved paths filtered for the given working directory. If cwd is ".", returns all resolved paths. Otherwise, returns only paths that match cwd.

func (*PathFilter) RunsIn

func (p *PathFilter) RunsIn(dir string) bool

RunsIn returns true if this Runnable should run in the given directory. The directory should be relative to git root.

func (*PathFilter) SkipTask

func (p *PathFilter) SkipTask(task *FuncDef, paths ...string) *PathFilter

SkipTask configures a task to be skipped in specific paths. If no paths are specified, the task is skipped everywhere within this PathFilter. Paths support regex patterns matched against the current execution path. Returns a new *PathFilter (immutable).

Example:

pocket.Paths(golang.Workflow()).
    DetectBy(golang.Detect()).
    SkipTask(golang.Test, "tests/go", "tests/features").
    SkipTask(golang.Vulncheck)  // skip everywhere

type PlanStep

type PlanStep struct {
	Type     string      // "serial", "parallel", "func"
	Name     string      // Function name
	Usage    string      // Function usage/description
	Hidden   bool        // Whether this is a hidden function
	Deduped  bool        // Would be skipped due to deduplication
	Path     string      // Path context for path-filtered execution
	Children []*PlanStep // Nested steps (for serial/parallel groups)
}

PlanStep represents a single step in the execution plan.

type Runnable

type Runnable interface {
	// contains filtered or unexported methods
}

Runnable is the interface for anything that can be executed. It uses unexported methods to prevent external implementation, ensuring only pocket types (FuncDef, serial, parallel, PathFilter) can satisfy it.

Users create Runnables via:

  • pocket.Func() for individual functions
  • pocket.Serial() for sequential execution
  • pocket.Parallel() for concurrent execution
  • pocket.Paths() for path filtering

func Parallel

func Parallel(items ...any) Runnable

Parallel composes items to run concurrently.

Returns a Runnable that executes items in parallel. Use it to:

  • Run independent tasks concurrently: Parallel(Lint, Test)
  • Compose in Config: Parallel(task1, task2)

Items can be *FuncDef, Runnable, or func(context.Context) error.

Example:

var CI = pocket.Func("ci", "run CI", pocket.Parallel(
    Lint,
    Test,
))

func Serial

func Serial(items ...any) Runnable

Serial composes items to run sequentially.

Returns a Runnable that executes items in order. Use it to:

  • Define dependencies: Serial(Install, TaskImpl)
  • Compose tasks in Config: Serial(Format, Lint, Test)

Items can be *FuncDef, Runnable, or func(context.Context) error.

Example:

var Lint = pocket.Func("lint", "run linter", pocket.Serial(
    golangcilint.Install,
    func(ctx context.Context) error {
        return pocket.Exec(ctx, "golangci-lint", "run", "./...")
    },
))

type ShimConfig

type ShimConfig struct {
	// Name is the base name of the generated shim scripts (without extension).
	// Default: "pok"
	Name string

	// Posix generates a bash script (./pok).
	// This is enabled by default if ShimConfig is nil.
	Posix bool

	// Windows generates a batch file (pok.cmd).
	// The batch file requires Go to be installed and in PATH.
	Windows bool

	// PowerShell generates a PowerShell script (pok.ps1).
	// The PowerShell script can auto-download Go if not found.
	PowerShell bool
}

ShimConfig controls shim script generation.

type ToolConfig

type ToolConfig struct {
	// UserFiles are filenames to search for in the repo root.
	// Checked in order; first match wins.
	UserFiles []string

	// DefaultFile is the filename for the bundled default config,
	// written to .pocket/tools/<name>/ if no user config exists.
	DefaultFile string

	// DefaultData is the bundled default configuration content.
	DefaultData []byte
}

ToolConfig describes how to find or create a tool's configuration file.

Directories

Path Synopsis
cmd
pocket command
internal
scaffold
Package scaffold provides generation of .pocket/ scaffold files.
Package scaffold provides generation of .pocket/ scaffold files.
shim
Package shim provides generation of the ./pok wrapper scripts.
Package shim provides generation of the ./pok wrapper scripts.
Package tasks provides the entry point for running pocket tasks.
Package tasks provides the entry point for running pocket tasks.
github
Package github provides GitHub-related tasks.
Package github provides GitHub-related tasks.
golang
Package golang provides Go development tasks.
Package golang provides Go development tasks.
lua
Package lua provides Lua-related build tasks.
Package lua provides Lua-related build tasks.
markdown
Package markdown provides Markdown formatting tasks.
Package markdown provides Markdown formatting tasks.
python
Package python provides Python-related build tasks using ruff and mypy.
Package python provides Python-related build tasks using ruff and mypy.
tools
basedpyright
Package basedpyright provides basedpyright (Python static type checker) tool integration.
Package basedpyright provides basedpyright (Python static type checker) tool integration.
bun
Package bun provides bun runtime integration.
Package bun provides bun runtime integration.
golangcilint
Package golangcilint provides golangci-lint integration.
Package golangcilint provides golangci-lint integration.
govulncheck
Package govulncheck provides govulncheck integration.
Package govulncheck provides govulncheck integration.
mdformat
Package mdformat provides mdformat (Markdown formatter) tool integration.
Package mdformat provides mdformat (Markdown formatter) tool integration.
mypy
Package mypy provides mypy (Python static type checker) tool integration.
Package mypy provides mypy (Python static type checker) tool integration.
nvim
Package nvim provides Neovim tool integration.
Package nvim provides Neovim tool integration.
prettier
Package prettier provides prettier (code formatter) integration.
Package prettier provides prettier (code formatter) integration.
ruff
Package ruff provides ruff (Python linter and formatter) tool integration.
Package ruff provides ruff (Python linter and formatter) tool integration.
stylua
Package stylua provides stylua tool integration.
Package stylua provides stylua tool integration.
tsqueryls
Package tsqueryls provides ts_query_ls tool integration.
Package tsqueryls provides ts_query_ls tool integration.
uv
Package uv provides uv (Python package manager) tool integration.
Package uv provides uv (Python package manager) tool integration.

Jump to

Keyboard shortcuts

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