Dependency Injection (Props)¶
The Props struct is the "Context Object" of GTB. It acts as a dependency injection container that carries global state, service interfaces, and tool metadata throughout your application's lifecycle.
What's in a Name?
The name Props is not merely a shorthand for 'properties' (though we do shove plenty of those in there). Itβs a direct reference to a prop, the heavy-duty timber or steel beam that prevents a structure from an embarrassing collapse. For the sports fans, itβs also a lovingly crafted nod to the rugby position: the broad-shouldered stalwarts who provide the primary structural support for the scrum. Much like its on-field namesake, our Props struct isn't here to score the flashy tries; it's here to do the unsung heavy lifting that keeps the entire framework from falling over.
The Props Struct¶
Defined in pkg/props, the Props object typically contains:
Tool: Metadata about your CLI (Name, Summary, GitHub Org/Repo).Logger: A unified logger abstraction (logger.Logger) with charmbracelet as the default backend for consistent output.Config: The loaded configuration container.FS: An abstraction of the file system (spf13/afero), allowing for easy mocking.Assets: A manager for embedded filesystem resources.Version: Current build information (Version, Commit, Date).ErrorHandler: A centralized handler for fatal and non-fatal errors.
Why use Props?¶
Instead of using global variables or passing dozens of arguments to every function, you pass the Props object. This provides several key benefits:
- Testability: You can easily swap out the
FSfor an in-memory filesystem or provide a mockLoggerduring tests. - Consistency: Global flags like
--debugautomatically update theLoggerlevel insideProps, ensuring all components behave consistently. - Extensibility: Adding new global services to the framework only requires adding them to the
Propsstruct.
Usage in Commands¶
Every command constructor in GTB accepts *props.Props:
func NewCmdExample(p *props.Props) *setup.Command {
return setup.Wrap("example", &cobra.Command{
Use: "example",
RunE: func(cmd *cobra.Command, args []string) error {
p.Logger.Info("Hello from Props!")
// Use p.FS to read a file
// Use p.Config to get a value
return nil
},
})
}