cli

package
v0.1.0-dev.20260127201926 Latest Latest
Warning

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

Go to latest
Published: Jan 27, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package cli provides shared CLI infrastructure for lore and writ.

Index

Constants

View Source
const (
	ExitOK          = 0  // Success
	ExitError       = 1  // Generic error
	ExitUsage       = 64 // Bad CLI syntax
	ExitDataErr     = 65 // Invalid manifest/config
	ExitNoInput     = 66 // File not found
	ExitUnavailable = 69 // Registry unreachable
	ExitSoftware    = 70 // Internal error (bug)
	ExitCantCreate  = 73 // Can't create file/symlink
	ExitIOErr       = 74 // Read/write failure
	ExitNoPerm      = 77 // Permission denied
)
View Source
const DefaultFormat = "json"

DefaultFormat is the default output format (JSON for scriptability).

Variables

View Source
var ErrManNotAvailable = errors.New("man command not available")

ErrManNotAvailable indicates the man command is not available on this system.

Functions

func AddMutationFlags

func AddMutationFlags(cmd *cobra.Command, flags *MutationFlags)

AddMutationFlags adds --passthru and --format flags for mutating commands. Mutating commands are silent by default; --passthru outputs what was changed. Usage:

var flags cli.MutationFlags
cli.AddMutationFlags(cmd, &flags)

func AddOutputFlags

func AddOutputFlags(cmd *cobra.Command, flags *OutputFlags)

AddOutputFlags adds --filter and --format flags to a command. Usage:

var output cli.OutputFlags
cli.AddOutputFlags(cmd, &output)

func AddSilentFlag

func AddSilentFlag(cmd *cobra.Command)

AddSilentFlag adds the --silent flag to a root command.

func AllSettings

func AllSettings() map[string]interface{}

AllSettings returns all settings as a map.

func BashCompletionPath

func BashCompletionPath() string

BashCompletionPath returns the bash completion directory. XDG_DATA_HOME/bash-completion/completions

func BindFlags

func BindFlags(cmd *cobra.Command, toolName string, useSharedConfig bool) error

BindFlags binds all persistent flags from a command to Viper. Call this after defining flags and before Execute().

Flags are bound with the tool's section prefix when using shared config:

  • --repo flag → viper key "writ.repo" (with UseSharedConfig)
  • --repo flag → viper key "repo" (without UseSharedConfig)

func BindFlagsWithPrefix

func BindFlagsWithPrefix(flags *pflag.FlagSet, prefix string) error

BindFlagsWithPrefix binds flags with a custom prefix. Useful for subcommands that need their own config section.

Example:

BindFlagsWithPrefix(addCmd.Flags(), "writ.add")
// --overwrite flag → viper key "writ.add.overwrite"

func CacheHome

func CacheHome() string

CacheHome returns XDG_CACHE_HOME or ~/.cache

func ConfigFileUsed

func ConfigFileUsed() string

ConfigFileUsed returns the config file path that Viper loaded. Returns empty string if no config file was found.

func ConfigHome

func ConfigHome() string

ConfigHome returns XDG_CONFIG_HOME or ~/.config

func DataHome

func DataHome() string

DataHome returns XDG_DATA_HOME or ~/.local/share

func Debug

func Debug()

Debug prints current Viper state for debugging.

func DisplayManPage

func DisplayManPage(cmd *cobra.Command, header *doc.GenManHeader) error

DisplayManPage generates a man page and displays it with the system pager. Returns ErrManNotAvailable if man is not available on this system.

func Error

func Error(format string, args ...interface{})

Error prints an error message to stderr. Unlike Failure, this does not return an error—use for non-fatal errors. Format: [program] [✖] message (red ✖)

func ExitCode

func ExitCode(err error) int

ExitCode extracts the exit code from an error. Returns the wrapped code if present, or ExitError (1) for plain errors.

func ExitWith

func ExitWith(code int, err error) error

ExitWith returns an error that carries a specific exit code.

func Failure

func Failure(format string, args ...interface{}) error

Failure prints an error message to stderr and returns an error. Use when the operation cannot continue. Format: [program] [✖] message (red ✖)

func FishCompletionPath

func FishCompletionPath() string

FishCompletionPath returns the fish completion directory. XDG_CONFIG_HOME/fish/completions

func Get

func Get(toolName, key string, useSharedConfig bool) interface{}

Get retrieves a config value with the tool's section prefix. When using shared config, automatically prefixes with tool name.

Example:

Get("writ", "repo", true)  → viper.Get("writ.repo")
Get("writ", "repo", false) → viper.Get("repo")

func GetBool

func GetBool(toolName, key string, useSharedConfig bool) bool

GetBool retrieves a boolean config value.

func GetInt

func GetInt(toolName, key string, useSharedConfig bool) int

