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