gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/runsc/cmd/help.go (about)

     1  // Copyright 2018 The gVisor 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 cmd
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  
    21  	"github.com/google/subcommands"
    22  	"gvisor.dev/gvisor/runsc/flag"
    23  )
    24  
    25  // NewHelp returns a help command for the given commander.
    26  func NewHelp(cdr *subcommands.Commander) *Help {
    27  	return &Help{
    28  		cdr: cdr,
    29  	}
    30  }
    31  
    32  // Help implements subcommands.Command for the "help" command. The 'help'
    33  // command prints help for commands registered to a Commander but also allows for
    34  // registering additional help commands that print other documentation.
    35  type Help struct {
    36  	cdr      *subcommands.Commander
    37  	commands []subcommands.Command
    38  	help     bool
    39  }
    40  
    41  // Name implements subcommands.Command.Name.
    42  func (*Help) Name() string {
    43  	return "help"
    44  }
    45  
    46  // Synopsis implements subcommands.Command.Synopsis.
    47  func (*Help) Synopsis() string {
    48  	return "Print help documentation."
    49  }
    50  
    51  // Usage implements subcommands.Command.Usage.
    52  func (*Help) Usage() string {
    53  	return `help [<subcommand>]:
    54  	With an argument, prints detailed information on the use of
    55  	the specified topic or subcommand. With no argument, print a list of
    56  	all commands and a brief description of each.
    57  `
    58  }
    59  
    60  // SetFlags implements subcommands.Command.SetFlags.
    61  func (h *Help) SetFlags(*flag.FlagSet) {}
    62  
    63  // Execute implements subcommands.Command.Execute.
    64  func (h *Help) Execute(ctx context.Context, f *flag.FlagSet, args ...any) subcommands.ExitStatus {
    65  	switch f.NArg() {
    66  	case 0:
    67  		fmt.Fprintf(h.cdr.Output, "Usage: %s <flags> <subcommand> <subcommand args>\n\n", h.cdr.Name())
    68  		fmt.Fprintf(h.cdr.Output, `runsc is the gVisor container runtime.
    69  
    70  Functionality is provided by subcommands. For help with a specific subcommand,
    71  use "%s %s <subcommand>".
    72  
    73  `, h.cdr.Name(), h.Name())
    74  		h.cdr.VisitGroups(func(g *subcommands.CommandGroup) {
    75  			h.cdr.ExplainGroup(h.cdr.Output, g)
    76  		})
    77  
    78  		fmt.Fprintf(h.cdr.Output, "Additional help topics (Use \"%s %s <topic>\" to see help on the topic):\n", h.cdr.Name(), h.Name())
    79  		for _, cmd := range h.commands {
    80  			fmt.Fprintf(h.cdr.Output, "\t%-15s  %s\n", cmd.Name(), cmd.Synopsis())
    81  		}
    82  		fmt.Fprintf(h.cdr.Output, "\nUse \"%s flags\" for a list of top-level flags\n", h.cdr.Name())
    83  		return subcommands.ExitSuccess
    84  	default:
    85  		// Look for commands registered to the commander and print help explanation if found.
    86  		found := false
    87  		h.cdr.VisitCommands(func(g *subcommands.CommandGroup, cmd subcommands.Command) {
    88  			if f.Arg(0) == cmd.Name() {
    89  				h.cdr.ExplainCommand(h.cdr.Output, cmd)
    90  				found = true
    91  			}
    92  		})
    93  		if found {
    94  			return subcommands.ExitSuccess
    95  		}
    96  
    97  		// Next check commands registered to the help command.
    98  		for _, cmd := range h.commands {
    99  			if f.Arg(0) == cmd.Name() {
   100  				fs := flag.NewFlagSet(f.Arg(0), flag.ContinueOnError)
   101  				fs.Usage = func() { h.cdr.ExplainCommand(h.cdr.Error, cmd) }
   102  				cmd.SetFlags(fs)
   103  				if fs.Parse(f.Args()[1:]) != nil {
   104  					return subcommands.ExitUsageError
   105  				}
   106  				return cmd.Execute(ctx, f, args...)
   107  			}
   108  		}
   109  
   110  		fmt.Fprintf(h.cdr.Error, "Subcommand %s not understood\n", f.Arg(0))
   111  	}
   112  
   113  	f.Usage()
   114  	return subcommands.ExitUsageError
   115  }
   116  
   117  // Register registers a new help command.
   118  func (h *Help) Register(cmd subcommands.Command) {
   119  	h.commands = append(h.commands, cmd)
   120  }