toolkit

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Dec 8, 2025 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNoEnvKey      = errors.New("env key missing")
	ErrEscapeAttempt = errors.New("path escape attempt: operation would access path outside jail")
)
View Source
var DefaultEditor = "nano"

Functions

func AbsPath

func AbsPath(ctx context.Context, rel string) string

AbsPath returns a cleaned absolute path for the provided path. Behavior: - If path is empty, returns empty string. - Expands a leading tilde using ExpandPath with the Env from ctx. - Expands environment variables from the injected env in ctx. - If the path is not absolute, attempts to convert it to an absolute path. - Returns a cleaned path in all cases.

If ExpandPath fails (for example when HOME is not available) AbsPath falls back to the original input and proceeds with expansion of environment variables and cleaning.

func AtomicWriteFile

func AtomicWriteFile(ctx context.Context, rel string, data []byte, perm os.FileMode) error

func CreateTestStdio deprecated

func CreateTestStdio(content string) (*os.File, func())

Deprecated: CreateTestStdio is unstable and may change in future releases.

CreateTestStdio creates a temporary file prefilled with the given content and seeks it to the beginning, making it suitable to pass as a stand-in for stdin, stdout, or stderr in tests.

It returns the open *os.File and a cleanup function. The cleanup function closes the file and removes it from disk. The function panics on any error while creating, writing, or seeking the temporary file; this makes test setup failures immediately visible.

Example usage in tests:

f, cleanup := CreateTestStdio("input text")
defer cleanup()
// pass f where a *os.File is needed

The returned file is created in the OS temporary directory using the pattern "test-stdio-*".

func DumpEnv

func DumpEnv(ctx context.Context) string

DumpEnv returns a sorted, newline separated representation of the environment visible via the Env stored in ctx. Each line is formatted as "KEY=VALUE".

For TestEnv and OsEnv the function enumerates the known keys. For other Env implementations the function attempts to use common helper methods (Environ or Keys) if available. If enumeration is not possible a short message is returned indicating that limitation.

func Edit

func Edit(ctx context.Context, path string) error

Edit launches the user's editor to edit the provided file path. It checks $VISUAL first, then $EDITOR. If neither is set, it falls back to "nano". The function attaches the current process's stdio to the editor so interactive editors work as expected.

func EnsureInJail

func EnsureInJail(jail, p string) string

EnsureInJail returns a path that resides inside jail when possible.

If the path is already inside jail, the cleaned absolute form is returned. Otherwise a path under jail is returned by appending the base name of the path.

func EnsureInJailFor

func EnsureInJailFor(jail, p string) string

EnsureInJailFor is a test-friendly helper that mirrors EnsureInJail but accepts paths written with forward slashes.

It converts both jail and p using filepath.FromSlash before applying the EnsureInJail logic. Use this from tests when expected values are easier to express using POSIX-style literals.

func ExpandEnv

func ExpandEnv(ctx context.Context, s string) string

ExpandEnv expands $var or ${var} in s using the Env stored in ctx. If no Env is present in the context the real OS environment is used via OsEnv.

func ExpandPath

func ExpandPath(ctx context.Context, p string) (string, error)

ExpandPath expands a leading tilde in the provided path to the user's home directory obtained from the Env stored in ctx. Supported forms:

"~"
"~/rest/of/path"
"~\rest\of\path" (Windows)

If the home directory cannot be obtained from the environment an error is returned. If the path does not start with a tilde it is returned unchanged.

func GetDefault

func GetDefault(env Env, key, other string) string

GetDefault returns the value of key from env when present and non-empty. Otherwise it returns the provided fallback value. Use this helper when a preference for an environment value is desired while still allowing a concrete default.

func GetTempDir added in v0.4.0

func GetTempDir(ctx context.Context) string

func Glob added in v0.3.0

func Glob(ctx context.Context, pattern string) ([]string, error)

Glob returns the names of all files matching the pattern using the Env stored in ctx. This enables glob patterns to work within sandboxed test environments. The pattern is expanded (handling ~) and then glob-matched. For TestEnv, results are restricted to within the jail boundary.

func IsInJail

func IsInJail(jail, rel string) bool

IsInJail reports whether the provided path resides within the jail boundary.

