github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/go/util/options/options.go (about)

     1  // Copyright (c) 2015, Kevin Walsh.  All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package options works in concert with flag, adding prettier printing of
    16  // options.
    17  package options
    18  
    19  import (
    20  	"flag"
    21  	"fmt"
    22  	"io"
    23  	"strings"
    24  	"text/tabwriter"
    25  	"time"
    26  
    27  	_ "github.com/golang/glog"
    28  )
    29  
    30  // Option is like flag.Flag, but supports prettier printing.
    31  type Option struct {
    32  	// Name for this flag, e.g. "pass"
    33  	Name string
    34  
    35  	// Default value, e.g. "BogusPassword"
    36  	Default interface{}
    37  
    38  	// Placeholder description of the argument e.g. "<password>"
    39  	Prototype string
    40  
    41  	// Help message, e.g. "Password for decryption"
    42  	Help string
    43  
    44  	// Relevance is a comma-separated list of words, used to group the flags
    45  	// into categories.
    46  	Relevance string
    47  }
    48  
    49  // Category describes a group of related command-line flags.
    50  type Category struct {
    51  
    52  	// Name for this group of flags.
    53  	Name string
    54  
    55  	// Description for this group of flags.
    56  	Description string
    57  }
    58  
    59  var (
    60  	// Options is like flag.CommandLine, the current set of options. It is not kept
    61  	// in lexicographical order. Initially, it will contain (at least) all the flags
    62  	// from golang/glog.
    63  	Options = []Option{}
    64  
    65  	// String maps from name to value for string options added with Add.
    66  	String = make(map[string]*string)
    67  
    68  	// Bool maps from name to value for boolean options added with Add.
    69  	Bool = make(map[string]*bool)
    70  
    71  	// Int maps from name to value for int options added with Add.
    72  	Int = make(map[string]*int)
    73  
    74  	// Duration maps from name to value for time.Duration options added with
    75  	// Add.
    76  	Duration = make(map[string]*time.Duration)
    77  )
    78  
    79  func init() {
    80  	// Add to options all existing flags, which presumably come from golang/glog
    81  	// since we import that package.
    82  	flag.VisitAll(func(f *flag.Flag) {
    83  		defval := f.Value.(flag.Getter).Get()
    84  		option := Option{f.Name, defval, "", f.Usage, "logging"}
    85  		switch defval.(type) {
    86  		case int:
    87  			option.Prototype = "<n>"
    88  		case bool:
    89  			option.Prototype = ""
    90  		default:
    91  			option.Prototype = "<arg>"
    92  		}
    93  		Options = append(Options, option)
    94  	})
    95  }
    96  
    97  // Add adds one or more options to Options, to the flag package's list, and to
    98  // the approprate map (either String, Bool, Int, or Duration).
    99  func Add(option ...Option) {
   100  	Options = append(Options, option...)
   101  	for _, o := range option {
   102  		switch defval := o.Default.(type) {
   103  		case string:
   104  			String[o.Name] = flag.String(o.Name, defval, o.Help)
   105  		case bool:
   106  			Bool[o.Name] = flag.Bool(o.Name, defval, o.Help)
   107  		case int:
   108  			Int[o.Name] = flag.Int(o.Name, defval, o.Help)
   109  		case time.Duration:
   110  			Duration[o.Name] = flag.Duration(o.Name, defval, o.Help)
   111  		default:
   112  			panic(fmt.Sprintf("Option type not yet supported: %T", o.Default))
   113  		}
   114  	}
   115  }
   116  
   117  // ShowRelevant pretty-prints all options relevant to one or more categories.
   118  func ShowRelevant(out io.Writer, category ...Category) {
   119  	w, ok := out.(*tabwriter.Writer)
   120  	if !ok {
   121  		w = new(tabwriter.Writer)
   122  		w.Init(out, 4, 0, 2, ' ', 0)
   123  	}
   124  	for i, c := range category {
   125  		if i != 0 {
   126  			fmt.Fprintf(w, "\t\n")
   127  		}
   128  		fmt.Fprintf(w, "%s:\n", c.Description)
   129  		Show(w, c.Name)
   130  	}
   131  	if !ok {
   132  		w.Flush()
   133  	}
   134  }
   135  
   136  // Show pretty-prints all options. If a category is given, only those are shown.
   137  func Show(out io.Writer, category string) {
   138  	w, ok := out.(*tabwriter.Writer)
   139  	if !ok {
   140  		w = new(tabwriter.Writer)
   141  		w.Init(out, 4, 0, 2, ' ', 0)
   142  	}
   143  	for _, opt := range Options {
   144  		for _, r := range strings.Split(opt.Relevance, ",") {
   145  			if category == "" || category == r {
   146  				// -name <prototype>     help
   147  				//                         (default is <default>)
   148  				fmt.Fprintf(w, "  -%s %s\t %s\n", opt.Name, opt.Prototype, opt.Help)
   149  				if opt.Default != "" && opt.Default != false && opt.Default != nil {
   150  					fmt.Fprintf(w, "  \t   (default is %v)\n", opt.Default)
   151  				}
   152  			}
   153  		}
   154  	}
   155  	if !ok {
   156  		w.Flush()
   157  	}
   158  }
   159  
   160  // Show pretty-prints all options.
   161  func ShowAll(out io.Writer) {
   162  	Show(out, "")
   163  }