// Package sink assists in building out consistent CLI plumbing. // // `sink` is inspired by github.com/peterbourgon/ff/v3/ffcli. // // The [Command] struct provides a declarative surface area for specifying trees // of commands. CLI authors can configure [Extension] for individual Commands // to reuse common functionality like configuration file loading, log decorating, // client instantiation, and any other execution state. // // When a Command is ran, a [Run] containing CLI machinery and execution state // is created for the lifetime of the Command's execution and passed through any // extensions that provide lifecycle hooks (e.g., [BeforeRunner] or [AfterRunner]). // // # Command Lifecycle // // - [Command.Parse]: // - The command tree is computed: FlagSets are created and flags are bound // - The FlagSet is parsed // - Based on input, the intended Command is selected for execution // // - [Command.Run], for the Command selected during [Command.Parse]: // - Configured extensions that implement [BeforeRunner] are invoked // - Command.Exec is invoked // - Configured extensions that implement [AfterRunner] are invoked // // # Design // // The design of this package is chiefly driven by a few principles: // // - Follow Go's guidance around using [context.Context]: https://github.com/golang/go/wiki/CodeReviewComments#contexts // - Don't implement custom contexts or use non-Context interfaces as parameters: // Persistent execution-scoped state is passed as a second, non-Context // parameter of type [Run], ensuring that top-level context functions such // as [context.WithValue] work in the expected way. // // - Clearly separate the declarative setup of commands from the execution state. // - Enable extensible CLI implementations without bloating the base Command API // or become a "kitchen sink" package. Extensions should be loosely coupled to // the core Command implementation without diminishing their usefulness. // - Avoid the state and scope creep that is associated with passing the // parsed command to CLI functions. The [Run] object allows sink to make the // command available to CLI execution without making it the primary surface // area for execution-scoped state. package sink