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