Cobra, in its default configuration, will execute a template to generate
help, usage and version outputs. Text/template execution calls MethodByName
and MethodByName disables dead code elimination in the Go linker, therefore
all programs that make use of cobra will be linked with dead code
elimination disabled, even if they end up replacing the default usage, help
and version formatters with a custom function and no actual text/template
evaluations are ever made at runtime.
Dead code elimination in the linker helps reduce disk space and memory
utilization of programs. For example, for the simple example program used by
TestDeadcodeElimination 40% of the final executable size is dead code. For a
more realistic example, 12% of the size of Delve's executable is deadcode.
This PR changes Cobra so that, in its default configuration, it does not
automatically inhibit deadcode elimination by:
1. changing Cobra's default behavior to emit output for usage and help using
simple Go functions instead of template execution
2. quarantining all calls to template execution into SetUsageTemplate,
SetHelpTemplate and SetVersionTemplate so that the linker can statically
determine if they are reachable
* Avoid redundant string splits
There likely isn't actually more than once to split in the source
strings in these cases, but avoid doing so anyway as we're only
interested in the first.
* Avoid redundant completion output target evaluations
The target is not to be changed while outputting completions, so resolve
it only once.
* Avoid redundant active help enablement evaluations
The enablement state is not to be changed during completion output, so
evaluate it only once.
* Preallocate some slices and maps with known size
* Avoid some unnecessary looping
* Use strings.Builder to construct suggestions
Currently, only one of the persistent pre-runs and post-runs is executed.
It is always the first one found in the parents chain, starting at this command.
Expected behavior is to execute all parents' persistent pre-runs and post-runs.
Dependent projects implemented various workarounds for this:
- manually building persistent hook chains (in every hook).
- applying some kind of monkey-patching on top of Cobra.
This change eliminates the necessity for such workarounds
by allowing to set a global variable EnableTraverseRunHooks.
Tickets:
- https://github.com/spf13/cobra/issues/216
- https://github.com/spf13/cobra/issues/252
Signed-off-by: Volodymyr Khoroz <volodymyr.khoroz@foundries.io>
The use in generated bash completion files is getting flagged by
Lintian (the Debian package linting tool).
Signed-off-by: Taavi Väänänen <hi@taavi.wtf>
This method is the OnInitialize counterpart. Like OnInitialize which allows
loading the configuration before each command is executed, OnFinalize allows
saving the configuration after each command has been executed.
Add a global `EnableCaseInsensitive` variable to allow
case-insensitive command names.
The variable supports commands names and aliases globally.
Resolves#1382
new variable MousetrapDisplayDuration allows to modify the default
display duration of 5s, or to completely disable the timeout and wait
for the user to press the return key.
There were template functions which we defined and others started using.
Although we no longer want those functions, since others use them,
deleting them breaks our API. Putting those (unused) functions back.
* Delete Eq, Gt, appendIfNotPresent and trim functions
* Add "[flags]" in UseLine
* Simplify other functions
* Simplify templates
Minor performance improvement.
Benchmark for command with 4 flags and one child command:
benchmark old ns/op new ns/op delta
BenchmarkCmdUsageFunc-4 335860 319290 -4.93%
benchmark old allocs new allocs delta
BenchmarkCmdUsageFunc-4 562 543 -3.38%
benchmark old bytes new bytes delta
BenchmarkCmdUsageFunc-4 21623 21037 -2.71%
* Moving final return outside of if-else
* Removing type declarations that Go can infer from values
* Cleaning up some existing comments
* Changing snake_case variables to camelCase
The flags usage template from pflags has a trailing \n. We need to
include a newline in case there are no flags in our template. This will
trim the newline from the end of the flags from pflag and we can do it
right outselves.
This patch enables developers to add one to many template functions that
can be used by custom Usage and Help templates. Here is an example that
is included in the file cobra_test.go as the test function named
TestAddTemplateFunctions:
AddTemplateFunc("t", func() bool { return true })
AddTemplateFuncs(template.FuncMap{
"f": func() bool { return false },
"h": func() string { return "Hello," },
"w": func() string { return "world." }})
const usage = "Hello, world."
c := &Command{}
c.SetUsageTemplate(`{{if t}}{{h}}{{end}}{{if f}}{{h}}{{end}} {{w}}`)
if us := c.UsageString(); us != usage {
t.Errorf("c.UsageString() != \"%s\", is \"%s\"", usage, us)
}
In the above example four functions are added to the template function
map used when the Usage and Help text is generated from the templates
that enable custom logic as well as data injection during template
execution.