If jail is empty, the function returns true (no boundary). Relative paths always are in the jail

func IsInteractiveTerminal

func IsInteractiveTerminal(f *os.File) bool

IsInteractiveTerminal reports whether the provided file is connected to an interactive terminal.

This delegates to golang.org/x/term.IsTerminal and returns true when the file descriptor refers to a terminal device (TTY). Pass os.Stdin to check the program's standard input.

Notes:

  • The check uses the file descriptor (f.Fd()) and will return false for pipes, redirected files, and other non-terminal descriptors.
  • It is a non-destructive check and does not change the file position.

func Mkdir

func Mkdir(ctx context.Context, rel string, perm os.FileMode, all bool) error

Mkdir creates a directory using the Env stored in ctx. If all is true MkdirAll is used.

func ReadDir

func ReadDir(ctx context.Context, rel string) ([]os.DirEntry, error)

ReadDir reads the directory named by name and returns a list of entries. The path is expanded using ExpandPath with the Env from ctx before calling os.ReadDir.

func ReadFile

func ReadFile(ctx context.Context, rel string) ([]byte, error)

ReadFile reads the named file using the Env stored in ctx. This ensures the filesystem view can be controlled by an injected TestEnv.

func RelativePath

func RelativePath(ctx context.Context, basepath, path string) string

RelativePath returns a path relative to basepath. If path is empty an empty string is returned. If computing the relative path fails the absolute target path is returned.

func Remove

func Remove(ctx context.Context, rel string, all bool) error

Remove removes the named file or directory using the Env stored in ctx. If all is true RemoveAll is used.

func RemoveJailPrefix

func RemoveJailPrefix(jail, path string) string

RemoveJailPrefix removes the jail prefix from a path and returns an absolute path.

func Rename

func Rename(ctx context.Context, src, dst string) error

Rename renames (moves) a file or directory using the Env stored in ctx.

func ResolvePath

func ResolvePath(ctx context.Context, rel string, follow bool) (string, error)

ResolvePath returns the absolute path with symlinks evaluated. If symlink evaluation fails the absolute path returned by AbsPath is returned instead.

func Stat

func Stat(ctx context.Context, rel string, followSymlinks bool) (os.FileInfo, error)

Stat returns the os.FileInfo for the named file. The path is expanded using ExpandPath with the Env from ctx before calling os.Stat.

func StdinHasData

func StdinHasData(f *os.File) bool

StdinHasData reports whether the provided file appears to be receiving piped or redirected input (for example: `echo hi | myprog` or `myprog < file.txt`).

The implementation performs a lightweight metadata check: it returns true when the file is not a character device (that is, not a terminal). This is a common, portable heuristic used to detect piped input.

Notes and caveats:

  • The check does not attempt to read from the file. It only inspects the file mode returned by Stat().
  • For pipes this indicates stdin is coming from a pipe or redirect, but it does not strictly guarantee that bytes are immediately available to read. An open pipe may be empty until the writer writes to it.
  • If f.Stat() returns an error the function conservatively returns false.
  • Callers should pass os.Stdin to check the program's standard input, or a *os.File pointing to another stream for testing.

Example:

if StdinHasData(os.Stdin) {
    // read from stdin
}
func Symlink(ctx context.Context, oldname, newname string) error

Symlink creates a symbolic link pointing to oldname named newname. The oldname and newname are expanded using ExpandPath with the Env from ctx before creating the symlink. If symlink creation fails an error is returned.

func UserCachePath

func UserCachePath(ctx context.Context) (string, error)

UserCachePath returns the directory that should be used to store per-user cache files.

Behavior:

  • On Unix-like systems: prefers XDG_CACHE_HOME if set.
  • On Windows: prefers LOCALAPPDATA if set.
  • Falls back to $HOME/.cache when no appropriate environment variable is set.

The returned path is the base cache directory; append appName if you want an application-specific subdirectory.

func UserConfigPath

func UserConfigPath(ctx context.Context) (string, error)

UserConfigPath returns the directory that should be used to store per-user configuration files.

Behavior:

  • On Unix-like systems: prefers XDG_CONFIG_HOME if set; otherwise falls back to $HOME/.config.
  • On Windows: prefers APPDATA (via the provided env) if set.

