common/command: introduce this package for common cmmand stuff
This commit is contained in:
parent
180d5c8275
commit
a0033fba35
|
@ -4,6 +4,7 @@ import (
|
|||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
cmdcommon "github.com/mitchellh/packer/common/command"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
|
@ -22,15 +23,13 @@ func (Command) Help() string {
|
|||
func (c Command) Run(env packer.Environment, args []string) int {
|
||||
var cfgDebug bool
|
||||
var cfgForce bool
|
||||
var cfgExcept []string
|
||||
var cfgOnly []string
|
||||
buildFilters := new(cmdcommon.BuildFilters)
|
||||
|
||||
cmdFlags := flag.NewFlagSet("build", flag.ContinueOnError)
|
||||
cmdFlags.Usage = func() { env.Ui().Say(c.Help()) }
|
||||
cmdFlags.BoolVar(&cfgDebug, "debug", false, "debug mode for builds")
|
||||
cmdFlags.BoolVar(&cfgForce, "force", false, "force a build if artifacts exist")
|
||||
cmdFlags.Var((*stringSliceValue)(&cfgExcept), "except", "build all builds except these")
|
||||
cmdFlags.Var((*stringSliceValue)(&cfgOnly), "only", "only build the given builds by name")
|
||||
cmdcommon.BuildFilterFlags(cmdFlags, buildFilters)
|
||||
if err := cmdFlags.Parse(args); err != nil {
|
||||
return 1
|
||||
}
|
||||
|
@ -41,8 +40,9 @@ func (c Command) Run(env packer.Environment, args []string) int {
|
|||
return 1
|
||||
}
|
||||
|
||||
if len(cfgOnly) > 0 && len(cfgExcept) > 0 {
|
||||
env.Ui().Error("Only one of '-except' or '-only' may be specified.\n")
|
||||
if err := buildFilters.Validate(); err != nil {
|
||||
env.Ui().Error(err.Error())
|
||||
env.Ui().Error("")
|
||||
env.Ui().Error(c.Help())
|
||||
return 1
|
||||
}
|
||||
|
@ -72,47 +72,10 @@ func (c Command) Run(env packer.Environment, args []string) int {
|
|||
}
|
||||
|
||||
// Go through each builder and compile the builds that we care about
|
||||
buildNames := tpl.BuildNames()
|
||||
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 {
|
||||
env.Ui().Error(fmt.Sprintf("Failed to create build '%s': \n\n%s", buildName, err))
|
||||
return 1
|
||||
}
|
||||
|
||||
builds = append(builds, build)
|
||||
builds, err := buildFilters.Builds(tpl, components)
|
||||
if err != nil {
|
||||
env.Ui().Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
if cfgDebug {
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
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
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
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")
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
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
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
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)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
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
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
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)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue