Turn Environment into an interface

This commit is contained in:
Mitchell Hashimoto 2013-05-02 14:03:55 -07:00
parent fefd2ae208
commit 520503e10c
5 changed files with 35 additions and 26 deletions

View File

@ -6,7 +6,7 @@ import (
type buildCommand byte
func (buildCommand) Run(env *Environment, args []string) int {
func (buildCommand) Run(env Environment, args []string) int {
if len(args) != 1 {
// TODO: Error message
return 1

View File

@ -1,5 +1,7 @@
package packer
import "net/rpc"
// A command is a runnable sub-command of the `packer` application.
// When `packer` is called with the proper subcommand, this will be
// called.
@ -14,7 +16,12 @@ package packer
// Synopsis should return a one-line, short synopsis of the command.
// This should be less than 50 characters ideally.
type Command interface {
Run(env *Environment, args []string) int
Run(env Environment, args []string) int
Synopsis() string
}
// An RPCCommand is an implementation of the Command interface where the
// command is actually executed over an RPC connection.
type RPCCommand struct {
client *rpc.Client
}

View File

@ -9,14 +9,20 @@ import (
"strings"
)
// The environment struct contains all the state necessary for a single
// instance of Packer.
// The environment interface provides access to the configuration and
// state of a single Packer run.
//
// It is *not* a singleton, but generally a single environment is created
// when Packer starts running to represent that Packer run. Technically,
// if you're building a custom Packer binary, you could instantiate multiple
// environments and run them in parallel.
type Environment struct {
// It allows for things such as executing CLI commands, getting the
// list of available builders, and more.
type Environment interface {
BuilderFactory() BuilderFactory
Cli(args []string) int
Ui() Ui
}
// An implementation of an Environment that represents the Packer core
// environment.
type coreEnvironment struct {
builderFactory BuilderFactory
command map[string]Command
ui Ui
@ -40,13 +46,13 @@ func DefaultEnvironmentConfig() *EnvironmentConfig {
}
// This creates a new environment
func NewEnvironment(config *EnvironmentConfig) (env *Environment, err error) {
func NewEnvironment(config *EnvironmentConfig) (resultEnv Environment, err error) {
if config == nil {
err = errors.New("config must be given to initialize environment")
return
}
env = &Environment{}
env := &coreEnvironment{}
env.builderFactory = config.BuilderFactory
env.command = make(map[string]Command)
env.ui = config.Ui
@ -60,19 +66,20 @@ func NewEnvironment(config *EnvironmentConfig) (env *Environment, err error) {
env.command["version"] = new(versionCommand)
}
resultEnv = env
return
}
// Returns the BuilderFactory associated with this Environment.
func (e *Environment) BuilderFactory() BuilderFactory {
func (e *coreEnvironment) BuilderFactory() BuilderFactory {
return e.builderFactory
}
// Executes a command as if it was typed on the command-line interface.
// The return value is the exit code of the command.
func (e *Environment) Cli(args []string) int {
func (e *coreEnvironment) Cli(args []string) int {
if len(args) == 0 || args[0] == "--help" || args[0] == "-h" {
e.PrintHelp()
e.printHelp()
return 1
}
@ -89,7 +96,7 @@ func (e *Environment) Cli(args []string) int {
// If we still don't have a command, show the help.
if command == nil {
e.PrintHelp()
e.printHelp()
return 1
}
}
@ -98,7 +105,7 @@ func (e *Environment) Cli(args []string) int {
}
// Prints the CLI help to the UI.
func (e *Environment) PrintHelp() {
func (e *coreEnvironment) printHelp() {
// Created a sorted slice of the map keys and record the longest
// command name so we can better format the output later.
commandKeys := make([]string, len(e.command))
@ -131,6 +138,6 @@ func (e *Environment) PrintHelp() {
// Returns the UI for the environment. The UI is the interface that should
// be used for all communication with the outside world.
func (e *Environment) Ui() Ui {
func (e *coreEnvironment) Ui() Ui {
return e.ui
}

View File

@ -11,10 +11,10 @@ import (
type TestCommand struct {
runArgs []string
runCalled bool
runEnv *Environment
runEnv Environment
}
func (tc *TestCommand) Run(env *Environment, args []string) int {
func (tc *TestCommand) Run(env Environment, args []string) int {
tc.runCalled = true
tc.runArgs = args
tc.runEnv = env
@ -25,7 +25,7 @@ func (tc *TestCommand) Synopsis() string {
return ""
}
func testEnvironment() *Environment {
func testEnvironment() Environment {
config := &EnvironmentConfig{}
config.Ui = &ReaderWriterUi{
new(bytes.Buffer),
@ -140,11 +140,6 @@ func TestEnvironment_DefaultCli_Version(t *testing.T) {
assert.Equal(defaultEnv.Cli([]string{"bad", "version"}), 1, "version should NOT work anywhere")
}
func TestEnvironment_PrintHelp(t *testing.T) {
// Just call the function and verify that no panics occur
testEnvironment().PrintHelp()
}
func TestEnvironment_SettingUi(t *testing.T) {
assert := asserts.NewTestingAsserts(t, true)

View File

@ -6,7 +6,7 @@ const Version = "0.1.0.dev"
type versionCommand byte
// Implement the Command interface by simply showing the version
func (versionCommand) Run(env *Environment, args []string) int {
func (versionCommand) Run(env Environment, args []string) int {
env.Ui().Say("Packer v%v\n", Version)
return 0
}