github.com/aca02djr/gb@v0.4.1/cmd/cmd.go (about) 1 // Package command holds support functions and types for writing gb and gb plugins 2 package cmd 3 4 import ( 5 "flag" 6 "fmt" 7 "os" 8 "path/filepath" 9 10 "github.com/constabulary/gb" 11 "github.com/constabulary/gb/debug" 12 ) 13 14 // Command represents a subcommand, or plugin that is executed within 15 // a gb project. 16 type Command struct { 17 // Name of the command 18 Name string 19 20 // UsageLine demonstrates how to use this command 21 UsageLine string 22 23 // Single line description of the purpose of the command 24 Short string 25 26 // Description of this command 27 Long string 28 29 // Run is invoked with a Context derived from the Project and arguments 30 // left over after flag parsing. 31 Run func(ctx *gb.Context, args []string) error 32 33 // AddFlags installs additional flags to be parsed before Run. 34 AddFlags func(fs *flag.FlagSet) 35 36 // Allow plugins to modify arguments 37 FlagParse func(fs *flag.FlagSet, args []string) error 38 39 // SkipParseArgs avoids parsing arguments as import paths. 40 SkipParseArgs bool 41 } 42 43 // Runnable indicates this is a command that can be involved. 44 // Non runnable commands are only informational. 45 func (c *Command) Runnable() bool { return c.Run != nil } 46 47 // Hidden indicates this is a command which is hidden from help / alldoc.go. 48 func (c *Command) Hidden() bool { return c.Name == "depset" } 49 50 // RunCommand detects the project root, parses flags and runs the Command. 51 func RunCommand(fs *flag.FlagSet, cmd *Command, projectroot, goroot string, args []string) error { 52 if cmd.AddFlags != nil { 53 cmd.AddFlags(fs) 54 } 55 if err := fs.Parse(args); err != nil { 56 fs.Usage() 57 os.Exit(1) 58 } 59 args = fs.Args() // reset to the remaining arguments 60 61 ctx, err := NewContext(projectroot, gb.GcToolchain()) 62 if err != nil { 63 return fmt.Errorf("unable to construct context: %v", err) 64 } 65 defer ctx.Destroy() 66 67 debug.Debugf("args: %v", args) 68 return cmd.Run(ctx, args) 69 } 70 71 // NewContext creates a gb.Context for the project root. 72 func NewContext(projectroot string, options ...func(*gb.Context) error) (*gb.Context, error) { 73 if projectroot == "" { 74 return nil, fmt.Errorf("project root is blank") 75 } 76 77 root, err := FindProjectroot(projectroot) 78 if err != nil { 79 return nil, fmt.Errorf("could not locate project root: %v", err) 80 } 81 project := gb.NewProject(root, 82 gb.SourceDir(filepath.Join(root, "src")), 83 gb.SourceDir(filepath.Join(root, "vendor", "src")), 84 ) 85 86 debug.Debugf("project root %q", project.Projectdir()) 87 return project.NewContext(options...) 88 }