Commit 089df41a authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

common/command: introduce this package for common cmmand stuff

parent 643d9033
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"flag" "flag"
"fmt" "fmt"
cmdcommon "github.com/mitchellh/packer/common/command"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"io/ioutil" "io/ioutil"
"log" "log"
...@@ -22,15 +23,13 @@ func (Command) Help() string { ...@@ -22,15 +23,13 @@ func (Command) Help() string {
func (c Command) Run(env packer.Environment, args []string) int { func (c Command) Run(env packer.Environment, args []string) int {
var cfgDebug bool var cfgDebug bool
var cfgForce bool var cfgForce bool
var cfgExcept []string buildFilters := new(cmdcommon.BuildFilters)
var cfgOnly []string
cmdFlags := flag.NewFlagSet("build", flag.ContinueOnError) cmdFlags := flag.NewFlagSet("build", flag.ContinueOnError)
cmdFlags.Usage = func() { env.Ui().Say(c.Help()) } cmdFlags.Usage = func() { env.Ui().Say(c.Help()) }
cmdFlags.BoolVar(&cfgDebug, "debug", false, "debug mode for builds") cmdFlags.BoolVar(&cfgDebug, "debug", false, "debug mode for builds")
cmdFlags.BoolVar(&cfgForce, "force", false, "force a build if artifacts exist") cmdFlags.BoolVar(&cfgForce, "force", false, "force a build if artifacts exist")
cmdFlags.Var((*stringSliceValue)(&cfgExcept), "except", "build all builds except these") cmdcommon.BuildFilterFlags(cmdFlags, buildFilters)
cmdFlags.Var((*stringSliceValue)(&cfgOnly), "only", "only build the given builds by name")
if err := cmdFlags.Parse(args); err != nil { if err := cmdFlags.Parse(args); err != nil {
return 1 return 1
} }
...@@ -41,8 +40,9 @@ func (c Command) Run(env packer.Environment, args []string) int { ...@@ -41,8 +40,9 @@ func (c Command) Run(env packer.Environment, args []string) int {
return 1 return 1
} }
if len(cfgOnly) > 0 && len(cfgExcept) > 0 { if err := buildFilters.Validate(); err != nil {
env.Ui().Error("Only one of '-except' or '-only' may be specified.\n") env.Ui().Error(err.Error())
env.Ui().Error("")
env.Ui().Error(c.Help()) env.Ui().Error(c.Help())
return 1 return 1
} }
...@@ -72,49 +72,12 @@ func (c Command) Run(env packer.Environment, args []string) int { ...@@ -72,49 +72,12 @@ func (c Command) Run(env packer.Environment, args []string) int {
} }
// Go through each builder and compile the builds that we care about // Go through each builder and compile the builds that we care about
buildNames := tpl.BuildNames() builds, err := buildFilters.Builds(tpl, components)
builds := make([]packer.Build, 0, len(buildNames))
for _, buildName := range buildNames {
if len(cfgExcept) > 0 {
found := false
for _, only := range cfgExcept {
if buildName == only {
found = true
break
}
}
if found {
log.Printf("Skipping build '%s' because specified by -except.", buildName)
continue
}
}
if len(cfgOnly) > 0 {
found := false
for _, only := range cfgOnly {
if buildName == only {
found = true
break
}
}
if !found {
log.Printf("Skipping build '%s' because not specified by -only.", buildName)
continue
}
}
log.Printf("Creating build: %s", buildName)
build, err := tpl.Build(buildName, components)
if err != nil { if err != nil {
env.Ui().Error(fmt.Sprintf("Failed to create build '%s': \n\n%s", buildName, err)) env.Ui().Error(err.Error())
return 1 return 1
} }
builds = append(builds, build)
}
if cfgDebug { if cfgDebug {
env.Ui().Say("Debug mode enabled. Builds will not be parallelized.") env.Ui().Say("Debug mode enabled. Builds will not be parallelized.")
} }
......
package build
import "strings"
type stringSliceValue []string
func (s *stringSliceValue) String() string {
return strings.Join(*s, ",")
}
func (s *stringSliceValue) Set(value string) error {
*s = strings.Split(value, ",")
return nil
}
package command
import (
"flag"
)
// BuildFilterFlags sets the proper command line flags needed for
// build filters.
func BuildFilterFlags(fs *flag.FlagSet, f *BuildFilters) {
fs.Var((*SliceValue)(&f.Except), "except", "build all builds except these")
fs.Var((*SliceValue)(&f.Only), "only", "only build the given builds by name")
}
package command
import "strings"
// SliceValue implements the flag.Value interface and allows a list of
// strings to be given on the command line and properly parsed into a slice
// of strings internally.
type SliceValue []string
func (s *SliceValue) String() string {
return strings.Join(*s, ",")
}
func (s *SliceValue) Set(value string) error {
*s = strings.Split(value, ",")
return nil
}
package command
import (
"flag"
"reflect"
"testing"
)
func TestSliceValue_implements(t *testing.T) {
var raw interface{}
raw = new(SliceValue)
if _, ok := raw.(flag.Value); !ok {
t.Fatalf("SliceValue should be a Value")
}
}
func TestSliceValueSet(t *testing.T) {
sv := new(SliceValue)
err := sv.Set("foo,bar,baz")
if err != nil {
t.Fatalf("err: %s", err)
}
expected := []string{"foo", "bar", "baz"}
if !reflect.DeepEqual([]string(*sv), expected) {
t.Fatalf("Bad: %#v", sv)
}
}
package command
import (
"errors"
"fmt"
"github.com/mitchellh/packer/packer"
"log"
)
// BuildFilters is a set of options to filter the builds out of a template.
type BuildFilters struct {
Except []string
Only []string
}
// Validate validates the filter settings
func (f *BuildFilters) Validate() error {
if len(f.Except) > 0 && len(f.Only) > 0 {
return errors.New("Only one of '-except' or '-only' may be specified.")
}
return nil
}
// Builds returns the builds out of the given template that pass the
// configured filters.
func (f *BuildFilters) Builds(t *packer.Template, cf *packer.ComponentFinder) ([]packer.Build, error) {
buildNames := t.BuildNames()
builds := make([]packer.Build, 0, len(buildNames))
for _, buildName := range buildNames {
if len(f.Except) > 0 {
found := false
for _, except := range f.Except {
if buildName == except {
found = true
break
}
}
if found {
log.Printf("Skipping build '%s' because specified by -except.", buildName)
continue
}
}
if len(f.Only) > 0 {
found := false
for _, only := range f.Only {
if buildName == only {
found = true
break
}
}
if !found {
log.Printf("Skipping build '%s' because not specified by -only.", buildName)
continue
}
}
log.Printf("Creating build: %s", buildName)
build, err := t.Build(buildName, cf)
if err != nil {
return nil, fmt.Errorf("Failed to create build '%s': \n\n%s", buildName, err)
}
builds = append(builds, build)
}
return builds, nil
}
package command
import (
"testing"
)
func TestBuildFiltersValidate(t *testing.T) {
bf := new(BuildFilters)
err := bf.Validate()
if err != nil {
t.Fatalf("err: %s", err)
}
// Both set
bf.Except = make([]string, 1)
bf.Only = make([]string, 1)
err = bf.Validate()
if err == nil {
t.Fatal("should error")
}
// One set
bf.Except = make([]string, 1)
bf.Only = make([]string, 0)
err = bf.Validate()
if err != nil {
t.Fatalf("err: %s", err)
}
bf.Except = make([]string, 0)
bf.Only = make([]string, 1)
err = bf.Validate()
if err != nil {
t.Fatalf("err: %s", err)
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment