exoskeleton

package module
v2.0.0-beta.1 Latest Latest
Warning

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

Go to latest
Published: Jan 28, 2026 License: Apache-2.0 Imports: 20 Imported by: 0

README

Exoskeleton

Exoskeleton is a library for creating modern multi-CLI applications whose commands are external to them.

Go Reference

Why Exoskeleton?

Exoskeleton is similar to frameworks like Cobra and Oclif in that it simplifies building subcommand-based command line applications (like git clone, git log) by providing:

  • nested subcommands and automatically generated menus of subcommands
  • tab-completion for shells
  • suggestions for mistyped commands ("Did you mean ...?")

Exoskeleton differs from other CLI frameworks in that each subcommand maps to a separate, standalone executable. This allows subcommands to be implemented in different languages and released on different schedules!

Exoskeleton's goal is to create a common entrypoint, better discoverability, and a cohesive experience for a decentralized suite of commandline tools.

Creating an Exoskeleton

Install Exoskeleton by running

go get -u github.com/square/exoskeleton@latest

The simplest Exoskeleton application looks like this:

package main

import (
	"os"

	"github.com/square/exit"
	"github.com/square/exoskeleton"
)

func main() {
	paths := []string{
		// paths
		// you want Exoskeleton to search
		// for subcommands
	}

	// 1. Create a new Command Line application that looks for subcommands in the given paths.
	cli, _ := exoskeleton.New(paths)

	// 2. Identify the subcommand being invoked from the arguments.
	cmd, args, _ := cli.Identify(os.Args[1:])

	// 3. Execute the subcommand.
	err := cmd.Exec(cli, args, os.Environ())

	// 4. Exit the program with the exit code the subcommand returned.
	os.Exit(exit.FromError(err))
}

① An exoskeleton is constructed with an array of paths to search for subcommands. ② It uses the arguments to identify which subcommand is being invoked. ③ The subcommand is executed ④ and the program exits (0 if err is nil, 1 or a semantic exit code otherwise).

To see this in action, take a look at the the Hello World example project.

In the real world, an application might also:

  1. Customize the exoskeleton by passing options to exoskeleton.New
  2. Add business logic between ② Identify and ③ Exec or ③ Exec and ④ os.Exit

[!TIP] At Square, we use the OnCommandNotFound callback to install subcommands on-demand, check for updates after constructing the exoskeleton, and wrap Exec to emit usage metrics.

Subcommands

Creating Subcommands

Subcommands can be either shell scripts or binaries.

  1. They MUST be executable.
  2. They SHOULD output help text to be displayed when the user invokes them with --help.
  3. They MAY respond to --summary by outputting a summary of their purpose to be displayed in a menu of commands.
  4. They MAY respond to --complete <input> by outputting a list of shell-completions for <input>.
Help and Summary Text

Compiled binaries should parse their arguments for the --help and --summary flags. They should do this early in execution before any expensive set up, write the text to standard out, and exit successfully.

