github.com/linuxboot/fiano@v1.2.0/pkg/visitors/cli.go (about)

     1  // Copyright 2018 the LinuxBoot Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package visitors uses the Visitor interface to recursively apply an
     6  // operation over the firmware image. Also, functions are exported for using
     7  // the visitors through the command line.
     8  package visitors
     9  
    10  import (
    11  	"fmt"
    12  	"sort"
    13  
    14  	"github.com/linuxboot/fiano/pkg/uefi"
    15  )
    16  
    17  var visitorRegistry = map[string]visitorEntry{}
    18  
    19  type visitorEntry struct {
    20  	numArgs       int
    21  	help          string
    22  	createVisitor func([]string) (uefi.Visitor, error)
    23  }
    24  
    25  const (
    26  	helpMessage = "Usage: utk FILE [COMMAND [ARGS]]..."
    27  )
    28  
    29  // RegisterCLI registers a function `createVisitor` to be called when parsing
    30  // the arguments with `ParseCLI`. For a Visitor to be accessible from the
    31  // command line, it should have an init function which registers a
    32  // `createVisitor` function here.
    33  func RegisterCLI(name string, help string, numArgs int, createVisitor func([]string) (uefi.Visitor, error)) {
    34  	if _, ok := visitorRegistry[name]; ok {
    35  		panic(fmt.Sprintf("two visitors registered the same name: '%s'", name))
    36  	}
    37  	visitorRegistry[name] = visitorEntry{
    38  		numArgs:       numArgs,
    39  		createVisitor: createVisitor,
    40  		help:          help,
    41  	}
    42  }
    43  
    44  // ParseCLI constructs a list of visitors from the given CLI argument list.
    45  func ParseCLI(args []string) ([]uefi.Visitor, error) {
    46  	visitors := []uefi.Visitor{}
    47  	for len(args) > 0 {
    48  		cmd := args[0]
    49  		args = args[1:]
    50  		o, ok := visitorRegistry[cmd]
    51  		if !ok {
    52  			return []uefi.Visitor{}, fmt.Errorf("could not find command '%s'\n%s", cmd, helpMessage)
    53  		}
    54  		if o.numArgs > len(args) {
    55  			return []uefi.Visitor{}, fmt.Errorf("too few arguments for command '%s', got %d, expected %d.\nSynopsis: %s",
    56  				cmd, len(args), o.numArgs, o.help)
    57  		}
    58  		visitor, err := o.createVisitor(args[:o.numArgs])
    59  		if err != nil {
    60  			return []uefi.Visitor{}, err
    61  		}
    62  		visitors = append(visitors, visitor)
    63  		args = args[o.numArgs:]
    64  	}
    65  	return visitors, nil
    66  }
    67  
    68  // ExecuteCLI applies each Visitor over the firmware in sequence.
    69  func ExecuteCLI(f uefi.Firmware, v []uefi.Visitor) error {
    70  	for i := range v {
    71  		if err := v[i].Run(f); err != nil {
    72  			return err
    73  		}
    74  	}
    75  	return nil
    76  }
    77  
    78  // ListCLI prints out the help entries in the visitor struct
    79  // as a newline-separated string in the form:
    80  //   name: help
    81  func ListCLI() string {
    82  	var s string
    83  	names := []string{}
    84  	for n := range visitorRegistry {
    85  		names = append(names, n)
    86  	}
    87  	sort.Strings(names)
    88  	for _, n := range names {
    89  		s += fmt.Sprintf("  %-22s: %s\n", n, visitorRegistry[n].help)
    90  	}
    91  	return s
    92  }