0

How do you get spaces in flag values when using directives?

Context

The flag package receives and/or handles flags with spaces differently depending on how Go is called. Quoting the flag value works from the command-line but not with a directive, such as go generate, for example.

In other words, called from the command line, Flag1 will receive the correct value (i.e., 4 words, 3 spaces).

Works

% go run -tags generate main.go -Flag1="flag value with spaces"

Doesn't Work

However, calling the exact same command in a directive file, e.g., with go generate ./..., Flag1 will not receive the correct value. Take a directive file (e.g., generate.go) with this line in it:

//go:generate go run -tags generate main.go -Flag1="flag value with spaces" -Flag2=next

Flag1 is not set correctly and Flag2 is not set at all.

DarkerIvy
  • 1,477
  • 14
  • 26

2 Answers2

1

The arguments to go run are parsed by your shell. The go:generate directive does its own parsing and that parsing is different from shells.

The relevant go:generate documentation is:

The arguments to the directive are space-separated tokens or double-quoted strings passed to the generator as individual arguments when it is run.

Quoted strings use Go syntax and are evaluated before execution; a quoted string appears as a single argument to the generator.

Each argument is separated by spaces. An argument is either a "token" or a double-quoted string. The documentation does not describe a token, but we can assume it means a sequence of non-space characters.

Quoted strings are evaluated. That means that quotes are removed, escape sequences are unescaped, etc. The implementation evaluates the string using strconv.Unquote.

Based on the above, use:

//go:generate go run -tags generate main.go "-Flag1=flag value with spaces"

The important change here is the " is moved forward to a position where it's proceeded by a space. Quotes inside of a token are ignored.

0

Extrapolating from an old, related, but not the same question, enclose the entire flag key, dash, and value in quotes.

//go:generate go run -tags generate main.go "-Flag1=flag value with spaces"

This syntax has the advantage of working on the command line or in directive files.

None of the current documentation (that I could find) provides a clear answer:

  • The flag documentation does not mention flag values with spaces.
  • The directive documentation provides this cryptic hint that leads you to the correct solution (though a bit more clarity would be helpful).

Quoted strings use Go syntax and are evaluated before execution; a quoted string appears as a single argument to the generator.

DarkerIvy
  • 1,477
  • 14
  • 26
  • 2
    When entered through the shell command line, the arguments to a process will be passed to the process *after* the shell processes them. That's why in the first case the quotes are removed, but with go:generate, the subprocess receives the argument quoted. – Burak Serdar Sep 13 '21 at 20:09
  • Also note that while the `go` tools make some exceptions for misuse, you generally should not be adding flags after the positional arguments since it's not universally accepted (with the `flags` package here being the most obvious example) – JimB Sep 13 '21 at 20:25