Shell scripts which start with the shebang (#!) may respond to --help and --summary flags or may choose to document themselves with magic comments (# HELP: <help text follows>, # SUMMARY: <summary line follows>). See examples/hello_world/libexec/ls and examples/hello_world/libexec/rm for examples.

Completions

Exoskeleton uses shellcomp (the API that Cobra developed) to separate shell-specific logic for implementing completions from the logic for producing the suggestions themselves.

Shellcomp scripts invoke exoskeleton with --complete <WHATEVER THE USER TYPED> and expect to receive a list of suggestions on standard output.

[!NOTE] Imagine git is implemented with Exoskeleton.

If the user types

$ git che<tab>

then the shellcomp scripts will execute:

$ git complete che

and Exoskeleton will suggest completions from the list of commands it knows and output:

checkout
:4

and the shellcomp scripts will complete the command git checkout.

If the user types

$ git checkout lail/<tab>

then the shellcomp scripts will execute:

$ git complete checkout lail/

and Exoskeleton will dispatch the completion to the checkout command, executing this:

$ $(git which checkout) --complete -- checkout lail/

and, at this point, if git checkout handles --complete, it may list branches that start with lail/.

See shellcomp's docs for implementing completions for a subcommand.

Call exoskeleton.GenerateCompletionScript to generate the shellcomp scripts for your project.

[!TIP] At Square, we call this function in our Makefile and distribute artifacts for Bash and Zsh with releases.

Menus

As each subcommand maps to a standalone executable, submenus map to directories.

  1. The directory MUST contain a file named .exoskeleton (the file name is configurable).

Take a look at the dir module in the Hello World example project.

Upgrading from v1 to v2

Exoskeleton v2 merged the Module interface into the Command interface. exoskeleton.Module has been removed and Command implements Subcommands() (Commands, error). Leaf commands implement this simply by returning a non-empty slice (Commands{}).

Along with that change,

  • exoskeleton.EmbeddedModule was merged into exoskeleton.EmbeddedCommand
  • the exoskeleton.IsModule helper was removed
  • Parent() returns a Command instead of a Module
Migration Examples
Type assertions

If you used exoskeleton.Module for type assertions, you can now check whether a command has any subcommands.

// v1
if m, ok := cmd.(exoskeleton.Module); ok {
    children, _ := m.Subcommands()
    // ...
}

// v2
if children, _ := cmd.Subcommands(); len(children) > 0 {
    // ...
}

Documentation

Overview

Package exoskeleton allows you to create modern multi-CLI applications whose subcommands are external to them.

You use it by defining an Entrypoint and a list of paths where external subcommands may be found.

Here's an example:

Assuming we have two executables that respond to `--summary` like this:

   $ ~/libexec/rm --summary
   Remove directory entries

   $ ~/libexec/ls --summary
   List directory contents

And a binary, `example`, that is implemented like this:

   package main

   import (
       "os"

       "github.com/square/exoskeleton/v2"
   )

   func main() {
       exoskeleton.Exec([]string{os.Getenv("HOME") + "/libexec"})
   }

Then our example program will behave like this:

   $ ./example
   USAGE
      example <command> [<args>]

   COMMANDS
      ls  List directory contents
      rm  Remove directory entries

   Run example help <command> to print information on a specific command.

And running `example ls` will forward execution to `~/libexec/ls`.

Discovery Contracts

Exoskeleton uses a contract system to determine how commands and modules are discovered and built. Four default contracts are provided:

  • DirectoryModuleContract: Directories containing a .exoskeleton file
  • ExecutableModuleContract: Executables with .exoskeleton extension
  • ScriptCommandContract: Shell scripts with magic comments (# SUMMARY:, # HELP:)
  • ExecutableCommandContract: Executables that respond to --summary and --help

Users can customize discovery by providing their own contracts via WithContracts():

e, _ := exoskeleton.New(
    paths,
    exoskeleton.WithContracts(
        &MyCustomContract{},
        &exoskeleton.DirectoryModuleContract{},
    ),
)

Index

Constants

View Source
const CompleteHelp = `` /* 969-byte string literal not displayed */

CompleteHelp is the help text for the built-in 'complete' command.

View Source
const HelpHelp = `` /* 269-byte string literal not displayed */

HelpHelp is the help text for the built-in 'help' command.

View Source
const WhichHelp = `` /* 423-byte string literal not displayed */

WhichHelp is the help text for the built-in 'which' command.

Variables

View Source
var ErrNotApplicable = errors.New("contract does not apply")

ErrNotApplicable indicates that a contract does not apply to a given file/directory. Discovery will try the next contract in the list.

Functions

func CompleteCommands

func CompleteCommands(e *Entrypoint, args, env []string) ([]string, shellcomp.Directive, error)

CompleteCommands is a CompleteFunc that provides completions for command names. It is used by commands like 'help' and 'which' which expect their arguments to be command names.

func CompleteExec

func CompleteExec(e *Entrypoint, args, env []string) error

CompleteExec implements the 'complete' command.

func CompleteFiles

func CompleteFiles(e *Entrypoint, args, env []string) ([]string, shellcomp.Directive, error)

CompleteFiles is a CompleteFunc that provides completions for files and paths.

func Exec

func Exec(paths []string, options ...Option)

Exec constructs an Entrypoint with the given paths and options and executes it.

func GenerateCompletionScript

func GenerateCompletionScript(name, shell string, w io.Writer) (err error)

GenerateCompletionScript generates a completion script for the given shell ("bash" or "zsh") and writes it to the given writer.

func HelpExec

func HelpExec(e *Entrypoint, args, _ []string) error

HelpExec implements the 'help' command.

func IsEmbedded

func IsEmbedded(command Command) bool

IsEmbedded returns true if the given Command is built into the exoskeleton.

func IsNull

func IsNull(command Command) bool

IsNull returns true if the given Command is a NullCommand and false if it is not.

func MenuFor(cmd Command, opts *MenuOptions) (string, []error)

MenuFor renders a menu of commands for a Command with subcommands.

func Usage

func Usage(cmd Command) string

Usage returns the usage string for the given command. For example, given the Tidy command in the Go CLI, Usage(Tidy) would be 'go mod tidy'.

func UsageRelativeTo

func UsageRelativeTo(cmd Command, relativeTo Command) string

UsageRelativeTo returns the usage string for the given command relative to the given command. For example, given the Tidy command in the Go CLI ('go mod tidy'), UsageRelativeTo(Tidy, Mod) would be 'tidy' and UsageRelativeTo(Tidy, Go) would be 'mod tidy'.

func WhichExec

func WhichExec(e *Entrypoint, args, _ []string) error

WhichExec implements the 'which' command.

Types

type AfterIdentifyFunc

type AfterIdentifyFunc func(*Entrypoint, Command, []string)

AfterIdentifyFunc is a function that is called after a command is identified. It accepts the Command and the remaining arguments that were not used to identify the command.

type Cache

type Cache interface {
	// Fetch returns a cached value for the given command and key, or calls compute()
	// to generate it. If compute() returns an error, the error is returned and the
	// value is not cached.
	//
	// The key identifies the operation (e.g., "summary", "describe-commands").
	// Implementations typically use cmd.Path() combined with key to form a cache key,
	// and may use the file's modification time for cache invalidation.
	Fetch(cmd Command, key string, compute func() (string, error)) (string, error)
}

Cache provides caching for expensive string-producing operations. Implementations control their own expiry/invalidation logic.

Cache implementations must be safe for concurrent use.

type Command

type Command interface {
	// Path returns the location of the executable that defines the command.
	// For built-in commands, it returns the path to the entrypoint executable itself.
	// It is used by the built-in command 'which'.
	Path() string

	// Name returns the name of the command.
	Name() string

	// Parent returns the command that contains this command.
	//
	// For unnested commands, Parent returns the Entrypoint. For the Entrypoint,
	// Parent returns nil.
	//
	// In the Go CLI, 'go test' and 'go mod tidy' are both commands. If modeled with
	// Exoskeleton, 'tidy”s Parent would be the 'mod' command and 'test”s Parent
	// would be the entrypoint itself, 'go'.
	Parent() Command

	// Exec executes the command.
	Exec(e *Entrypoint, args, env []string) error

	// Complete asks the command to return completions.
	// It is used by the built-in command 'complete' which provides shell completions.
	Complete(e *Entrypoint, args, env []string) ([]string, shellcomp.Directive, error)

	// Summary returns the (short!) description of the command to be displayed
	// in menus.
	//
	// Returns a CommandError if the command does not fulfill the contract
	// for providing its summary.
	Summary() (string, error)

	// Help returns the help text for the command.
	//
	// Returns a CommandError if the command does not fulfill the contract
	// for providing its help.
	Help() (string, error)

	// Subcommands returns the list of Commands contained by this command.
	// Returns an empty slice for leaf commands (commands without subcommands).
	//
	// Returns a CommandError if the command does not fulfill the contract
	// for providing its subcommands.
	Subcommands() (Commands, error)
}

Command is a command in your CLI application.

In the Go CLI, 'go test' and 'go mod tidy' are both commands. Exoskeleton would model 'test' and 'tidy' as Commands. 'tidy' would be nested one level deeper than 'test', beneath a Command named 'mod'.

type CommandDescribeError

type CommandDescribeError struct{ CommandError }

CommandDescribeError indicates that an executable module did not properly respond to `--describe-commands`

type CommandError

type CommandError struct {
	Message string
	Cause   error
	Command Command
}

CommandError records an error that occurred with a command's implementation of its interface

func (CommandError) Error

func (e CommandError) Error() string

func (CommandError) Unwrap

func (e CommandError) Unwrap() error

type CommandHelpError

type CommandHelpError struct{ CommandError }

CommandHelpError indicates that a command did not properly implement the interface for providing help

type CommandNotFoundFunc

type CommandNotFoundFunc func(*Entrypoint, Command)

CommandNotFoundFunc is a function that accepts a Null Command object. It is called when a command is not found.

type CommandSummaryError

type CommandSummaryError struct{ CommandError }

CommandSummaryError indicates that a command did not properly implement the interface for providing a summary

type Commands

type Commands []Command

func (Commands) Expand

func (c Commands) Expand(fops ...ExpandOption) (Commands, []error)

Expand returns a list of commands, recursively replacing modules with their subcommands up to a given depth, along with any errors returned by modules' Subcommands().

func (Commands) Find

func (c Commands) Find(cmdName string) Command

Find returns the first command with a given name.

func (Commands) Flatten

func (c Commands) Flatten() (Commands, []error)

Flatten returns a list of commands, recursively replacing modules with their subcommands, along with any errors returned by modules' Subcommands().

type CompleteFunc

type CompleteFunc func(e *Entrypoint, args, env []string) ([]string, shellcomp.Directive, error)

CompleteFunc is called when an built-in command is asked to supply shell completions.

type Contract

type Contract interface {
	// BuildCommand constructs a Command using this contract's rules.
	// Returns ErrNotApplicable if this contract doesn't handle the file/directory.
	// Returns nil, nil if the file/directory should be ignored (e.g., non-executable file).
	BuildCommand(path string, info fs.DirEntry, parent Command, d DiscoveryContext) (Command, error)
}

Contract represents an agreement between Exoskeleton and a command about how the command is discovered.

Contracts are tried in order during discovery. The first contract that doesn't return ErrNotApplicable builds the command.

type DirectoryContract

type DirectoryContract struct {
	MetadataFilename string
}

DirectoryContract handles directories containing a module metadata file.

The module metadata filename is configured on the Entrypoint and passed through the discoverer, not stored on the contract itself.

func (*DirectoryContract) BuildCommand

func (c *DirectoryContract) BuildCommand(path string, info fs.DirEntry, parent Command, d DiscoveryContext) (Command, error)

type DiscoveryContext

type DiscoveryContext interface {
	DiscoverIn(path string, parent Command) (Commands, []error)
	Executor() ExecutorFunc
	MaxDepth() int
	Next() DiscoveryContext
	Cache() Cache
}

type DiscoveryError

type DiscoveryError struct {
	Cause error
	Path  string
}

DiscoveryError records an error that occurred while discovering commands in a directory.

func (DiscoveryError) Error

func (e DiscoveryError) Error() string

func (DiscoveryError) Unwrap

func (e DiscoveryError) Unwrap() error

type EmbeddedCommand

type EmbeddedCommand struct {
	Name     string
	Summary  string
	Help     string
	Exec     ExecFunc
	Complete CompleteFunc
	Commands []*EmbeddedCommand
}

EmbeddedCommand defines a built-in command that can be added to an Entrypoint (as opposed to an executable external to the Entrypoint).

type Entrypoint

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

Entrypoint is the root of an exoskeleton CLI application.

func New

func New(paths []string, options ...Option) (*Entrypoint, error)

New searches the given paths and constructs an Entrypoint with a list of commands discovered in those paths. It also accepts options that can be used to customize the behavior of the Entrypoint.

func (*Entrypoint) Complete

func (e *Entrypoint) Complete(_ *Entrypoint, args, _ []string) (completions []string, directive shellcomp.Directive, err error)

func (*Entrypoint) Exec

func (e *Entrypoint) Exec(_ *Entrypoint, rawArgs, env []string) error

func (*Entrypoint) GenerateCompletionScript

func (e *Entrypoint) GenerateCompletionScript(shell string, w io.Writer) error

GenerateCompletionScript generates a completion script for the given shell ("bash" or "zsh") and writes it to the given writer.

func (*Entrypoint) Help

func (e *Entrypoint) Help() (string, error)

func (*Entrypoint) Identify

func (e *Entrypoint) Identify(args []string) (Command, []string, error)

Identify identifies the command being invoked.

The function also returns any arguments that were not used to identify the command. For example, if the Go CLI were implemented with Exoskeleton, and we ran it with the rawArgs 'get -u github.com/square/exoskeleton/v2', Identify would return the Get command and the arguments {'-u', 'github.com/square/exoskeleton/v2'}.

If no command is identified, Identify invokes CommandNotFound callbacks and returns NullCommand.

Returns a CommandError if the command does not fulfill the contract for providing its subcommands.

func (*Entrypoint) Name

func (e *Entrypoint) Name() string

func (*Entrypoint) Parent

func (e *Entrypoint) Parent() Command

func (*Entrypoint) Path

func (e *Entrypoint) Path() string

func (*Entrypoint) Subcommands

func (e *Entrypoint) Subcommands() (Commands, error)

func (*Entrypoint) Summary

func (e *Entrypoint) Summary() (string, error)

type ErrorFunc

type ErrorFunc func(*Entrypoint, error)

ErrorFunc is called when an error occurs.

type ExecFunc

type ExecFunc func(e *Entrypoint, args, env []string) error

ExecFunc is called when an built-in command is run.

type ExecutableContract

type ExecutableContract struct {
}

ExecutableContract handles executables that respond to --describe-commands.

The extension is hardcoded to ".exoskeleton", and the --describe-commands flag is also hardcoded.

func (*ExecutableContract) BuildCommand

func (c *ExecutableContract) BuildCommand(path string, info fs.DirEntry, parent Command, d DiscoveryContext) (Command, error)

type ExecutorFunc

type ExecutorFunc func(*exec.Cmd) error

type ExpandOption

type ExpandOption func(*expandOptions)

func WithDepth

func WithDepth(d int) ExpandOption

func WithoutExpandedModules

func WithoutExpandedModules() ExpandOption

type FileCache

type FileCache struct {
	// Path is the location of the cache file (e.g., "~/.myapp/cache.json").
	Path string

	// ExpiresAfter is the maximum age of a cache entry before it's considered stale.
	// If zero, entries never expire based on age (only mtime changes invalidate).
	ExpiresAfter time.Duration
	// contains filtered or unexported fields
}

FileCache is a file-backed cache with mtime-based invalidation and optional TTL expiration. It persists cache entries to a JSON file and invalidates entries when the source file's mtime changes or the TTL expires.

FileCache is safe for concurrent use. It uses singleflight to deduplicate concurrent calls with the same key.

func (*FileCache) Fetch

func (c *FileCache) Fetch(cmd Command, key string, compute func() (string, error)) (string, error)
type Menu struct {
	Usage     string
	HelpUsage string
	Sections  MenuSections
}

Menu is the data passed to MenuOptions.Template when it is executed.

type MenuHeadingForFunc func(parent Command, cmd Command) string

MenuHeadingForFunc is a function that is expected to return the heading under which a command should be listed when it is printed in a menu. (The default value is "COMMANDS".)

It accepts the parent Command whose subcommands are being listed and the Command whose heading should be returned.

type MenuItem struct {
	Name    string
	Summary string
	Heading string
	Width   int
}
type MenuItems []*MenuItem
func (m MenuItems) Len() int
func (m MenuItems) Less(i, j int) bool
func (m MenuItems) MaxWidth() (longestCommand int)
func (m MenuItems) Swap(i, j int)
type MenuOptions struct {
	// Depth describes how recursively a menu should be constructed. Its default
	// value is 0, which indicates that the menu should list only the commands
	// that are descendants of the module. A value of 1 would list descendants one
	// level deep, a value of 2 would list descendants two levels deep, etc. A value
	// -1 lists all descendants.
	Depth int

	// HeadingFor accepts the parent Command and a subcommand, returning a
	// string to use as a section heading for the subcommand.
	// The default function returns "COMMANDS".
	HeadingFor MenuHeadingForFunc

	// SummaryFor accepts a Command and returns its summary and, optionally, an error.
	// The default function invokes Summary() on the provided Command.
	SummaryFor SummaryFunc

	// Template is executed with the constructed exoskeleton.Menu to render
	// help content for a Command with subcommands.
	Template *template.Template
}

MenuOptions are the options that control how menus are constructed for modules.

type MenuSection struct {
	Heading   string
	MenuItems MenuItems
}
type MenuSections []MenuSection

type Option

type Option interface {
	Apply(*Entrypoint)
}

An Option applies optional changes to an Exoskeleton Entrypoint.

func AfterIdentify

func AfterIdentify(fn AfterIdentifyFunc) Option

AfterIdentify registers a callback (AfterIdentifyFunc) to be invoked with any command that is successfully identified.

func AppendCommands

func AppendCommands(cmds ...*EmbeddedCommand) Option

AppendCommands adds new embedded commands to the Entrypoint. The commands are added to the end of the list and will have the lowest precedence: an executable with the same name as one of these commands would override it.

func OnCommandNotFound

func OnCommandNotFound(fn CommandNotFoundFunc) Option

OnCommandNotFound registers a callback (CommandNotFoundFunc) to be invoked when the command a user attempted to execute is not found. The callback is also invoked when the user asks for help on a command that can not be found.

func OnError

func OnError(fn ErrorFunc) Option

OnError registers a callback (ErrorFunc) to be invoked when a nonfatal error occurs.

These are recoverable errors such as

  • a broken symlink is encountered in one of the paths being searched
  • a command exits unnsuccessfully when invoked with --summary or --help

func PrependCommands

func PrependCommands(cmds ...*EmbeddedCommand) Option

PrependCommands adds new embedded commands to the Entrypoint. The command are added to the front of the list and will have the highest precedence: an executable with the same name as one of these commands would be overridden by it.

func WithCache

func WithCache(c Cache) Option

WithCache sets a cache for expensive operations like command execution. If not set, no caching is performed.

func WithContracts

func WithContracts(contracts ...Contract) Option

WithContracts sets the contracts used during discovery. Contracts are tried in order; the first that doesn't return ErrNotApplicable builds the command.

The default contracts are:

  1. DirectoryContract (directories that contain the module metadata file)
  2. ExecutableContract (executables with .exoskeleton extension which must implement --describe-commands)
  3. ShellScriptContract (shell scripts with magic comments)
  4. StandaloneExecutableContract (all other executables which must implement --summary)

func WithExecutor

func WithExecutor(value ExecutorFunc) Option

WithExecutor supplies a function that executes a subcommand. The default executor calls `Run()` on the command and returns the error.

func WithMaxDepth

func WithMaxDepth(value int) Option

WithMaxDepth sets the maximum depth of the command tree.

A value of 0 prohibits any submodules. All subcommands are leaves of the Entrypoint. (i.e. If the Go CLI were an exoskeleton, 'go doc' would be allowed, 'go mod tidy' would not.)

A value of -1 (the default value) means there is no maximum depth.

func WithMenuHeadingFor

func WithMenuHeadingFor(fn MenuHeadingForFunc) Option

WithMenuHeadingFor allows you to supply a function that determines the heading a Command should be listed under in the main menu.

func WithMenuTemplate

func WithMenuTemplate(value *template.Template) Option

WithMenuTemplate sets the template that will be used to render help for modules. The template will be executed with an instance of exoskeleton.Menu as its data.

func WithModuleMetadataFilename

func WithModuleMetadataFilename(value string) Option

WithModuleMetadataFilename sets the filename to use for module metadata. (Default: ".exoskeleton")

func WithName

func WithName(value string) Option

WithName sets the name of the entrypoint. (By default, this is the basename of the executable.)

type ShellScriptContract

type ShellScriptContract struct{}

ShellScriptContract handles shell scripts with magic comments.

Scripts are detected by checking for a shebang (#!) at the start of the file. They provide metadata via magic comments like "# SUMMARY:" and "# HELP:".

func (*ShellScriptContract) BuildCommand

func (c *ShellScriptContract) BuildCommand(path string, info fs.DirEntry, parent Command, d DiscoveryContext) (Command, error)

type StandaloneExecutableContract

type StandaloneExecutableContract struct{}

StandaloneExecutableContract handles executable files that respond to --summary and --help.

Note: This contract should be ordered AFTER ScriptCommandContract and ExecutableModuleContract in the contract list, as it matches all executable files.

func (*StandaloneExecutableContract) BuildCommand

func (c *StandaloneExecutableContract) BuildCommand(path string, info fs.DirEntry, parent Command, d DiscoveryContext) (Command, error)

type SummaryFunc

type SummaryFunc func(Command) (string, error)

SummaryFunc is a function that is expected to return the heading

type SymlinkError

type SymlinkError struct {
	Cause error
	Path  string
}

SymlinkError records an error that occurred while following a symlink.

func (SymlinkError) Error

func (e SymlinkError) Error() string

func (SymlinkError) Unwrap

func (e SymlinkError) Unwrap() error

Directories

Path Synopsis
pkg
shellcomp
The constants in this file are taken from https://github.com/spf13/cobra/blob/v1.5.0/completions.go
The constants in this file are taken from https://github.com/spf13/cobra/blob/v1.5.0/completions.go

Jump to

Keyboard shortcuts

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