The function returns the raw directory value as used by the platform. Callers should append an application-specific subdirectory if desired.

func UserDataPath

func UserDataPath(ctx context.Context) (string, error)

UserDataPath returns the directory that should be used to store per-user application data.

Behavior:

  • On Windows: uses LOCALAPPDATA and returns a "data" directory under it. If LOCALAPPDATA is not set, the function returns an error that wraps ErrNoEnvKey.
  • On Unix-like systems: prefers XDG_DATA_HOME if set; otherwise falls back to ~/.local/share.

Callers should append an application-specific subdirectory if desired.

func UserStatePath

func UserStatePath(ctx context.Context) (string, error)

UserStatePath returns the directory that should be used to store per-user state files for an application (transient runtime state).

Behavior:

  • On Windows: uses LOCALAPPDATA and returns a "state" directory under it. If LOCALAPPDATA is not set, the function returns an error that wraps ErrNoEnvKey.
  • On Unix-like systems: prefers XDG_STATE_HOME if set; otherwise falls back to ~/.local/state.

Callers should append an application-specific subdirectory if desired.

func WithEnv

func WithEnv(ctx context.Context, env Env) context.Context

WithEnv returns a copy of ctx that carries env. Use this to inject a test environment into code under test.

func WithHasher

func WithHasher(ctx context.Context, h Hasher) context.Context

WithHasher returns a copy of ctx that carries the provided Hasher. Use this to inject a custom hasher for tests or alternative hashing strategies.

func WithStream

func WithStream(ctx context.Context, s *Stream) context.Context

WithStream returns a copy of ctx that carries the provided Stream. Use this to inject custom I/O streams for testing or alternative stream configurations.

func WriteFile

func WriteFile(ctx context.Context, rel string, data []byte, perm os.FileMode) error

WriteFile writes data to a file using the Env stored in ctx. The perm argument is the file mode to apply to the written file.

Types

type Env

type Env interface {
	FileSystem

	// Name of the environment
	Name() string

	// Get returns the raw environment value for key. The return value may be
	// empty when the key is not present.
	Get(key string) string

	// Set assigns the environment key to value.
	Set(key, value string) error

	// Has reports whether the environment key is set.
	Has(key string) bool

	// Environ returns a copy of the environment as a slice of strings in the
	// form "KEY=VALUE".
	Environ() []string

	// Unset removes the environment key.
	Unset(key string)

	// GetHome returns the user's home directory. Implementations should return
	// an error if the value is not available.
	GetHome() (string, error)

	// SetHome sets the user's home directory in the environment.
	SetHome(home string) error

	// GetUser returns the current user's username. Implementations should
	// return an error if the value is not available.
	GetUser() (string, error)

	// SetUser sets the current user's username in the environment.
	SetUser(user string) error

	// Getwd returns the working directory as seen by this Env. For OsEnv this
	// is the process working directory; for TestEnv it is the stored PWD.
	Getwd() (string, error)

	// Setwd sets the working directory for this Env. For OsEnv this may change
	// the process working directory; for TestEnv it updates the stored PWD.
	Setwd(dir string)

	// GetTempDir returns an appropriate temp directory for this Env. For OsEnv
	// this delegates to os.TempDir(); TestEnv provides testable fallbacks.
	GetTempDir() string

	// ResolvePath resolves that path. Follows symlinks and returns the absolute
	// path
	ResolvePath(rel string, follow bool) (string, error)
}

Env is a compact interface for reading and modifying environment values. Implementations may reflect the real process environment (OsEnv) or provide an in-memory view suitable for tests (TestEnv).

The interface mirrors common environment operations so callers can inject a test implementation for unit tests without touching the real process env.

func EnvFromContext

func EnvFromContext(ctx context.Context) Env

EnvFromContext returns the Env stored in ctx. If ctx is nil or does not contain an Env, the real OsEnv is returned.

type FileSystem

