Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

flag: no way to access a FlagSet's output #17628

Closed
dominikh opened this issue Oct 27, 2016 · 5 comments
Closed

flag: no way to access a FlagSet's output #17628

dominikh opened this issue Oct 27, 2016 · 5 comments
Labels
FrozenDueToAge NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made.
Milestone

Comments

@dominikh
Copy link
Member

The FlagSet type has a SetOutput method for setting the destination for
usage messages. This destination is used by the default Usage
function, but it's impossible to use it in custom implementations,
because no accessor for the output exists.

I propose adding a field or method to access the set output.

Relatedly, FlagSet.Usage currently writes the banner to os.Stderr,
ignoring the set output, while PrintDefaults writes to the set output.

What did you do?

https://play.golang.org/p/tDimNWwNwD

What did you expect to see?

This or similar code to compile and write to the set output

What did you see instead?

No way to do so.

@odeke-em
Copy link
Member

@dominikh I too found a need for this when working on https://go-review.googlesource.com/#/c/28488 but then thought I was overthinking it for that CL.

There is an unexposed FlagSet.output method

func (f *FlagSet) out() io.Writer {

@rakyll
Copy link
Contributor

rakyll commented Oct 31, 2016

You can rewrite FlagSet.Usage easily. PrintDefaults output can be forwarded to any io.Writer by using *FlagSet.SetOutput.

I don't think we should add more APIs to this package. Usage exists for convince and is rewritable for cases where default behavior is not good enough.

See the program below:

func main() {
    fs := flag.NewFlagSet("name", flag.ExitOnError)
    fs.Int("count", 0, "")
    fs.Usage = usage(fs, os.Stdout)
}

func usage(fs *flag.FlagSet, out io.Writer) func() {
    fs.SetOutput(out)
    return func() {
        fmt.Fprintf(out, "Usage of %s:\n", os.Args[0])
        fs.PrintDefaults()
    }
}

@quentinmit quentinmit added the NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made. label Nov 1, 2016
@quentinmit quentinmit added this to the Go1.9Maybe milestone Nov 1, 2016
@dominikh
Copy link
Member Author

@rakyll there are two issues here, both involving broken contracts.

  1. The API allows the user to specify where output should go. The user's wish is, however, ignored any time they use a custom Usage function that needs to output text. This turns SetOutput into a special case that is only relevant for the default function. Having to write another wrapper (your usage) is not only a crutch, it also makes for very odd code, where printing a usage message mutates the flag set, overwriting previous calls to SetOutput, creating two disjoint truths of where output should go.

  2. The fact that even the default Usage function ignores the user's wish half of the time is both a bug and further indication of how weirdly special SetOutput currently is. It cannot even be used with the default Usage function if one expects correct results.

Quoting the documentation of SetOutput:

SetOutput sets the destination for usage and error messages

None of that is really true.

@bruceauyeung
Copy link

i think after user called flag.CommandLine.SetOutput(os.Stdout), Usage of xxx should also be printed to stdout without customizing usage function

@gopherbot
Copy link

Change https://golang.org/cl/70391 mentions this issue: flag: add (*FlagSet).Name, (*FlagSet).ErrorHandling, export (*FlagSet).Output

@golang golang locked and limited conversation to collaborators Oct 31, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made.
Projects
None yet
Development

No branches or pull requests

7 participants