Skip to content

Add urfave_cli_no_template build tag (generated code) - #2442

Closed
kolyshkin wants to merge 4 commits into
urfave:mainfrom
kolyshkin:no-template-codegen
Closed

kolyshkin wants to merge 4 commits into
urfave:mainfrom
kolyshkin:no-template-codegen

Conversation

@kolyshkin

@kolyshkin kolyshkin commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

This is an alternative to #2441, which see for the motivation. The difference is how the template-less help rendering code is written:

  • Add urfave_cli_no_template build tag #2441: hand-written Go equivalent of the default templates.
  • This PR: Go code generated from the default templates by internal/genhelp (run via go generate). It parses the templates using text/template/parse and compiles them into Go code, resolving fields and methods statically via go/types (stdlib only, no new dependencies). Anything outside of the template language subset used by the default templates (pipelines, unknown functions or fields etc.) is a generation error.

Everything else (build tag, tests, CI, docs) is the same.

Pros and cons

#2441 (hand-written) this PR (generated)
Changing a default template edit both the template and the Go code edit the template, run go generate
Forgetting the second step caught by the golden test in CI (tagged run) caught by TestGeneratedHelpUpToDate in any go test run
Code size ~290 lines of renderer 576 lines of generator + 352 generated lines
Review simple, straightforward code the generator is more complex, but it's a one-time investment
runc binary with the tag 10.53 MB 10.54 MB
Custom templates with the tag not supported not supported

In both cases, a build tag is required, since custom templates can't be rendered without text/template at runtime.

I'm fine with either approach.

With this tag, examples/example-cli is 3.3 MB instead of 5.1 MB, and runc is 10.5 MB instead of 12.4 MB (all 19 help pages of runc are byte-for-byte identical).

Addresses #2277.

Move DefaultPrintHelpCustom and the fish completion template rendering
to help_template.go, so that all uses of text/template are in one file.

No functional change; this is a preparation for the next commit.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Using text/template makes the Go linker disable dead code elimination
of exported methods for the whole program, since templates can call
arbitrary methods by name (see golang/go#72895). For large programs,
this results in a noticeably bigger binary.

Add urfave_cli_no_template build tag, which renders the default help
and fish completion without using text/template, producing the same
output. Custom templates are not supported in this mode.

The rendering code is generated from the default templates by
internal/genhelp (run via go generate), which parses the templates
using text/template/parse and compiles them into Go code, resolving
fields and methods statically with the help of go/types. Only the
subset of the template language used by the default templates is
supported; anything else is a generation error.

With this tag, examples/example-cli binary is 3.3 MB instead of 5.1 MB,
and runc binary is 10.5 MB instead of 12.4 MB.

Run tests with this tag in CI, skipping those that use custom templates,
and add tests to ensure text/template is not linked in with this tag,
and that the generated code is up to date.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Add a test which renders various help pages and fish completion for
a few commands exercising most of the template features, and compares
the result with a golden file.

Since CI runs tests both with and without urfave_cli_no_template tag,
this ensures both implementations produce the exact same output.

To regenerate the golden file, run the test with UPDATE_GOLDEN=1.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
In check-binary-size, also show how much the package contributes to the
binary size when built with urfave_cli_no_template tag. This is for
informational purposes only; the limits are checked for the default
build.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
@Juneezee

Juneezee commented Sep 25, 2026 •

Copy link
Copy Markdown
Member

Thanks! I reviewed both approaches together in #2441 (review)

@kolyshkin

Copy link
Copy Markdown
Contributor Author

Closing in favor of #2441, as discussed in #2441 (review).

@kolyshkin kolyshkin closed this Sep 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dead code elimination partially disabled

2 participants