gitlab.com/aquachain/aquachain@v1.17.16-rc3.0.20221018032414-e3ddf1e1c055/cmd/attacher/usage.go (about)

     1  // Copyright 2019 The aquachain Authors
     2  // This file is part of aquachain.
     3  //
     4  // aquachain is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // aquachain is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with aquachain. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Contains the aquachain command usage template and generator.
    18  
    19  package main
    20  
    21  import (
    22  	"io"
    23  	"sort"
    24  
    25  	"strings"
    26  
    27  	"github.com/urfave/cli"
    28  	"gitlab.com/aquachain/aquachain/cmd/utils"
    29  	"gitlab.com/aquachain/aquachain/internal/debug"
    30  )
    31  
    32  const logo = `                              _           _
    33    __ _  __ _ _   _  __ _  ___| |__   __ _(_)_ __
    34   / _ '|/ _' | | | |/ _' |/ __| '_ \ / _' | | '_ \
    35  | (_| | (_| | |_| | (_| | (__| | | | (_| | | | | |
    36   \__,_|\__, |\__,_|\__,_|\___|_| |_|\__,_|_|_| |_|
    37            |_|` + "Update Often! https://gitlab.com/aquachain/aquachain\n\n"
    38  
    39  // AppHelpTemplate is the test template for the default, global app help topic.
    40  var AppHelpTemplate = logo + `NAME:
    41     {{.App.Name}} - {{.App.Usage}}
    42  
    43      Copyright 2018-2019 The aquachain authors
    44      Copyright 2013-2018 The go-ethereum authors
    45  
    46  USAGE:
    47     {{.App.HelpName}} [options]{{if .App.Commands}} command [command options]{{end}} {{if .App.ArgsUsage}}{{.App.ArgsUsage}}{{else}}[arguments...]{{end}}
    48     {{if .App.Version}}
    49  VERSION:
    50     {{.App.Version}}
    51     {{end}}{{if len .App.Authors}}
    52  AUTHOR(S):
    53     {{range .App.Authors}}{{ . }}{{end}}
    54     {{end}}{{if .App.Commands}}
    55  COMMANDS:
    56     {{range .App.Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
    57     {{end}}{{end}}{{if .FlagGroups}}
    58  {{range .FlagGroups}}{{.Name}} OPTIONS:
    59    {{range .Flags}}{{.}}
    60    {{end}}
    61  {{end}}{{end}}{{if .App.Copyright }}
    62  COPYRIGHT:
    63     {{.App.Copyright}}
    64     {{end}}
    65  `
    66  
    67  // flagGroup is a collection of flags belonging to a single topic.
    68  type flagGroup struct {
    69  	Name  string
    70  	Flags []cli.Flag
    71  }
    72  
    73  // AppHelpFlagGroups is the application flags, grouped by functionality.
    74  var AppHelpFlagGroups = []flagGroup{
    75  	{
    76  		Name: "Aquachain",
    77  		Flags: []cli.Flag{
    78  			utils.NetworkIdFlag,
    79  			utils.IdentityFlag,
    80  		},
    81  	},
    82  	{
    83  		Name: "API AND CONSOLE",
    84  		Flags: []cli.Flag{
    85  			utils.IPCPathFlag,
    86  			utils.JSpathFlag,
    87  			utils.ExecFlag,
    88  			utils.PreloadJSFlag,
    89  		},
    90  	},
    91  	{
    92  		Name: "LOGGING AND DEBUGGING",
    93  		Flags: append([]cli.Flag{
    94  			utils.MetricsEnabledFlag,
    95  			utils.NoCompactionFlag,
    96  		}, debug.Flags...),
    97  	},
    98  	{
    99  		Name:  "MISC",
   100  		Flags: []cli.Flag{utils.FastSyncFlag},
   101  	},
   102  }
   103  
   104  // byCategory sorts an array of flagGroup by Name in the order
   105  // defined in AppHelpFlagGroups.
   106  type byCategory []flagGroup
   107  
   108  func (a byCategory) Len() int      { return len(a) }
   109  func (a byCategory) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
   110  func (a byCategory) Less(i, j int) bool {
   111  	iCat, jCat := a[i].Name, a[j].Name
   112  	iIdx, jIdx := len(AppHelpFlagGroups), len(AppHelpFlagGroups) // ensure non categorized flags come last
   113  
   114  	for i, group := range AppHelpFlagGroups {
   115  		if iCat == group.Name {
   116  			iIdx = i
   117  		}
   118  		if jCat == group.Name {
   119  			jIdx = i
   120  		}
   121  	}
   122  
   123  	return iIdx < jIdx
   124  }
   125  
   126  func flagCategory(flag cli.Flag) string {
   127  	for _, category := range AppHelpFlagGroups {
   128  		for _, flg := range category.Flags {
   129  			if flg.GetName() == flag.GetName() {
   130  				return category.Name
   131  			}
   132  		}
   133  	}
   134  	return "MISC"
   135  }
   136  
   137  func init() {
   138  	// Override the default app help template
   139  	cli.AppHelpTemplate = AppHelpTemplate
   140  
   141  	// Define a one shot struct to pass to the usage template
   142  	type helpData struct {
   143  		App        interface{}
   144  		FlagGroups []flagGroup
   145  	}
   146  
   147  	// Override the default app help printer, but only for the global app help
   148  	originalHelpPrinter := cli.HelpPrinter
   149  	cli.HelpPrinter = func(w io.Writer, tmpl string, data interface{}) {
   150  		if tmpl == AppHelpTemplate {
   151  			// Iterate over all the flags and add any uncategorized ones
   152  			categorized := make(map[string]struct{})
   153  			for _, group := range AppHelpFlagGroups {
   154  				for _, flag := range group.Flags {
   155  					categorized[flag.String()] = struct{}{}
   156  				}
   157  			}
   158  			uncategorized := []cli.Flag{}
   159  			for _, flag := range data.(*cli.App).Flags {
   160  				if _, ok := categorized[flag.String()]; !ok {
   161  					if strings.HasPrefix(flag.GetName(), "dashboard") {
   162  						continue
   163  					}
   164  					uncategorized = append(uncategorized, flag)
   165  				}
   166  			}
   167  			if len(uncategorized) > 0 {
   168  				// Append all ungategorized options to the misc group
   169  				miscs := len(AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags)
   170  				AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags = append(AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags, uncategorized...)
   171  
   172  				// Make sure they are removed afterwards
   173  				defer func() {
   174  					AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags = AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags[:miscs]
   175  				}()
   176  			}
   177  			// Render out custom usage screen
   178  			originalHelpPrinter(w, tmpl, helpData{data, AppHelpFlagGroups})
   179  		} else if tmpl == utils.CommandHelpTemplate {
   180  			// Iterate over all command specific flags and categorize them
   181  			categorized := make(map[string][]cli.Flag)
   182  			for _, flag := range data.(cli.Command).Flags {
   183  				if _, ok := categorized[flag.String()]; !ok {
   184  					categorized[flagCategory(flag)] = append(categorized[flagCategory(flag)], flag)
   185  				}
   186  			}
   187  
   188  			// sort to get a stable ordering
   189  			sorted := make([]flagGroup, 0, len(categorized))
   190  			for cat, flgs := range categorized {
   191  				sorted = append(sorted, flagGroup{cat, flgs})
   192  			}
   193  			sort.Sort(byCategory(sorted))
   194  
   195  			// add sorted array to data and render with default printer
   196  			originalHelpPrinter(w, tmpl, map[string]interface{}{
   197  				"cmd":              data,
   198  				"categorizedFlags": sorted,
   199  			})
   200  		} else {
   201  			originalHelpPrinter(w, tmpl, data)
   202  		}
   203  	}
   204  }