GetInt retrieves an integer config value.

func GetString

func GetString(toolName, key string, useSharedConfig bool) string

GetString retrieves a string config value.

func GetStringMap

func GetStringMap(toolName, key string, useSharedConfig bool) map[string]interface{}

GetStringMap retrieves a string map config value.

func GetStringSlice

func GetStringSlice(toolName, key string, useSharedConfig bool) []string

GetStringSlice retrieves a string slice config value.

func InitViper

func InitViper(cfg ViperConfig) error

InitViper initializes Viper with standard devlore conventions. Call this in PersistentPreRunE of the root command.

Precedence (lowest to highest):

  1. Config file defaults
  2. Config file values
  3. Environment variables (TOOL_KEY_NAME)
  4. Command-line flags

Environment variable mapping:

  • WRIT_REPO → writ.repo (with UseSharedConfig)
  • WRIT_VARS_USER_NAME → writ.vars.user_name
  • Dots become underscores, keys are case-insensitive

func ManPath

func ManPath() string

ManPath returns the user man page directory: XDG_DATA_HOME/man/man1

func NewCompletionCmd

func NewCompletionCmd(rootCmd *cobra.Command) *cobra.Command

NewCompletionCmd creates the completion command for shell completions. Usage:

tool completion bash              # output to stdout
tool completion bash --install    # install to XDG_DATA_HOME
eval "$(tool completion bash)"

func NewConfigCmd

func NewConfigCmd(info ConfigInfo) *cobra.Command

NewConfigCmd creates the config command with git-style subcommands.

Dot-paths match the config file structure exactly. No implicit prefixing. "writ.repos.0.path" in the CLI reads writ.repos[0].path in the file. "secrets.mode" reads secrets.mode. WYSIWYG.

Usage:

tool config get <key>...                    # Get values
tool config set <key>=<value>...            # Set values
tool config unset <key>...                  # Remove keys
tool config list                            # List all settings
tool config edit                            # Open in $EDITOR
tool config validate                        # Validate against schema
tool config schema                          # Output JSON schema
tool config path                            # Show config file location

func NewHelpCmd

func NewHelpCmd(rootCmd *cobra.Command, header ManHeader) *cobra.Command

NewHelpCmd creates a help command that prefers man pages when available. This follows git's model: if man pages are installed, display them via pager; otherwise fall back to console text output.

func NewManCmd

func NewManCmd(rootCmd *cobra.Command, header ManHeader) *cobra.Command

NewManCmd creates the man command for displaying/installing man pages. Usage:

tool man              # display man page with pager
tool man --install    # install to ~/.local/share/man/man1/
tool man deploy       # display man page for subcommand

func NewSelfInstallCmd

func NewSelfInstallCmd(rootCmd *cobra.Command, info SelfInstallInfo) *cobra.Command

NewSelfInstallCmd creates the self-install command. Usage:

./tool self-install ~/.local
./tool self-install ~/.local --personal-repo=~/dotfiles

This performs complete installation:

  • Copies binary to <root>/bin/
  • Installs man pages to <root>/share/man/man1/
  • Installs completions for bash, zsh, fish
  • Initializes config in XDG_CONFIG_HOME
  • Initializes cache in XDG_CACHE_HOME
  • Scans and registers repos (if --personal-repo or --team-repo provided)

func NewVersionCmd

func NewVersionCmd(info VersionInfo) *cobra.Command

NewVersionCmd creates the version command.

func Note

func Note(format string, args ...interface{})

Note prints an informational message to stderr. Format: [program] [+] message (light gray +)

func RegisterRepo

func RegisterRepo(tool string, entry RepoEntry) error

RegisterRepo registers a repository in the shared config file. If a repo with the same layer already exists, it is replaced.

func Render

func Render(w io.Writer, data interface{}, flags OutputFlags) error

Render outputs data according to the format specification. Supported formats: json, yaml, table, or a Go template string.

func RenderMutation

func RenderMutation(w io.Writer, data interface{}, flags MutationFlags) error

RenderMutation outputs data only if --passthru is set. Returns nil without output if passthru is false.

func RenderMutationTo

func RenderMutationTo(data interface{}, flags MutationFlags) error

RenderMutationTo is a convenience function that renders to stdout if --passthru is set.

func RenderTo

func RenderTo(data interface{}, flags OutputFlags) error

RenderTo is a convenience function that renders to stdout.

func SetProgramName

func SetProgramName(name string)

SetProgramName sets the program name used in output prefixes.

func SetSilent

func SetSilent(s bool)

SetSilent enables or disables silent mode.

func SharedConfigPath

func SharedConfigPath() string

SharedConfigPath returns the path to the shared devlore config file.

func StateHome

func StateHome() string

StateHome returns XDG_STATE_HOME or ~/.local/state

func Success

