2013-03-24 17:03:53 -04:00
|
|
|
// The packer package contains the core components of Packer.
|
|
|
|
package packer
|
|
|
|
|
2013-03-24 19:28:35 -04:00
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
)
|
2013-03-24 17:03:53 -04:00
|
|
|
|
|
|
|
// 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.
|
2013-03-24 19:35:33 -04:00
|
|
|
//
|
|
|
|
// 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.
|
2013-03-24 17:03:53 -04:00
|
|
|
type Command interface {
|
|
|
|
Run(env *Environment, args []string) int
|
2013-03-24 19:28:35 -04:00
|
|
|
Synopsis() string
|
2013-03-24 17:03:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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 {
|
2013-04-15 22:53:29 -04:00
|
|
|
builder map[string]Builder
|
2013-03-24 17:03:53 -04:00
|
|
|
command map[string]Command
|
|
|
|
ui Ui
|
|
|
|
}
|
|
|
|
|
2013-04-15 23:26:38 -04:00
|
|
|
// This struct configures new environments.
|
|
|
|
type EnvironmentConfig struct {
|
|
|
|
builder map[string]Builder
|
|
|
|
command map[string]Command
|
|
|
|
ui Ui
|
|
|
|
}
|
|
|
|
|
2013-03-24 17:03:53 -04:00
|
|
|
// This creates a new environment
|
2013-04-15 23:26:38 -04:00
|
|
|
func NewEnvironment(config *EnvironmentConfig) *Environment {
|
2013-03-24 17:03:53 -04:00
|
|
|
env := &Environment{}
|
2013-04-15 22:53:29 -04:00
|
|
|
env.builder = make(map[string]Builder)
|
2013-03-24 17:03:53 -04:00
|
|
|
env.command = make(map[string]Command)
|
2013-04-15 23:26:38 -04:00
|
|
|
|
|
|
|
if config != nil {
|
|
|
|
for k, v := range config.builder {
|
|
|
|
env.builder[k] = v
|
|
|
|
}
|
|
|
|
|
|
|
|
for k, v := range config.command {
|
|
|
|
env.command[k] = v
|
|
|
|
}
|
|
|
|
|
|
|
|
env.ui = config.ui
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, ok := env.command["build"]; !ok {
|
|
|
|
env.command["build"] = new(buildCommand)
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, ok := env.command["version"]; !ok {
|
|
|
|
env.command["version"] = new(versionCommand)
|
|
|
|
}
|
|
|
|
|
|
|
|
if env.ui == nil {
|
|
|
|
env.ui = &ReaderWriterUi{os.Stdin, os.Stdout}
|
|
|
|
}
|
|
|
|
|
2013-03-24 17:03:53 -04:00
|
|
|
return env
|
|
|
|
}
|
|
|
|
|
2013-04-15 22:53:29 -04:00
|
|
|
// Looks up a builder with the given name and returns an interface
|
|
|
|
// to access it.
|
|
|
|
func (e *Environment) Builder(name string) Builder {
|
|
|
|
return e.builder[name]
|
|
|
|
}
|
|
|
|
|
2013-03-24 17:03:53 -04:00
|
|
|
// 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 {
|
2013-03-24 19:35:33 -04:00
|
|
|
if len(args) == 0 || args[0] == "--help" || args[0] == "-h" {
|
2013-03-24 17:03:53 -04:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-15 18:03:41 -04:00
|
|
|
return command.Run(e, args[1:])
|
2013-03-24 17:03:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Prints the CLI help to the UI.
|
|
|
|
func (e *Environment) PrintHelp() {
|
2013-03-24 19:28:35 -04:00
|
|
|
// 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))
|
|
|
|
i := 0
|
|
|
|
maxKeyLen := 0
|
|
|
|
for key, _ := range e.command {
|
|
|
|
commandKeys[i] = key
|
|
|
|
if len(key) > maxKeyLen {
|
|
|
|
maxKeyLen = len(key)
|
|
|
|
}
|
|
|
|
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sort the keys
|
|
|
|
sort.Strings(commandKeys)
|
|
|
|
|
|
|
|
e.ui.Say("usage: packer [--version] [--help] <command> [<args>]\n\n")
|
|
|
|
e.ui.Say("Available commands are:\n")
|
|
|
|
for _, key := range commandKeys {
|
|
|
|
command := e.command[key]
|
|
|
|
|
|
|
|
// Pad the key with spaces so that they're all the same width
|
2013-03-24 19:36:02 -04:00
|
|
|
key = fmt.Sprintf("%v%v", key, strings.Repeat(" ", maxKeyLen-len(key)))
|
2013-03-24 19:28:35 -04:00
|
|
|
|
|
|
|
// Output the command and the synopsis
|
|
|
|
e.ui.Say(" %v %v\n", key, command.Synopsis())
|
|
|
|
}
|
2013-03-24 17:03:53 -04:00
|
|
|
}
|
2013-03-24 19:41:58 -04:00
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|