packer, etc: added Help method to Command interface

This will be used for long-form help when "packer help foo"
or "packer foo --help" is called.
This commit is contained in:
Mitchell Hashimoto 2013-06-02 11:41:12 -07:00
parent cf732a913d
commit bbafcfa938
9 changed files with 81 additions and 11 deletions

View File

@ -10,6 +10,10 @@ import (
type Command byte type Command byte
func (Command) Help() string {
return "help"
}
func (Command) Run(env packer.Environment, args []string) int { func (Command) Run(env packer.Environment, args []string) int {
if len(args) != 1 { if len(args) != 1 {
env.Ui().Error("A single template argument is required.") env.Ui().Error("A single template argument is required.")

View File

@ -22,6 +22,13 @@ func testEnvironment() packer.Environment {
return env return env
} }
func TestCommand_Implements(t *testing.T) {
assert := asserts.NewTestingAsserts(t, true)
var actual packer.Command
assert.Implementor(new(Command), &actual, "should be a Command")
}
func TestCommand_Run_NoArgs(t *testing.T) { func TestCommand_Run_NoArgs(t *testing.T) {
assert := asserts.NewTestingAsserts(t, true) assert := asserts.NewTestingAsserts(t, true)
command := new(Command) command := new(Command)

View File

@ -6,14 +6,18 @@ package packer
// //
// The mapping of command names to command interfaces is in the // The mapping of command names to command interfaces is in the
// Environment struct. // Environment struct.
//
// Run should run the actual command with the given environmet and
// command-line arguments. It should return the exit status when it is
// finished.
//
// Synopsis should return a one-line, short synopsis of the command.
// This should be less than 50 characters ideally.
type Command interface { type Command interface {
// Help should return long-form help text that includes the command-line
// usage, a brief few sentences explaining the function of the command,
// and the complete list of flags the command accepts.
Help() string
// Run should run the actual command with the given environmet and
// command-line arguments. It should return the exit status when it is
// finished.
Run(env Environment, args []string) int Run(env Environment, args []string) int
// Synopsis should return a one-line, short synopsis of the command.
// This should be less than 50 characters ideally.
Synopsis() string Synopsis() string
} }

View File

@ -6,6 +6,10 @@ type TestCommand struct {
runEnv Environment runEnv Environment
} }
func (tc *TestCommand) Help() string {
return "bar"
}
func (tc *TestCommand) Run(env Environment, args []string) int { func (tc *TestCommand) Run(env Environment, args []string) int {
tc.runCalled = true tc.runCalled = true
tc.runArgs = args tc.runArgs = args

View File

@ -13,6 +13,16 @@ type cmdCommand struct {
client *client client *client
} }
func (c *cmdCommand) Help() (result string) {
defer func() {
r := recover()
c.checkExit(r, func() { result = "" })
}()
result = c.command.Help()
return
}
func (c *cmdCommand) Run(e packer.Environment, args []string) (exitCode int) { func (c *cmdCommand) Run(e packer.Environment, args []string) (exitCode int) {
defer func() { defer func() {
r := recover() r := recover()

View File

@ -7,11 +7,12 @@ import (
"testing" "testing"
) )
// TODO: Test command cleanup functionality
// TODO: Test timeout functionality
type helperCommand byte type helperCommand byte
func (helperCommand) Help() string {
return "2"
}
func (helperCommand) Run(packer.Environment, []string) int { func (helperCommand) Run(packer.Environment, []string) int {
return 42 return 42
} }
@ -37,6 +38,9 @@ func TestCommand_Good(t *testing.T) {
if command != nil { if command != nil {
result := command.Synopsis() result := command.Synopsis()
assert.Equal(result, "1", "should return result") assert.Equal(result, "1", "should return result")
result = command.Help()
assert.Equal(result, "2", "should return result")
} }
} }

View File

@ -28,6 +28,15 @@ func Command(client *rpc.Client) *command {
return &command{client} return &command{client}
} }
func (c *command) Help() (result string) {
err := c.client.Call("Command.Help", new(interface{}), &result)
if err != nil {
panic(err)
}
return
}
func (c *command) Run(env packer.Environment, args []string) (result int) { func (c *command) Run(env packer.Environment, args []string) (result int) {
// Create and start the server for the Environment // Create and start the server for the Environment
server := rpc.NewServer() server := rpc.NewServer()
@ -51,6 +60,11 @@ func (c *command) Synopsis() (result string) {
return return
} }
func (c *CommandServer) Help(args *interface{}, reply *string) error {
*reply = c.command.Help()
return nil
}
func (c *CommandServer) Run(args *CommandRunArgs, reply *int) error { func (c *CommandServer) Run(args *CommandRunArgs, reply *int) error {
client, err := rpc.Dial("tcp", args.RPCAddress) client, err := rpc.Dial("tcp", args.RPCAddress)
if err != nil { if err != nil {

View File

@ -13,6 +13,10 @@ type TestCommand struct {
runEnv packer.Environment runEnv packer.Environment
} }
func (tc *TestCommand) Help() string {
return "bar"
}
func (tc *TestCommand) Run(env packer.Environment, args []string) int { func (tc *TestCommand) Run(env packer.Environment, args []string) int {
tc.runCalled = true tc.runCalled = true
tc.runArgs = args tc.runArgs = args
@ -42,6 +46,10 @@ func TestRPCCommand(t *testing.T) {
clientComm := Command(client) clientComm := Command(client)
//Test Help
help := clientComm.Help()
assert.Equal(help, "bar", "helps hould be correct")
// Test run // Test run
runArgs := []string{"foo", "bar"} runArgs := []string{"foo", "bar"}
testEnv := &testEnvironment{} testEnv := &testEnvironment{}
@ -59,3 +67,12 @@ func TestRPCCommand(t *testing.T) {
synopsis := clientComm.Synopsis() synopsis := clientComm.Synopsis()
assert.Equal(synopsis, "foo", "Synopsis should be correct") assert.Equal(synopsis, "foo", "Synopsis should be correct")
} }
func TestCommand_Implements(t *testing.T) {
assert := asserts.NewTestingAsserts(t, true)
var r packer.Command
c := Command(nil)
assert.Implementor(c, &r, "should be a Builder")
}

View File

@ -7,7 +7,13 @@ const Version = "0.1.0.dev"
type versionCommand byte type versionCommand byte
// Implement the Command interface by simply showing the version func (versionCommand) Help() string {
return `usage: packer version
Outputs the version of Packer that is running. There are no additional
command-line flags for this command.`
}
func (versionCommand) Run(env Environment, args []string) int { func (versionCommand) Run(env Environment, args []string) int {
env.Ui().Say(fmt.Sprintf("Packer v%v\n", Version)) env.Ui().Say(fmt.Sprintf("Packer v%v\n", Version))
return 0 return 0