func Success(format string, args ...interface{})

Success prints a success message to stderr. Format: [program] [✔] message (green ✔)

func ToolConfigPath

func ToolConfigPath(toolName string) string

ToolConfigPath returns the path to a tool-specific config file.

func UnregisterRepo

func UnregisterRepo(tool, layer string) error

UnregisterRepo removes a repository for the given layer from the shared config.

func Warn

func Warn(format string, args ...interface{})

Warn prints a warning message to stderr. Format: [program] [△] message (yellow △)

func ZshCompletionPath

func ZshCompletionPath() string

ZshCompletionPath returns the zsh completion directory. XDG_DATA_HOME/zsh/site-functions

Types

type ConfigInfo

type ConfigInfo struct {
	Name          string // Tool name (e.g., "lore", "writ")
	Schema        []byte // Embedded JSON schema
	DefaultConfig []byte // Default configuration content
}

ConfigInfo contains configuration metadata for a tool.

type ManHeader

type ManHeader struct {
	Title   string
	Section string
	Source  string
	Manual  string
}

ManHeader contains metadata for man page generation.

type Migration

type Migration struct {
	Issue    string   // what's wrong
	Commands []string // suggested git commands to fix it
}

Migration describes a recommended migration step.

type MutationFlags

type MutationFlags struct {
	Passthru bool
	Format   string
}

MutationFlags holds flags for mutating commands (--passthru).

type OutputFlags

type OutputFlags struct {
	Format string
	Filter []string
}

OutputFlags holds the --filter and --format flag values.

type ProjectInfo

type ProjectInfo struct {
	Name      string
	Path      string
	Segment   string // segment suffix (e.g., "Darwin", "Unix")
	FileCount int
	Templates int
	Secrets   int
}

ProjectInfo describes a detected project directory.

type RepoEntry

type RepoEntry struct {
	Layer string // "personal", "team", or "base"
	Path  string // Local filesystem path
	URL   string // Optional remote URL
	Name  string // Optional display name
}

RepoEntry represents a repository configuration entry.

type RepoScanResult

type RepoScanResult struct {
	Path string

	// Git information
	IsGit    bool
	Remote   string
	Branch   string
	Dirty    int // count of uncommitted changes
	GitError string

	// Structure detection
	Structure     RepoStructure
	HomePath      string // path to detected Home-equivalent directory
	Projects      []ProjectInfo
	NestedUnder   string // non-empty if projects are nested (e.g., "Configs")
	TemplateCount int
	SecretCount   int
	HasRecipients bool

	// Migration guidance
	Migrations []Migration
}

RepoScanResult holds the results of scanning a potential writ repository.

func ScanRepo

func ScanRepo(path string) *RepoScanResult

ScanRepo inspects a directory and reports on its suitability as a writ repository.

func (*RepoScanResult) NeedsMigration

func (r *RepoScanResult) NeedsMigration() bool

NeedsMigration returns true if the scan found issues that require migration.

func (*RepoScanResult) PrintReport

func (r *RepoScanResult) PrintReport()

PrintReport outputs the scan result to stderr.

type RepoStructure

type RepoStructure int

RepoStructure describes the detected repository layout.

const (
	StructureUnknown     RepoStructure = iota
	StructureCompatible                // Home/<project>/ with "." segments
	StructurePartial                   // Has Home/ but needs migration
	StructureTraditional               // Dotfiles at root
	StructureStow                      // Stow-like packages at root
)

func (RepoStructure) String

func (s RepoStructure) String() string

String returns a human-readable label for the structure type.

type SelfInstallInfo

type SelfInstallInfo struct {
	Name       string     // Tool name (e.g., "lore", "writ")
	ManHeader  ManHeader  // Man page header metadata
	ConfigInfo ConfigInfo // Config schema and defaults
}

SelfInstallInfo contains metadata needed for self-installation.

type VersionInfo

type VersionInfo struct {
	Version   string // Semantic version (e.g., "0.1.0")
	Commit    string // Git commit hash
	BuildDate string // Build timestamp
}

VersionInfo contains version metadata set at build time.

type ViperConfig

type ViperConfig struct {
	// Name is the tool name (e.g., "lore", "writ")
	Name string

	// EnvPrefix is the environment variable prefix (e.g., "LORE", "WRIT")
	// If empty, defaults to uppercase Name
	EnvPrefix string

	// ConfigName is the config file name without extension (default: "config")
	ConfigName string

	// ConfigType is the config file type (default: "yaml")
	ConfigType string

	// UseSharedConfig uses ~/.config/devlore/config.yaml with tool-specific section
	// When true, config is read from the tool's section (e.g., config.writ.repo)
	UseSharedConfig bool
}

ViperConfig holds configuration for Viper initialization.

Jump to

Keyboard shortcuts

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