type FileSystem interface {
	// ReadFile reads the named file.
	ReadFile(rel string) ([]byte, error)

	// WriteFile writes data to a file with the given permissions.
	WriteFile(rel string, data []byte, perm os.FileMode) error

	// Mkdir creates a directory. If all is true, MkdirAll is used.
	Mkdir(rel string, perm os.FileMode, all bool) error

	// Remove removes the named file or directory. If all is true, RemoveAll is used.
	Remove(rel string, all bool) error

	// Rename renames (moves) a file or directory.
	Rename(src, dst string) error

	// Stat returns the os.FileInfo for the named file.
	Stat(name string, followSymlinks bool) (os.FileInfo, error)

	// ReadDir reads the directory and returns a list of entries.
	ReadDir(rel string) ([]os.DirEntry, error)

	Symlink(oldname, newname string) error

	Glob(pattern string) ([]string, error)

	AtomicWriteFile(rel string, data []byte, perm os.FileMode) error
}

FileSystem defines the contract for filesystem operations. Implementations may reflect the real filesystem (OsEnv) or provide an in-memory view suitable for tests (TestEnv).

type Hasher

type Hasher interface {
	Hash(data []byte) string
}

Hasher computes a deterministic short hash for a byte slice. Implementations should return a textual representation suitable for inclusion in meta fields.

var DefaultHasher Hasher = &MD5Hasher{}

DefaultHasher is the fallback hasher used when none is provided via context.

func HasherFromContext

func HasherFromContext(ctx context.Context) Hasher

HasherFromContext returns the Hasher stored in ctx. If ctx is nil or does not contain a Hasher, DefaultHasher is returned.

type MD5Hasher

type MD5Hasher struct{}

MD5Hasher is a simple Hasher implementation that returns an MD5 hex digest.

Note: MD5 is used here for deterministic, compact hashes only and is not intended for cryptographic integrity protection.

func (*MD5Hasher) Hash

func (m *MD5Hasher) Hash(data []byte) string

Hash implements Hasher by returning the lowercase hex MD5 of the trimmed input bytes.

type OsEnv

type OsEnv struct{}

OsEnv is an Env implementation that delegates to the real process environment and filesystem. Use this in production code where access to the actual OS environment is required.

func (*OsEnv) AtomicWriteFile

func (o *OsEnv) AtomicWriteFile(rel string, data []byte, perm os.FileMode) error

func (*OsEnv) Environ

func (o *OsEnv) Environ() []string

Environ returns a copy of the process environment in "key=value" form.

func (*OsEnv) ExpandPath

func (o *OsEnv) ExpandPath(p string) string

func (*OsEnv) Get

func (o *OsEnv) Get(key string) string

Get returns the environment variable for key.

func (*OsEnv) GetHome

func (o *OsEnv) GetHome() (string, error)

GetHome returns the home directory reported by the OS. It delegates to os.UserHomeDir.

func (*OsEnv) GetTempDir

func (o *OsEnv) GetTempDir() string

GetTempDir returns the OS temporary directory.

func (*OsEnv) GetUser

func (o *OsEnv) GetUser() (string, error)

GetUser returns the current OS user username. If the Username field is empty it falls back to the user's Name field.

func (*OsEnv) Getwd

func (o *OsEnv) Getwd() (string, error)

Getwd returns the current process working directory.

func (*OsEnv) Glob added in v0.3.0

func (o *OsEnv) Glob(pattern string) ([]string, error)

func (*OsEnv) Has

func (o *OsEnv) Has(key string) bool

Has reports whether the given environment key is present.

func (*OsEnv) Mkdir

func (o *OsEnv) Mkdir(path string, perm os.FileMode, all bool) error

Mkdir creates a directory. If all is true MkdirAll is used.

func (*OsEnv) Name

func (o *OsEnv) Name() string

func (*OsEnv) ReadDir

func (o *OsEnv) ReadDir(rel string) ([]os.DirEntry, error)

func (*OsEnv) ReadFile

func (o *OsEnv) ReadFile(name string) ([]byte, error)

ReadFile reads the named file from the real filesystem.

func (*OsEnv) Remove

func (o *OsEnv) Remove(path string, all bool) error

Remove removes the named file or directory. If all is true all items in the path are removed.

func (*OsEnv) Rename

func (o *OsEnv) Rename(src, dst string) error

Rename renames (moves) a file or directory.

func (*OsEnv) ResolvePath

func (o *OsEnv) ResolvePath(rel string, follow bool) (string, error)

ResolvePath implements FileSystem.

