github.com/coreos/rocket@v1.30.1-0.20200224141603-171c416fac02/rkt/help.go (about)

     1  // Copyright 2015 The rkt Authors
     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 main
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    20  	"os"
    21  	"strings"
    22  	"text/template"
    23  
    24  	"github.com/appc/spec/schema"
    25  	"github.com/rkt/rkt/version"
    26  	"github.com/spf13/cobra"
    27  	"github.com/spf13/pflag"
    28  )
    29  
    30  var (
    31  	commandUsageTemplate *template.Template
    32  	templFuncs           = template.FuncMap{
    33  		"descToLines": func(s string) []string {
    34  			// trim leading/trailing whitespace and split into slice of lines
    35  			return strings.Split(strings.Trim(s, "\n\t "), "\n")
    36  		},
    37  		"cmdName": func(cmd *cobra.Command, startCmd *cobra.Command) string {
    38  			parts := []string{cmd.Name()}
    39  			for cmd.HasParent() && cmd.Parent().Name() != startCmd.Name() {
    40  				cmd = cmd.Parent()
    41  				parts = append([]string{cmd.Name()}, parts...)
    42  			}
    43  			return strings.Join(parts, " ")
    44  		},
    45  	}
    46  )
    47  
    48  func init() {
    49  	commandUsage := `
    50  {{ $cmd := .Cmd }}\
    51  {{ $cmdname := cmdName .Cmd .Cmd.Root }}\
    52  NAME:
    53  {{ if not .Cmd.HasParent }}\
    54  {{printf "\t%s - %s" .Cmd.Name .Cmd.Short}}
    55  {{else}}\
    56  {{printf "\t%s - %s" $cmdname .Cmd.Short}}
    57  {{end}}\
    58  
    59  USAGE:
    60  {{printf "\t%s" .Cmd.UseLine}}
    61  {{ if not .Cmd.HasParent }}\
    62  
    63  VERSION:
    64  {{printf "\t%s" .Version}}
    65  {{end}}\
    66  {{if .Cmd.HasSubCommands}}\
    67  
    68  COMMANDS:
    69  {{range .SubCommands}}\
    70  {{ $cmdname := cmdName . $cmd }}\
    71  {{ if .Runnable }}\
    72  {{printf "\t%s\t%s" $cmdname .Short}}
    73  {{end}}\
    74  {{end}}\
    75  {{end}}\
    76  {{ if .Cmd.Long }}\
    77  
    78  DESCRIPTION:
    79  {{range $line := descToLines .Cmd.Long}}{{printf "\t%s" $line}}
    80  {{end}}\
    81  {{end}}\
    82  {{if .Cmd.HasLocalFlags}}\
    83  
    84  OPTIONS:
    85  {{.LocalFlags}}\
    86  {{end}}\
    87  {{if .Cmd.HasInheritedFlags}}\
    88  
    89  GLOBAL OPTIONS:
    90  {{.GlobalFlags}}\
    91  {{end}}
    92  `[1:]
    93  
    94  	commandUsageTemplate = template.Must(template.New("command_usage").Funcs(templFuncs).Parse(strings.Replace(commandUsage, "\\\n", "", -1)))
    95  }
    96  
    97  func rktFlagUsages(flagSet *pflag.FlagSet) string {
    98  	x := new(bytes.Buffer)
    99  
   100  	flagSet.VisitAll(func(flag *pflag.Flag) {
   101  		if len(flag.Deprecated) > 0 || flag.Hidden {
   102  			return
   103  		}
   104  		format := ""
   105  		if len(flag.Shorthand) > 0 && len(flag.ShorthandDeprecated) == 0 {
   106  			format = "  -%s, --%s"
   107  		} else {
   108  			format = "   %s   --%s"
   109  		}
   110  		if len(flag.NoOptDefVal) > 0 {
   111  			format = format + "["
   112  		}
   113  		if flag.Value.Type() == "string" {
   114  			// put quotes on the value
   115  			format = format + "=%q"
   116  		} else {
   117  			format = format + "=%s"
   118  		}
   119  		if len(flag.NoOptDefVal) > 0 {
   120  			format = format + "]"
   121  		}
   122  		format = format + "\t%s\n"
   123  		shorthand := flag.Shorthand
   124  		fmt.Fprintf(x, format, shorthand, flag.Name, flag.DefValue, flag.Usage)
   125  	})
   126  
   127  	return x.String()
   128  }
   129  
   130  func getSubCommands(cmd *cobra.Command) []*cobra.Command {
   131  	var subCommands []*cobra.Command
   132  	for _, subCmd := range cmd.Commands() {
   133  		if !subCmd.Hidden {
   134  			subCommands = append(subCommands, subCmd)
   135  			subCommands = append(subCommands, getSubCommands(subCmd)...)
   136  		}
   137  	}
   138  	return subCommands
   139  }
   140  
   141  func usageFunc(cmd *cobra.Command) error {
   142  	subCommands := getSubCommands(cmd)
   143  	tabOut := getTabOutWithWriter(os.Stdout)
   144  	commandUsageTemplate.Execute(tabOut, struct {
   145  		Cmd         *cobra.Command
   146  		LocalFlags  string
   147  		GlobalFlags string
   148  		SubCommands []*cobra.Command
   149  		Version     string
   150  	}{
   151  		cmd,
   152  		rktFlagUsages(cmd.LocalFlags()),
   153  		rktFlagUsages(cmd.InheritedFlags()),
   154  		subCommands,
   155  		version.Version,
   156  	})
   157  	tabOut.Flush()
   158  	return nil
   159  }
   160  
   161  func printErrors(errors []error, operation string) {
   162  	sep := "----------------------------------------"
   163  	stderr.Printf("%d error(s) encountered when %s:", len(errors), operation)
   164  	stderr.Print(sep)
   165  	for _, err := range errors {
   166  		stderr.Error(err)
   167  		stderr.Print(sep)
   168  	}
   169  	stderr.Print("misc:")
   170  	stderr.Printf("  rkt's appc version: %s", schema.AppContainerVersion)
   171  	// make a visible break between errors and the listing
   172  	stderr.Print("")
   173  }