github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/cli/usage.go (about)

     1  package cli
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"text/tabwriter"
     7  
     8  	"github.com/fatih/color"
     9  	"github.com/spf13/cobra"
    10  	"github.com/spf13/pflag"
    11  )
    12  
    13  var (
    14  	headerClr *color.Color
    15  	itemClr   *color.Color
    16  	descClr   *color.Color
    17  	defClr    *color.Color
    18  )
    19  
    20  func init() {
    21  	headerClr = color.New(color.FgGreen)
    22  	itemClr = color.New(color.Bold)
    23  	// itemClr = color.New()
    24  	descClr = color.New()
    25  	defClr = color.New(color.FgYellow)
    26  }
    27  
    28  // TODO: Do we want to keep this or use cobra default one? Maybe banner + cobra default? Or something else?
    29  // This is mostly copied from ffcli package
    30  func DefaultUsageFunc(sf *pflag.FlagSet, c *cobra.Command) string {
    31  	var b strings.Builder
    32  
    33  	fmt.Fprintf(&b, "continuous profiling platform\n\n")
    34  	headerClr.Fprintf(&b, "USAGE\n")
    35  	if c.Use != "" {
    36  		fmt.Fprintf(&b, "  %s\n", c.Use)
    37  	} else {
    38  		fmt.Fprintf(&b, "  %s\n", c.Name())
    39  	}
    40  	fmt.Fprintf(&b, "\n")
    41  
    42  	if c.Long != "" {
    43  		fmt.Fprintf(&b, "%s\n\n", c.Long)
    44  	}
    45  
    46  	if hasSubCommands(c) {
    47  		headerClr.Fprintf(&b, "SUBCOMMANDS\n")
    48  		tw := tabwriter.NewWriter(&b, 0, 2, 2, ' ', 0)
    49  		for _, subcommand := range c.Commands() {
    50  			if !subcommand.Hidden {
    51  				fmt.Fprintf(tw, "  %s\t%s\n", itemClr.Sprintf(subcommand.Name()), subcommand.Short)
    52  			}
    53  		}
    54  		tw.Flush()
    55  		fmt.Fprintf(&b, "\n")
    56  	}
    57  
    58  	if countFlags(c.Flags()) > 0 {
    59  		// headerClr.Fprintf(&b, "FLAGS\n")
    60  		tw := tabwriter.NewWriter(&b, 0, 2, 2, ' ', 0)
    61  		fmt.Fprintf(tw, "%s\t  %s@new-line@\n", headerClr.Sprintf("FLAGS"), defClr.Sprint("DEFAULT VALUES"))
    62  
    63  		// TODO: it would be nice to sort by how often people would use these.
    64  		//   But for that we'd have to have a conversion from flag-set back to struct
    65  		sf.VisitAll(func(f *pflag.Flag) {
    66  			if f.Hidden {
    67  				return
    68  			}
    69  			def := f.DefValue
    70  			// if def == "" {
    71  			// 	def = "..."
    72  			// }
    73  			def = defClr.Sprint(def)
    74  			// def = fmt.Sprintf("(%s)", def)
    75  			fmt.Fprintf(tw, "  %s\t%s", itemClr.Sprintf("--"+f.Name), def)
    76  			if f.Usage != "" {
    77  				fmt.Fprintf(tw, "@new-line@    ")
    78  				descClr.Fprint(tw, f.Usage)
    79  			}
    80  			descClr.Fprint(tw, "@new-line@")
    81  			fmt.Fprint(tw, "\n")
    82  		})
    83  		tw.Flush()
    84  		// fmt.Fprintf(&b, "\n")
    85  	}
    86  
    87  	if hasSubCommands(c) {
    88  		b.WriteString("Run 'pyroscope SUBCOMMAND --help' for more information on a subcommand.\n")
    89  	}
    90  
    91  	return strings.ReplaceAll(b.String(), "@new-line@", "\n")
    92  }
    93  
    94  // hasSubCommands works as cobra HasSubCommands but reports false
    95  // when the only subcommand is help.
    96  func hasSubCommands(cmd *cobra.Command) bool {
    97  	return cmd.HasSubCommands() && !(len(cmd.Commands()) == 1 && cmd.Commands()[0].Name() == "help")
    98  }
    99  
   100  func countFlags(fs *pflag.FlagSet) (n int) {
   101  	fs.VisitAll(func(*pflag.Flag) { n++ })
   102  	return n
   103  }