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