github.com/hernad/nomad@v1.6.112/main.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package main
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"io"
    10  	"os"
    11  	"sort"
    12  	"strings"
    13  	"text/tabwriter"
    14  
    15  	// These packages have init() funcs which check os.Args and drop directly
    16  	// into their command logic. This is because they are run as separate
    17  	// processes along side of a task. By early importing them we can avoid
    18  	// additional code being imported and thus reserving memory.
    19  	_ "github.com/hernad/nomad/client/allocrunner/taskrunner/getter"
    20  	_ "github.com/hernad/nomad/client/logmon"
    21  	_ "github.com/hernad/nomad/drivers/docker/docklog"
    22  	_ "github.com/hernad/nomad/drivers/shared/executor"
    23  
    24  	// Don't move any other code imports above the import block above!
    25  	"github.com/hernad/nomad/command"
    26  	"github.com/hernad/nomad/version"
    27  	"github.com/mitchellh/cli"
    28  )
    29  
    30  var (
    31  	// Hidden hides the commands from both help and autocomplete. Commands that
    32  	// users should not be running should be placed here, versus hiding
    33  	// subcommands from the main help, which should be filtered out of the
    34  	// commands above.
    35  	hidden = []string{
    36  		"alloc-status",
    37  		"check",
    38  		"client-config",
    39  		"debug",
    40  		"eval-status",
    41  		"executor",
    42  		"logmon",
    43  		"node-drain",
    44  		"node-status",
    45  		"server-force-leave",
    46  		"server-join",
    47  		"server-members",
    48  		"syslog",
    49  		"docker_logger",
    50  		"operator raft _info",
    51  		"operator raft _logs",
    52  		"operator raft _state",
    53  		"operator snapshot _state",
    54  	}
    55  
    56  	// aliases is the list of aliases we want users to be aware of. We hide
    57  	// these form the help output but autocomplete them.
    58  	aliases = []string{
    59  		"fs",
    60  		"init",
    61  		"inspect",
    62  		"logs",
    63  		"plan",
    64  		"validate",
    65  	}
    66  
    67  	// Common commands are grouped separately to call them out to operators.
    68  	commonCommands = []string{
    69  		"run",
    70  		"stop",
    71  		"status",
    72  		"alloc",
    73  		"job",
    74  		"node",
    75  		"agent",
    76  	}
    77  )
    78  
    79  func main() {
    80  	os.Exit(Run(os.Args[1:]))
    81  }
    82  
    83  func Run(args []string) int {
    84  	// Create the meta object
    85  	metaPtr := new(command.Meta)
    86  	metaPtr.SetupUi(args)
    87  
    88  	// The Nomad agent never outputs color
    89  	agentUi := &cli.BasicUi{
    90  		Reader:      os.Stdin,
    91  		Writer:      os.Stdout,
    92  		ErrorWriter: os.Stderr,
    93  	}
    94  
    95  	commands := command.Commands(metaPtr, agentUi)
    96  	cli := &cli.CLI{
    97  		Name:                       "nomad",
    98  		Version:                    version.GetVersion().FullVersionNumber(true),
    99  		Args:                       args,
   100  		Commands:                   commands,
   101  		HiddenCommands:             hidden,
   102  		Autocomplete:               true,
   103  		AutocompleteNoDefaultFlags: true,
   104  		HelpFunc: groupedHelpFunc(
   105  			cli.BasicHelpFunc("nomad"),
   106  		),
   107  		HelpWriter: os.Stdout,
   108  	}
   109  
   110  	exitCode, err := cli.Run()
   111  	if err != nil {
   112  		fmt.Fprintf(os.Stderr, "Error executing CLI: %s\n", err.Error())
   113  		return 1
   114  	}
   115  
   116  	return exitCode
   117  }
   118  
   119  func groupedHelpFunc(f cli.HelpFunc) cli.HelpFunc {
   120  	return func(commands map[string]cli.CommandFactory) string {
   121  		var b bytes.Buffer
   122  		tw := tabwriter.NewWriter(&b, 0, 2, 6, ' ', 0)
   123  
   124  		fmt.Fprintf(tw, "Usage: nomad [-version] [-help] [-autocomplete-(un)install] <command> [args]\n\n")
   125  		fmt.Fprintf(tw, "Common commands:\n")
   126  		for _, v := range commonCommands {
   127  			printCommand(tw, v, commands[v])
   128  		}
   129  
   130  		// Filter out common commands and aliased commands from the other
   131  		// commands output
   132  		otherCommands := make([]string, 0, len(commands))
   133  		for k := range commands {
   134  			found := false
   135  			for _, v := range commonCommands {
   136  				if k == v {
   137  					found = true
   138  					break
   139  				}
   140  			}
   141  
   142  			for _, v := range aliases {
   143  				if k == v {
   144  					found = true
   145  					break
   146  				}
   147  			}
   148  
   149  			if !found {
   150  				otherCommands = append(otherCommands, k)
   151  			}
   152  		}
   153  		sort.Strings(otherCommands)
   154  
   155  		fmt.Fprintf(tw, "\n")
   156  		fmt.Fprintf(tw, "Other commands:\n")
   157  		for _, v := range otherCommands {
   158  			printCommand(tw, v, commands[v])
   159  		}
   160  
   161  		tw.Flush()
   162  
   163  		return strings.TrimSpace(b.String())
   164  	}
   165  }
   166  
   167  func printCommand(w io.Writer, name string, cmdFn cli.CommandFactory) {
   168  	cmd, err := cmdFn()
   169  	if err != nil {
   170  		panic(fmt.Sprintf("failed to load %q command: %s", name, err))
   171  	}
   172  	fmt.Fprintf(w, "    %s\t%s\n", name, cmd.Synopsis())
   173  }