21891: Comment to explain mysterious numbers 13 and 17 in test case.
[arvados.git] / lib / cmd / parseflags.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: Apache-2.0
4
5 package cmd
6
7 import (
8         "flag"
9         "fmt"
10         "io"
11         "reflect"
12 )
13
14 // Hack to enable checking whether a given FlagSet's Usage method is
15 // the (private) default one.
16 var defaultFlagSet = flag.NewFlagSet("none", flag.ContinueOnError)
17
18 // ParseFlags calls f.Parse(args) and prints appropriate error/help
19 // messages to stderr.
20 //
21 // The positional argument is "" if no positional arguments are
22 // accepted, otherwise a string to print with the usage message,
23 // "Usage: {prog} [options] {positional}".
24 //
25 // The first return value, ok, is true if the program should continue
26 // running normally, or false if it should exit now.
27 //
28 // If ok is false, the second return value is an appropriate exit
29 // code: 0 if "-help" was given, 2 if there was a usage error.
30 func ParseFlags(f FlagSet, prog string, args []string, positional string, stderr io.Writer) (ok bool, exitCode int) {
31         f.Init(prog, flag.ContinueOnError)
32         f.SetOutput(io.Discard)
33         err := f.Parse(args)
34         switch err {
35         case nil:
36                 if f.NArg() > 0 && positional == "" {
37                         fmt.Fprintf(stderr, "unrecognized command line arguments: %v (try -help)\n", f.Args())
38                         return false, EXIT_INVALIDARGUMENT
39                 }
40                 return true, 0
41         case flag.ErrHelp:
42                 // Use our own default usage func, not the one
43                 // provided by the flag pkg, if the caller hasn't set
44                 // one. (We use reflect to determine whether f.Usage
45                 // is the private defaultUsage func that
46                 // flag.NewFlagSet uses.)
47                 if f, ok := f.(*flag.FlagSet); ok && f.Usage != nil && reflect.ValueOf(f.Usage).String() != reflect.ValueOf(defaultFlagSet.Usage).String() {
48                         f.SetOutput(stderr)
49                         f.Usage()
50                 } else {
51                         fmt.Fprintf(stderr, "Usage: %s [options] %s\n", prog, positional)
52                         f.SetOutput(stderr)
53                         f.PrintDefaults()
54                 }
55                 return false, 0
56         default:
57                 fmt.Fprintf(stderr, "error parsing command line arguments: %s (try -help)\n", err)
58                 return false, EXIT_INVALIDARGUMENT
59         }
60 }