github.com/emate/packer@v0.8.1-0.20150625195101-fe0fde195dc6/command/meta.go (about) 1 package command 2 3 import ( 4 "bufio" 5 "flag" 6 "fmt" 7 "io" 8 9 "github.com/mitchellh/packer/helper/flag-kv" 10 "github.com/mitchellh/packer/helper/flag-slice" 11 "github.com/mitchellh/packer/packer" 12 "github.com/mitchellh/packer/template" 13 ) 14 15 // FlagSetFlags is an enum to define what flags are present in the 16 // default FlagSet returned by Meta.FlagSet 17 type FlagSetFlags uint 18 19 const ( 20 FlagSetNone FlagSetFlags = 0 21 FlagSetBuildFilter FlagSetFlags = 1 << iota 22 FlagSetVars 23 ) 24 25 // Meta contains the meta-options and functionality that nearly every 26 // Packer command inherits. 27 type Meta struct { 28 CoreConfig *packer.CoreConfig 29 Cache packer.Cache 30 Ui packer.Ui 31 32 // These are set by command-line flags 33 flagBuildExcept []string 34 flagBuildOnly []string 35 flagVars map[string]string 36 } 37 38 // Core returns the core for the given template given the configured 39 // CoreConfig and user variables on this Meta. 40 func (m *Meta) Core(tpl *template.Template) (*packer.Core, error) { 41 // Copy the config so we don't modify it 42 config := *m.CoreConfig 43 config.Template = tpl 44 config.Variables = m.flagVars 45 46 // Init the core 47 core, err := packer.NewCore(&config) 48 if err != nil { 49 return nil, fmt.Errorf("Error initializing core: %s", err) 50 } 51 52 return core, nil 53 } 54 55 // BuildNames returns the list of builds that are in the given core 56 // that we care about taking into account the only and except flags. 57 func (m *Meta) BuildNames(c *packer.Core) []string { 58 // TODO: test 59 60 // Filter the "only" 61 if len(m.flagBuildOnly) > 0 { 62 // Build a set of all the available names 63 nameSet := make(map[string]struct{}) 64 for _, n := range c.BuildNames() { 65 nameSet[n] = struct{}{} 66 } 67 68 // Build our result set which we pre-allocate some sane number 69 result := make([]string, 0, len(m.flagBuildOnly)) 70 for _, n := range m.flagBuildOnly { 71 if _, ok := nameSet[n]; ok { 72 result = append(result, n) 73 } 74 } 75 76 return result 77 } 78 79 // Filter the "except" 80 if len(m.flagBuildExcept) > 0 { 81 // Build a set of the things we don't want 82 nameSet := make(map[string]struct{}) 83 for _, n := range m.flagBuildExcept { 84 nameSet[n] = struct{}{} 85 } 86 87 // Build our result set which is the names of all builds except 88 // those in the given set. 89 names := c.BuildNames() 90 result := make([]string, 0, len(names)) 91 for _, n := range names { 92 if _, ok := nameSet[n]; !ok { 93 result = append(result, n) 94 } 95 } 96 return result 97 } 98 99 // We care about everything 100 return c.BuildNames() 101 } 102 103 // FlagSet returns a FlagSet with the common flags that every 104 // command implements. The exact behavior of FlagSet can be configured 105 // using the flags as the second parameter, for example to disable 106 // build settings on the commands that don't handle builds. 107 func (m *Meta) FlagSet(n string, fs FlagSetFlags) *flag.FlagSet { 108 f := flag.NewFlagSet(n, flag.ContinueOnError) 109 110 // FlagSetBuildFilter tells us to enable the settings for selecting 111 // builds we care about. 112 if fs&FlagSetBuildFilter != 0 { 113 f.Var((*sliceflag.StringFlag)(&m.flagBuildExcept), "except", "") 114 f.Var((*sliceflag.StringFlag)(&m.flagBuildOnly), "only", "") 115 } 116 117 // FlagSetVars tells us what variables to use 118 if fs&FlagSetVars != 0 { 119 f.Var((*kvflag.Flag)(&m.flagVars), "var", "") 120 f.Var((*kvflag.FlagJSON)(&m.flagVars), "var-file", "") 121 } 122 123 // Create an io.Writer that writes to our Ui properly for errors. 124 // This is kind of a hack, but it does the job. Basically: create 125 // a pipe, use a scanner to break it into lines, and output each line 126 // to the UI. Do this forever. 127 errR, errW := io.Pipe() 128 errScanner := bufio.NewScanner(errR) 129 go func() { 130 for errScanner.Scan() { 131 m.Ui.Error(errScanner.Text()) 132 } 133 }() 134 f.SetOutput(errW) 135 136 return f 137 } 138 139 // ValidateFlags should be called after parsing flags to validate the 140 // given flags 141 func (m *Meta) ValidateFlags() error { 142 // TODO 143 return nil 144 }