github.com/jerryclinesmith/packer@v0.3.7/common/command/template.go (about) 1 package command 2 3 import ( 4 "errors" 5 "fmt" 6 jsonutil "github.com/mitchellh/packer/common/json" 7 "github.com/mitchellh/packer/packer" 8 "io/ioutil" 9 "log" 10 "os" 11 ) 12 13 // BuildOptions is a set of options related to builds that can be set 14 // from the command line. 15 type BuildOptions struct { 16 UserVarFiles []string 17 UserVars map[string]string 18 Except []string 19 Only []string 20 } 21 22 // Validate validates the options 23 func (f *BuildOptions) Validate() error { 24 if len(f.Except) > 0 && len(f.Only) > 0 { 25 return errors.New("Only one of '-except' or '-only' may be specified.") 26 } 27 28 if len(f.UserVarFiles) > 0 { 29 for _, path := range f.UserVarFiles { 30 if _, err := os.Stat(path); err != nil { 31 return fmt.Errorf("Cannot access: %s", path) 32 } 33 } 34 } 35 36 return nil 37 } 38 39 // AllUserVars returns the user variables, compiled from both the 40 // file paths and the vars on the command line. 41 func (f *BuildOptions) AllUserVars() (map[string]string, error) { 42 all := make(map[string]string) 43 44 // Copy in the variables from the files 45 for _, path := range f.UserVarFiles { 46 fileVars, err := readFileVars(path) 47 if err != nil { 48 return nil, err 49 } 50 51 for k, v := range fileVars { 52 all[k] = v 53 } 54 } 55 56 // Copy in the command-line vars 57 for k, v := range f.UserVars { 58 all[k] = v 59 } 60 61 return all, nil 62 } 63 64 // Builds returns the builds out of the given template that pass the 65 // configured options. 66 func (f *BuildOptions) Builds(t *packer.Template, cf *packer.ComponentFinder) ([]packer.Build, error) { 67 buildNames := t.BuildNames() 68 69 checks := make(map[string][]string) 70 checks["except"] = f.Except 71 checks["only"] = f.Only 72 for t, ns := range checks { 73 for _, n := range ns { 74 found := false 75 for _, actual := range buildNames { 76 if actual == n { 77 found = true 78 break 79 } 80 } 81 82 if !found { 83 return nil, fmt.Errorf( 84 "Unknown build in '%s' flag: %s", t, n) 85 } 86 } 87 } 88 89 builds := make([]packer.Build, 0, len(buildNames)) 90 for _, buildName := range buildNames { 91 if len(f.Except) > 0 { 92 found := false 93 for _, except := range f.Except { 94 if buildName == except { 95 found = true 96 break 97 } 98 } 99 100 if found { 101 log.Printf("Skipping build '%s' because specified by -except.", buildName) 102 continue 103 } 104 } 105 106 if len(f.Only) > 0 { 107 found := false 108 for _, only := range f.Only { 109 if buildName == only { 110 found = true 111 break 112 } 113 } 114 115 if !found { 116 log.Printf("Skipping build '%s' because not specified by -only.", buildName) 117 continue 118 } 119 } 120 121 log.Printf("Creating build: %s", buildName) 122 build, err := t.Build(buildName, cf) 123 if err != nil { 124 return nil, fmt.Errorf("Failed to create build '%s': \n\n%s", buildName, err) 125 } 126 127 builds = append(builds, build) 128 } 129 130 return builds, nil 131 } 132 133 func readFileVars(path string) (map[string]string, error) { 134 bytes, err := ioutil.ReadFile(path) 135 if err != nil { 136 return nil, err 137 } 138 139 vars := make(map[string]string) 140 err = jsonutil.Unmarshal(bytes, &vars) 141 if err != nil { 142 return nil, err 143 } 144 145 return vars, nil 146 }