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  }