func (*OsEnv) Set

func (o *OsEnv) Set(key string, value string) error

Set sets the OS environment variable key to value.

func (*OsEnv) SetHome

func (o *OsEnv) SetHome(home string) error

SetHome sets environment values that represent the user's home directory.

On Windows it also sets USERPROFILE to satisfy common callers.

func (*OsEnv) SetUser

func (o *OsEnv) SetUser(username string) error

SetUser sets environment values that represent the current user.

On Windows it also sets USERNAME in addition to USER.

func (*OsEnv) Setwd

func (o *OsEnv) Setwd(dir string)

Setwd attempts to change the process working directory to dir.

It also attempts to update PWD. Chdir errors are intentionally ignored to avoid surprising callers.

func (*OsEnv) Stat

func (o *OsEnv) Stat(name string, follow bool) (os.FileInfo, error)
func (o *OsEnv) Symlink(oldname string, newname string) error

func (*OsEnv) Unset

func (o *OsEnv) Unset(key string)

Unset removes the OS environment variable.

func (*OsEnv) WriteFile

func (o *OsEnv) WriteFile(name string, data []byte, perm os.FileMode) error

WriteFile writes data to a file on the real filesystem with the given permissions.

type Stream

type Stream struct {
	// In is the input stream, typically os.Stdin.
	In io.Reader
	// Out is the output stream, typically os.Stdout.
	Out io.Writer
	// Err is the error stream, typically os.Stderr.
	Err io.Writer

	// IsPiped indicates whether stdin appears to be piped or redirected.
	IsPiped bool
	// IsTTY indicates whether stdout refers to a terminal.
	IsTTY bool
}

Stream models the standard IO streams and common stream properties.

Struct field tags are included for clarity to external consumers that may wish to encode some stream metadata. The actual reader and writer fields are not suitable for encoding and therefore are tagged to be ignored.

func DefaultStream

func DefaultStream() *Stream

DefaultStream returns a Stream configured with the real process standard input, output, and error streams. It detects whether stdin is piped and whether stdout is a terminal.

func StreamFromContext

func StreamFromContext(ctx context.Context) *Stream

StreamFromContext returns the Stream stored in ctx. If ctx is nil or does not contain a Stream, DefaultStream() is returned.

type TestEnv

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

TestEnv is an in-memory Env implementation useful for tests. It does not touch the real process environment and therefore makes tests hermetic.

The home and user fields satisfy GetHome and GetUser. The data map stores other keys. For convenience, setting or unsetting the keys "HOME" and "USER" updates the corresponding home and user fields.

func NewTestEnv

func NewTestEnv(jail, home, username string) *TestEnv

NewTestEnv constructs a TestEnv populated with sensible defaults for tests. It sets HOME and USER and also sets platform specific variables so functions that prefer XDG_* on Unix or APPDATA/LOCALAPPDATA on Windows will pick them up.

If home or username are empty, reasonable defaults are chosen:

  • home defaults to EnsureInJailFor(jail, "/home/<username>")
  • username defaults to "testuser"

The function does not create directories on disk. It only sets environment values in the returned TestEnv.

func (*TestEnv) AtomicWriteFile

func (m *TestEnv) AtomicWriteFile(rel string, data []byte, perm os.FileMode) error

func (*TestEnv) Clone

func (m *TestEnv) Clone() *TestEnv

Clone returns a copy of the TestEnv so tests can modify the returned environment without mutating the original. It deep copies the internal map and makes a copy of the Stream struct.

func (*TestEnv) Environ

func (m *TestEnv) Environ() []string

Environ returns a slice of "KEY=VALUE" entries representing the environment stored in the TestEnv. It guarantees HOME and USER are present when set.

func (*TestEnv) ExpandPath

func (m *TestEnv) ExpandPath(p string) string

ExpandPath expands a leading tilde in the provided path to the TestEnv home. Supported forms:

"~"
"~/rest/of/path"
"~\rest\of\path" (Windows)

If the path does not start with a tilde it is returned unchanged. This method uses the TestEnv GetHome value. If home is not set, expansion may produce an empty or unexpected result.

func (TestEnv) Get

func (m TestEnv) Get(key string) string

