diff --git a/.gitignore b/.gitignore index 9fe5baeb6..5e56e040e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ /bin -/packer diff --git a/Makefile b/Makefile index f01239e52..d16327fb5 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ all: @mkdir -p bin/ - go get -a + go get -d go build -a -o bin/packer .PHONY: all diff --git a/builder/amazon/builder.go b/builder/amazon/builder.go index 62d626081..27a47afbc 100644 --- a/builder/amazon/builder.go +++ b/builder/amazon/builder.go @@ -11,11 +11,12 @@ type Builder struct { config config } +func (b *Builder) ConfigInterface() interface{} { + return &b.config +} + func (*Builder) Prepare() { } -func (*Builder) Build() { -} - -func (*Builder) Destroy() { +func (b *Builder) Build() { } diff --git a/example.json b/example.json new file mode 100644 index 000000000..0ff9c3987 --- /dev/null +++ b/example.json @@ -0,0 +1,24 @@ +{ + "name": "my-custom-image", + + "builders": [ + { + "type": "amazon-ebs", + "region": "us-east-1", + "source": "ami-de0d9eb7" + } + ], + + "provisioners": [ + { + "type": "shell", + "path": "script.sh" + } + ], + + "outputs": [ + { + "type": "vagrant" + } + ] +} diff --git a/packer.go b/packer.go index c4ede8395..8f648ec07 100644 --- a/packer.go +++ b/packer.go @@ -1,44 +1,40 @@ // This is the main package for the `packer` application. package main -import "github.com/mitchellh/packer/builder/amazon" +import "github.com/mitchellh/packer/packer" +import "os" -// A command is a runnable sub-command of the `packer` application. -// When `packer` is called with the proper subcommand, this will be -// called. -// -// The mapping of command names to command interfaces is in the -// Environment struct. -type Command interface { - Run(args []string) -} - -// The environment struct contains all the state necessary for a single -// instance of Packer. -// -// 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 { - commands map[string]Command -} - -type Template struct { +type RawTemplate struct { Name string - Builders map[string]interface{} `toml:"builder"` - Provisioners map[string]interface{} `toml:"provision"` - Outputs map[string]interface{} `toml:"output"` + Builders []map[string]interface{} + Provisioners []map[string]interface{} + Outputs []map[string]interface{} } type Builder interface { + ConfigInterface() interface{} Prepare() Build() - Destroy() +} + +type Build interface { + Hook(name string) } func main() { - var builder Builder - builder = &amazon.Builder{} - builder.Build() + env := packer.NewEnvironment() + os.Exit(env.Cli(os.Args[1:])) + /* + file, _ := ioutil.ReadFile("example.json") + + var tpl RawTemplate + json.Unmarshal(file, &tpl) + fmt.Printf("%#v\n", tpl) + + builderType, ok := tpl.Builders[0]["type"].(Build) + if !ok { + panic("OH NOES") + } + fmt.Printf("TYPE: %v\n", builderType) + */ } diff --git a/packer/environment.go b/packer/environment.go new file mode 100644 index 000000000..b732a83ea --- /dev/null +++ b/packer/environment.go @@ -0,0 +1,75 @@ +// The packer package contains the core components of Packer. +package packer + +import "os" + +// A command is a runnable sub-command of the `packer` application. +// When `packer` is called with the proper subcommand, this will be +// called. +// +// The mapping of command names to command interfaces is in the +// Environment struct. +type Command interface { + Run(env *Environment, args []string) int +} + +// The environment struct contains all the state necessary for a single +// instance of Packer. +// +// 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 { + command map[string]Command + ui Ui +} + +// This creates a new environment +func NewEnvironment() *Environment { + env := &Environment{} + env.command = make(map[string]Command) + env.command["version"] = new(versionCommand) + env.ui = &ReaderWriterUi{ os.Stdin, os.Stdout } + return env +} + +// 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 { + if len(args) == 0 { + e.PrintHelp() + return 1 + } + + command, ok := e.command[args[0]] + if !ok { + // The command was not found. In this case, let's go through + // the arguments and see if the user is requesting the version. + for _, arg := range args { + if arg == "--version" || arg == "-v" { + command = e.command["version"] + break + } + } + + // If we still don't have a command, show the help. + if command == nil { + e.PrintHelp() + return 1 + } + } + + return command.Run(e, args) +} + +// 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 { + return e.ui +} + +// Prints the CLI help to the UI. +func (e *Environment) PrintHelp() { + e.ui.Say("Bad.\n") +} diff --git a/packer/ui.go b/packer/ui.go new file mode 100644 index 000000000..c8ee559d8 --- /dev/null +++ b/packer/ui.go @@ -0,0 +1,22 @@ +package packer + +import "fmt" +import "io" + +// The Ui interface handles all communication for Packer with the outside +// world. This sort of control allows us to strictly control how output +// is formatted and various levels of output. +type Ui interface { + Say(format string, a ...interface{}) +} + +// The ReaderWriterUi is a UI that writes and reads from standard Go +// io.Reader and io.Writer. +type ReaderWriterUi struct { + Reader io.Reader + Writer io.Writer +} + +func (rw *ReaderWriterUi) Say(format string, a ...interface{}) { + fmt.Fprintf(rw.Writer, format, a...) +} diff --git a/packer/version.go b/packer/version.go new file mode 100644 index 000000000..394834a8a --- /dev/null +++ b/packer/version.go @@ -0,0 +1,12 @@ +package packer + +// The version of packer. +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 { + env.Ui().Say("Packer v%v\n", Version) + return 0 +}