packer-cn/packer/environment.go

172 lines
4.1 KiB
Go
Raw Normal View History

// The packer package contains the core components of Packer.
package packer
2013-03-24 19:28:35 -04:00
import (
"errors"
2013-03-24 19:28:35 -04:00
"fmt"
"log"
2013-03-24 19:28:35 -04:00
"os"
"sort"
"strings"
)
type BuilderFunc func(name string) (Builder, error)
2013-05-05 17:47:17 -04:00
type CommandFunc func(name string) (Command, error)
2013-05-05 17:47:17 -04:00
2013-05-02 17:03:55 -04:00
// The environment interface provides access to the configuration and
// state of a single Packer run.
//
2013-05-02 17:03:55 -04:00
// It allows for things such as executing CLI commands, getting the
// list of available builders, and more.
type Environment interface {
Builder(name string) (Builder, error)
Cli(args []string) (int, error)
2013-05-02 17:03:55 -04:00
Ui() Ui
}
// An implementation of an Environment that represents the Packer core
// environment.
type coreEnvironment struct {
2013-05-05 17:47:17 -04:00
builderFunc BuilderFunc
commands []string
commandFunc CommandFunc
ui Ui
}
2013-04-15 23:26:38 -04:00
// This struct configures new environments.
type EnvironmentConfig struct {
2013-05-05 17:47:17 -04:00
BuilderFunc BuilderFunc
CommandFunc CommandFunc
Commands []string
Ui Ui
2013-04-15 23:26:38 -04:00
}
// DefaultEnvironmentConfig returns a default EnvironmentConfig that can
// be used to create a new enviroment with NewEnvironment with sane defaults.
func DefaultEnvironmentConfig() *EnvironmentConfig {
config := &EnvironmentConfig{}
config.BuilderFunc = func(string) (Builder, error) { return nil, nil }
config.CommandFunc = func(string) (Command, error) { return nil, nil }
2013-05-05 17:47:17 -04:00
config.Commands = make([]string, 0)
config.Ui = &ReaderWriterUi{os.Stdin, os.Stdout}
return config
}
2013-04-15 23:26:38 -04:00
// This creates a new environment
2013-05-02 17:03:55 -04:00
func NewEnvironment(config *EnvironmentConfig) (resultEnv Environment, err error) {
if config == nil {
err = errors.New("config must be given to initialize environment")
return
2013-04-15 23:26:38 -04:00
}
2013-05-02 17:03:55 -04:00
env := &coreEnvironment{}
2013-05-05 17:47:17 -04:00
env.builderFunc = config.BuilderFunc
env.commandFunc = config.CommandFunc
env.commands = config.Commands
env.ui = config.Ui
2013-05-02 17:03:55 -04:00
resultEnv = env
return
}
// Returns a builder of the given name that is registered with this
// environment.
func (e *coreEnvironment) Builder(name string) (b Builder, err error) {
b, err = e.builderFunc(name)
if err != nil {
return
}
if b == nil {
err = fmt.Errorf("No builder returned for name: %s", name)
}
return
}
// 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 *coreEnvironment) Cli(args []string) (result int, err error) {
log.Printf("Environment.Cli: %#v\n", args)
if len(args) == 0 || args[0] == "--help" || args[0] == "-h" {
2013-05-02 17:03:55 -04:00
e.printHelp()
return 1, nil
}
2013-05-05 17:47:17 -04:00
version := args[0] == "version"
if !version {
for _, arg := range args {
if arg == "--version" || arg == "-v" {
2013-05-05 17:47:17 -04:00
version = true
break
}
}
2013-05-05 17:47:17 -04:00
}
var command Command
if version {
command = new(versionCommand)
}
if command == nil {
command, err = e.commandFunc(args[0])
if err != nil {
return
}
// If we still don't have a command, show the help.
if command == nil {
log.Printf("Environment.CLI: command not found: %s\n", args[0])
2013-05-02 17:03:55 -04:00
e.printHelp()
return 1, nil
}
}
return command.Run(e, args[1:]), nil
}
// Prints the CLI help to the UI.
2013-05-02 17:03:55 -04:00
func (e *coreEnvironment) 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.
i := 0
maxKeyLen := 0
2013-05-05 17:47:17 -04:00
for _, command := range e.commands {
if len(command) > maxKeyLen {
maxKeyLen = len(command)
2013-03-24 19:28:35 -04:00
}
i++
}
// Sort the keys
2013-05-05 17:47:17 -04:00
sort.Strings(e.commands)
2013-03-24 19:28:35 -04:00
e.ui.Say("usage: packer [--version] [--help] <command> [<args>]\n\n")
e.ui.Say("Available commands are:\n")
2013-05-05 17:47:17 -04:00
for _, key := range e.commands {
var synopsis string
command, err := e.commandFunc(key)
if err != nil {
synopsis = fmt.Sprintf("Error loading command: %s", err.Error())
} else {
synopsis = command.Synopsis()
}
2013-03-24 19:28:35 -04:00
// 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, synopsis)
2013-03-24 19:28:35 -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.
2013-05-02 17:03:55 -04:00
func (e *coreEnvironment) Ui() Ui {
2013-03-24 19:41:58 -04:00
return e.ui
}