Get returns the stored value for key. Reading from a nil map returns the zero value, so this method is safe on a zero TestEnv. The special keys HOME and USER come from dedicated fields.

func (*TestEnv) GetHome

func (m *TestEnv) GetHome() (string, error)

GetHome returns the configured home directory or an error if it is not set.

For TestEnv the returned home is guaranteed to be located within the configured jail when possible. This helps keep tests hermetic by ensuring paths used for home are under the test temporary area.

func (*TestEnv) GetJail

func (m *TestEnv) GetJail() string

func (*TestEnv) GetTempDir

func (m *TestEnv) GetTempDir() string

GetTempDir returns a temp directory appropriate for the TestEnv. If the receiver is nil this falls back to os.TempDir to avoid panics.

The method prefers explicit TMPDIR/TEMP/TMP values stored in the TestEnv. On Windows it applies a series of fallbacks: LOCALAPPDATA, APPDATA, USERPROFILE, then a home based default. On Unix like systems it falls back to /tmp.

The returned path will be adjusted to reside inside the configured jail when possible to keep test artifacts contained.

func (*TestEnv) GetUser

func (m *TestEnv) GetUser() (string, error)

GetUser returns the configured username or an error if it is not set.

func (*TestEnv) Getwd

func (m *TestEnv) Getwd() (string, error)

Getwd returns the TestEnv's PWD value if set, otherwise an error.

func (*TestEnv) Glob added in v0.3.0

func (m *TestEnv) Glob(pattern string) ([]string, error)

func (*TestEnv) Has

func (m *TestEnv) Has(key string) bool

Has reports whether the given key is present in the TestEnv map.

func (*TestEnv) Mkdir

func (m *TestEnv) Mkdir(rel string, perm os.FileMode, all bool) error

Mkdir creates a directory. If all is true MkdirAll is used.

func (*TestEnv) Name

func (o *TestEnv) Name() string

func (*TestEnv) ReadDir

func (m *TestEnv) ReadDir(name string) ([]os.DirEntry, error)

ReadDir implements FileSystem.

func (*TestEnv) ReadFile

func (m *TestEnv) ReadFile(rel string) ([]byte, error)

ReadFile reads the named file from the filesystem view held by this TestEnv. When the receiver is nil the real filesystem is used.

func (*TestEnv) Remove

func (m *TestEnv) Remove(rel string, all bool) error

Remove removes the named file or directory. If all is true RemoveAll is used. When the receiver is nil the real filesystem is affected.

func (*TestEnv) Rename

func (m *TestEnv) Rename(src string, dst string) error

Rename renames (moves) a file or directory. When the receiver is nil the operation is performed on the real filesystem.

func (*TestEnv) ResolvePath

func (m *TestEnv) ResolvePath(rel string, follow bool) (string, error)

func (*TestEnv) Set

func (m *TestEnv) Set(key string, value string) error

Set stores a key/value pair in the TestEnv. If key is "HOME" or "USER" the corresponding dedicated field is updated. Calling Set on a nil receiver returns an error rather than panicking.

func (*TestEnv) SetHome

func (m *TestEnv) SetHome(rel string) error

SetHome sets the TestEnv home directory and updates the "HOME" key in the underlying map for callers that read via Get.

func (*TestEnv) SetUser

func (m *TestEnv) SetUser(username string) error

SetUser sets the TestEnv current user and updates the "USER" key in the underlying map for callers that use Get.

func (*TestEnv) Setwd

func (m *TestEnv) Setwd(dir string)

Setwd sets the TestEnv's PWD value to the provided directory.

func (*TestEnv) Stat

func (m *TestEnv) Stat(rel string, followSymlinks bool) (os.FileInfo, error)

Stat implements FileSystem.

func (o *TestEnv) Symlink(oldname string, newname string) error

func (*TestEnv) Unset

func (m *TestEnv) Unset(key string)

Unset removes a key from the TestEnv. If key is "HOME" or "USER" the corresponding field is cleared. Calling Unset on a nil receiver is a no-op.

func (*TestEnv) WriteFile

func (m *TestEnv) WriteFile(name string, data []byte, perm os.FileMode) error

WriteFile writes data to a file in the filesystem view held by this TestEnv.

Jump to

Keyboard shortcuts

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