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 }