From a3343c18485a267b50b3d030a161e631932013cc Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Wed, 29 Apr 2020 15:33:10 +0200 Subject: [PATCH 01/34] Delete zz_retrocompat.go it's dead/unused code I previously though I'd need it --- hcl2template/zz_retrocompat.go | 156 --------------------------------- 1 file changed, 156 deletions(-) delete mode 100644 hcl2template/zz_retrocompat.go diff --git a/hcl2template/zz_retrocompat.go b/hcl2template/zz_retrocompat.go deleted file mode 100644 index 2e67b8947..000000000 --- a/hcl2template/zz_retrocompat.go +++ /dev/null @@ -1,156 +0,0 @@ -package hcl2template - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "log" - "os" - "strings" -) - -func translateBuilder(path string) (string, error) { - - type ConfigV1 map[string]json.RawMessage - - type ConfigV1V2 struct { - Artifact map[string]map[string]json.RawMessage `json:"artifact"` - } - - type Type struct { - Name string `json:"name"` - Type string `json:"type"` - } - type PostProcessor struct { - Type string `json:"type"` - Except []string `json:"except"` - Only []string `json:"only"` - } - - b, err := ioutil.ReadFile(path) - if err != nil { - return "", err - } - c1 := ConfigV1{} - if err := json.Unmarshal(b, &c1); err != nil { - return "", err - } - c12 := ConfigV1V2{} - if err := json.Unmarshal(b, &c12); err != nil { - return "", err - } - - rawBuilder, found := c1["builders"] - if !found { - // no v1 builders - return path, nil - } - - var tn []Type - if err := json.Unmarshal([]byte(rawBuilder), &tn); err != nil { - return "", err - } - var rawbuilders []json.RawMessage - if err := json.Unmarshal([]byte(rawBuilder), &rawbuilders); err != nil { - return "", err - } - - var typePPs []PostProcessor - var rawPPs []json.RawMessage - if rawPP := c1["post-processors"]; len(rawPP) != 0 { - if err := json.Unmarshal([]byte(rawPP), &typePPs); err != nil { - return "", err - } - if err := json.Unmarshal([]byte(rawPP), &rawPPs); err != nil { - return "", err - } - } - - for n, tn := range tn { - builderName := tn.Type - if tn.Name != "" { - builderName = tn.Name - } - - if c12.Artifact[tn.Type] == nil { - c12.Artifact[tn.Type] = map[string]json.RawMessage{} - } - - name := tn.Name - if name == "" { - name = fmt.Sprintf("autotranslated-builder-%d", len(c12.Artifact[tn.Type])) - } - if _, exists := c12.Artifact[tn.Type][name]; exists { - return "", fmt.Errorf("%s-%s is defined in old and new config", tn.Type, name) - } - rawbuilder := rawbuilders[n] - rawbuilder = removeKey(rawbuilder, "name", "only", "type") - c12.Artifact[tn.Type][name] = rawbuilder - - for n, pp := range typePPs { - skip := false - for _, except := range pp.Except { - if except == builderName { - skip = true - break - } - } - for _, only := range pp.Only { - if only != builderName { - skip = true - break - } - } - if skip { - continue - } - if c12.Artifact[pp.Type] == nil { - c12.Artifact[pp.Type] = map[string]json.RawMessage{} - } - name := fmt.Sprintf("autotranslated-post-processor-%d", len(c12.Artifact[pp.Type])) - if _, exists := c12.Artifact[tn.Type][name]; exists { - return "", fmt.Errorf("%s-%s is defined in old and new config", tn.Type, name) - } - rawpp := rawPPs[n] - rawpp = rawpp[:len(rawpp)-1] - rawpp = append(rawpp, json.RawMessage(`,"source":"$artifacts.`+tn.Type+`.`+builderName+`"}`)...) - rawpp = removeKey(rawpp, "name", "only", "type") - c12.Artifact[pp.Type][name] = rawpp - - log.Printf("%s", rawpp) - } - - } - - path = strings.TrimSuffix(path, ".json") - path = strings.TrimSuffix(path, ".pk") - path = path + ".v2.pk.json" - - file, err := os.Create(path) - if err != nil { - return "", err - } - defer file.Close() - - enc := json.NewEncoder(file) - enc.SetIndent("", " ") - - return path, enc.Encode(c12) -} - -func removeKey(in json.RawMessage, keys ...string) json.RawMessage { - m := map[string]json.RawMessage{} - if err := json.Unmarshal(in, &m); err != nil { - panic(err) - } - - for _, key := range keys { - delete(m, key) - } - - b, err := json.Marshal(m) - if err != nil { - panic(err) - } - return b -} From 2df21496b36799b2dbcb96862acd50351030fc92 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Wed, 29 Apr 2020 16:15:42 +0200 Subject: [PATCH 02/34] hcl2template: let PackerConfig actually start a builder/provisioner/post-processor --- hcl2template/common_test.go | 3 ++- hcl2template/parser.go | 5 ++++- hcl2template/types.build.post-processor.go | 4 ++-- hcl2template/types.build.provisioners.go | 4 ++-- hcl2template/types.packer_config.go | 24 ++++++++++++++-------- hcl2template/types.source.go | 4 ++-- 6 files changed, 27 insertions(+), 17 deletions(-) diff --git a/hcl2template/common_test.go b/hcl2template/common_test.go index 752055fc4..d0a88a6ee 100644 --- a/hcl2template/common_test.go +++ b/hcl2template/common_test.go @@ -68,6 +68,7 @@ func testParse(t *testing.T, tests []parseTest) { } if diff := cmp.Diff(tt.parseWantCfg, gotCfg, cmpopts.IgnoreUnexported( + PackerConfig{}, cty.Value{}, cty.Type{}, Variable{}, @@ -115,7 +116,7 @@ func testParse(t *testing.T, tests []parseTest) { return } - gotBuilds, gotDiags := tt.parser.getBuilds(gotCfg, nil, nil) + gotBuilds, gotDiags := gotCfg.getBuilds(nil, nil) if tt.getBuildsWantDiags == (gotDiags == nil) { t.Fatalf("Parser.getBuilds() unexpected diagnostics. %s", gotDiags) } diff --git a/hcl2template/parser.go b/hcl2template/parser.go index d27ee74a0..f621f32dc 100644 --- a/hcl2template/parser.go +++ b/hcl2template/parser.go @@ -89,7 +89,10 @@ func (p *Parser) parse(filename string, varFiles []string, argVars map[string]st basedir = filepath.Dir(basedir) } cfg := &PackerConfig{ - Basedir: basedir, + Basedir: basedir, + builderSchemas: p.BuilderSchemas, + provisionersSchemas: p.ProvisionersSchemas, + postProcessorsSchemas: p.PostProcessorsSchemas, } // Decode variable blocks so that they are available later on. Here locals diff --git a/hcl2template/types.build.post-processor.go b/hcl2template/types.build.post-processor.go index 5c0c7004d..8add11514 100644 --- a/hcl2template/types.build.post-processor.go +++ b/hcl2template/types.build.post-processor.go @@ -49,11 +49,11 @@ func (p *Parser) decodePostProcessor(block *hcl.Block) (*PostProcessorBlock, hcl return postProcessor, diags } -func (p *Parser) startPostProcessor(source *SourceBlock, pp *PostProcessorBlock, ectx *hcl.EvalContext, generatedVars map[string]string) (packer.PostProcessor, hcl.Diagnostics) { +func (cfg *PackerConfig) startPostProcessor(source *SourceBlock, pp *PostProcessorBlock, ectx *hcl.EvalContext, generatedVars map[string]string) (packer.PostProcessor, hcl.Diagnostics) { // ProvisionerBlock represents a detected but unparsed provisioner var diags hcl.Diagnostics - postProcessor, err := p.PostProcessorsSchemas.Start(pp.PType) + postProcessor, err := cfg.postProcessorsSchemas.Start(pp.PType) if err != nil { diags = append(diags, &hcl.Diagnostic{ Summary: fmt.Sprintf("Failed loading %s", pp.PType), diff --git a/hcl2template/types.build.provisioners.go b/hcl2template/types.build.provisioners.go index 706f154a0..df10d77dc 100644 --- a/hcl2template/types.build.provisioners.go +++ b/hcl2template/types.build.provisioners.go @@ -77,10 +77,10 @@ func (p *Parser) decodeProvisioner(block *hcl.Block) (*ProvisionerBlock, hcl.Dia return provisioner, diags } -func (p *Parser) startProvisioner(source *SourceBlock, pb *ProvisionerBlock, ectx *hcl.EvalContext, generatedVars map[string]string) (packer.Provisioner, hcl.Diagnostics) { +func (cfg *PackerConfig) startProvisioner(source *SourceBlock, pb *ProvisionerBlock, ectx *hcl.EvalContext, generatedVars map[string]string) (packer.Provisioner, hcl.Diagnostics) { var diags hcl.Diagnostics - provisioner, err := p.ProvisionersSchemas.Start(pb.PType) + provisioner, err := cfg.provisionersSchemas.Start(pb.PType) if err != nil { diags = append(diags, &hcl.Diagnostic{ Summary: fmt.Sprintf("failed loading %s", pb.PType), diff --git a/hcl2template/types.packer_config.go b/hcl2template/types.packer_config.go index ead2d66b1..940defe92 100644 --- a/hcl2template/types.packer_config.go +++ b/hcl2template/types.packer_config.go @@ -31,6 +31,12 @@ type PackerConfig struct { // Builds is the list of Build blocks defined in the config files. Builds Builds + + builderSchemas packer.BuilderStore + + provisionersSchemas packer.ProvisionerStore + + postProcessorsSchemas packer.PostProcessorStore } type ValidationOptions struct { @@ -188,11 +194,11 @@ func (c *PackerConfig) evaluateLocalVariable(local *Local) hcl.Diagnostics { // getCoreBuildProvisioners takes a list of provisioner block, starts according // provisioners and sends parsed HCL2 over to it. -func (p *Parser) getCoreBuildProvisioners(source *SourceBlock, blocks []*ProvisionerBlock, ectx *hcl.EvalContext, generatedVars map[string]string) ([]packer.CoreBuildProvisioner, hcl.Diagnostics) { +func (cfg *PackerConfig) getCoreBuildProvisioners(source *SourceBlock, blocks []*ProvisionerBlock, ectx *hcl.EvalContext, generatedVars map[string]string) ([]packer.CoreBuildProvisioner, hcl.Diagnostics) { var diags hcl.Diagnostics res := []packer.CoreBuildProvisioner{} for _, pb := range blocks { - provisioner, moreDiags := p.startProvisioner(source, pb, ectx, generatedVars) + provisioner, moreDiags := cfg.startProvisioner(source, pb, ectx, generatedVars) diags = append(diags, moreDiags...) if moreDiags.HasErrors() { continue @@ -228,11 +234,11 @@ func (p *Parser) getCoreBuildProvisioners(source *SourceBlock, blocks []*Provisi // getCoreBuildProvisioners takes a list of post processor block, starts // according provisioners and sends parsed HCL2 over to it. -func (p *Parser) getCoreBuildPostProcessors(source *SourceBlock, blocks []*PostProcessorBlock, ectx *hcl.EvalContext, generatedVars map[string]string) ([]packer.CoreBuildPostProcessor, hcl.Diagnostics) { +func (cfg *PackerConfig) getCoreBuildPostProcessors(source *SourceBlock, blocks []*PostProcessorBlock, ectx *hcl.EvalContext, generatedVars map[string]string) ([]packer.CoreBuildPostProcessor, hcl.Diagnostics) { var diags hcl.Diagnostics res := []packer.CoreBuildPostProcessor{} for _, ppb := range blocks { - postProcessor, moreDiags := p.startPostProcessor(source, ppb, ectx, generatedVars) + postProcessor, moreDiags := cfg.startPostProcessor(source, ppb, ectx, generatedVars) diags = append(diags, moreDiags...) if moreDiags.HasErrors() { continue @@ -250,7 +256,7 @@ func (p *Parser) getCoreBuildPostProcessors(source *SourceBlock, blocks []*PostP // getBuilds will return a list of packer Build based on the HCL2 parsed build // blocks. All Builders, Provisioners and Post Processors will be started and // configured. -func (p *Parser) getBuilds(cfg *PackerConfig, onlyGlobs []glob.Glob, exceptGlobs []glob.Glob) ([]packer.Build, hcl.Diagnostics) { +func (cfg *PackerConfig) getBuilds(onlyGlobs []glob.Glob, exceptGlobs []glob.Glob) ([]packer.Build, hcl.Diagnostics) { res := []packer.Build{} var diags hcl.Diagnostics @@ -297,7 +303,7 @@ func (p *Parser) getBuilds(cfg *PackerConfig, onlyGlobs []glob.Glob, exceptGlobs } } - builder, moreDiags, generatedVars := p.startBuilder(src, cfg.EvalContext(nil)) + builder, moreDiags, generatedVars := cfg.startBuilder(src, cfg.EvalContext(nil)) diags = append(diags, moreDiags...) if moreDiags.HasErrors() { continue @@ -323,12 +329,12 @@ func (p *Parser) getBuilds(cfg *PackerConfig, onlyGlobs []glob.Glob, exceptGlobs } } - provisioners, moreDiags := p.getCoreBuildProvisioners(src, build.ProvisionerBlocks, cfg.EvalContext(variables), generatedPlaceholderMap) + provisioners, moreDiags := cfg.getCoreBuildProvisioners(src, build.ProvisionerBlocks, cfg.EvalContext(variables), generatedPlaceholderMap) diags = append(diags, moreDiags...) if moreDiags.HasErrors() { continue } - postProcessors, moreDiags := p.getCoreBuildPostProcessors(src, build.PostProcessors, cfg.EvalContext(variables), generatedPlaceholderMap) + postProcessors, moreDiags := cfg.getCoreBuildPostProcessors(src, build.PostProcessors, cfg.EvalContext(variables), generatedPlaceholderMap) pps := [][]packer.CoreBuildPostProcessor{} if len(postProcessors) > 0 { pps = [][]packer.CoreBuildPostProcessor{postProcessors} @@ -404,6 +410,6 @@ func (p *Parser) Parse(path string, varFiles []string, argVars map[string]string return nil, diags } - builds, moreDiags := p.getBuilds(cfg, onlyGlobs, exceptGlobs) + builds, moreDiags := cfg.getBuilds(onlyGlobs, exceptGlobs) return builds, append(diags, moreDiags...) } diff --git a/hcl2template/types.source.go b/hcl2template/types.source.go index f81dd768b..c44fb2687 100644 --- a/hcl2template/types.source.go +++ b/hcl2template/types.source.go @@ -38,10 +38,10 @@ func (p *Parser) decodeSource(block *hcl.Block) (*SourceBlock, hcl.Diagnostics) return source, diags } -func (p *Parser) startBuilder(source *SourceBlock, ectx *hcl.EvalContext) (packer.Builder, hcl.Diagnostics, []string) { +func (cfg *PackerConfig) startBuilder(source *SourceBlock, ectx *hcl.EvalContext) (packer.Builder, hcl.Diagnostics, []string) { var diags hcl.Diagnostics - builder, err := p.BuilderSchemas.Start(source.Type) + builder, err := cfg.builderSchemas.Start(source.Type) if err != nil { diags = append(diags, &hcl.Diagnostic{ Summary: "Failed to load " + sourceLabel + " type", From 5c2b8da63bebfe4561da59c3969589e155204232 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Wed, 29 Apr 2020 16:36:40 +0200 Subject: [PATCH 03/34] get builds from PackerConfig instead of parser to allow just reading the config and to not start anything. This will allow to later on run `validate --syntax-only`. Note that none of the builder/provisioner/post-processor config will be read but simply ignored. HCL2 still needs the body to be properly formatted and it should detect most syntax errors. --- command/build.go | 20 +++++++- hcl2template/common_test.go | 4 +- hcl2template/parser.go | 6 ++- hcl2template/types.packer_config.go | 75 +++++------------------------ hcl2template/utils.go | 21 ++++++++ 5 files changed, 59 insertions(+), 67 deletions(-) diff --git a/command/build.go b/command/build.go index 05392c063..6765b3128 100644 --- a/command/build.go +++ b/command/build.go @@ -104,7 +104,7 @@ func (c *BuildCommand) GetBuildsFromHCL(path string) ([]packer.Build, int) { PostProcessorsSchemas: c.CoreConfig.Components.PostProcessorStore, } - builds, diags := parser.Parse(path, c.varFiles, c.flagVars, c.CoreConfig.Only, c.CoreConfig.Except) + cfg, diags := parser.Parse(path, c.varFiles, c.flagVars) { // write HCL errors/diagnostics if any. b := bytes.NewBuffer(nil) @@ -122,6 +122,24 @@ func (c *BuildCommand) GetBuildsFromHCL(path string) ([]packer.Build, int) { ret = 1 } + builds, diags := cfg.GetBuilds(c.CoreConfig.Only, c.CoreConfig.Except) + { + // write HCL errors/diagnostics if any. + b := bytes.NewBuffer(nil) + err := hcl.NewDiagnosticTextWriter(b, parser.Files(), 80, false).WriteDiagnostics(diags) + if err != nil { + c.Ui.Error("could not write diagnostic: " + err.Error()) + return nil, 1 + } + if b.Len() != 0 { + c.Ui.Message(b.String()) + } + } + ret = 0 + if diags.HasErrors() { + ret = 1 + } + return builds, ret } diff --git a/hcl2template/common_test.go b/hcl2template/common_test.go index d0a88a6ee..b64295057 100644 --- a/hcl2template/common_test.go +++ b/hcl2template/common_test.go @@ -59,7 +59,7 @@ func testParse(t *testing.T, tests []parseTest) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - gotCfg, gotDiags := tt.parser.parse(tt.args.filename, tt.args.varFiles, tt.args.vars) + gotCfg, gotDiags := tt.parser.Parse(tt.args.filename, tt.args.varFiles, tt.args.vars) if tt.parseWantDiags == (gotDiags == nil) { t.Fatalf("Parser.parse() unexpected %q diagnostics.", gotDiags) } @@ -116,7 +116,7 @@ func testParse(t *testing.T, tests []parseTest) { return } - gotBuilds, gotDiags := gotCfg.getBuilds(nil, nil) + gotBuilds, gotDiags := gotCfg.GetBuilds(nil, nil) if tt.getBuildsWantDiags == (gotDiags == nil) { t.Fatalf("Parser.getBuilds() unexpected diagnostics. %s", gotDiags) } diff --git a/hcl2template/parser.go b/hcl2template/parser.go index f621f32dc..169d336f3 100644 --- a/hcl2template/parser.go +++ b/hcl2template/parser.go @@ -52,7 +52,11 @@ const ( hcl2VarJsonFileExt = ".auto.pkrvars.json" ) -func (p *Parser) parse(filename string, varFiles []string, argVars map[string]string) (*PackerConfig, hcl.Diagnostics) { +// Parse will Parse HCL file(s) in path. Path can be a folder or a file. +// +// Parse will first Parse variables and then the rest; so that interpolation +// can happen. +func (p *Parser) Parse(filename string, varFiles []string, argVars map[string]string) (*PackerConfig, hcl.Diagnostics) { var files []*hcl.File var diags hcl.Diagnostics diff --git a/hcl2template/types.packer_config.go b/hcl2template/types.packer_config.go index 940defe92..86b3702cc 100644 --- a/hcl2template/types.packer_config.go +++ b/hcl2template/types.packer_config.go @@ -7,8 +7,6 @@ import ( "github.com/hashicorp/packer/helper/common" "github.com/hashicorp/packer/packer" "github.com/zclconf/go-cty/cty" - - "github.com/gobwas/glob" ) // PackerConfig represents a loaded Packer HCL config. It will contain @@ -253,10 +251,10 @@ func (cfg *PackerConfig) getCoreBuildPostProcessors(source *SourceBlock, blocks return res, diags } -// getBuilds will return a list of packer Build based on the HCL2 parsed build +// GetBuilds returns a list of packer Build based on the HCL2 parsed build // blocks. All Builders, Provisioners and Post Processors will be started and // configured. -func (cfg *PackerConfig) getBuilds(onlyGlobs []glob.Glob, exceptGlobs []glob.Glob) ([]packer.Build, hcl.Diagnostics) { +func (cfg *PackerConfig) GetBuilds(only, except []string) ([]packer.Build, hcl.Diagnostics) { res := []packer.Build{} var diags hcl.Diagnostics @@ -276,7 +274,11 @@ func (cfg *PackerConfig) getBuilds(onlyGlobs []glob.Glob, exceptGlobs []glob.Glo buildName := fmt.Sprintf("%s.%s", src.Type, src.Name) // -only - if len(onlyGlobs) > 0 { + if len(only) > 0 { + onlyGlobs, diags := convertFilterOption(only, "only") + if diags.HasErrors() { + return nil, diags + } include := false for _, onlyGlob := range onlyGlobs { if onlyGlob.Match(buildName) { @@ -290,7 +292,11 @@ func (cfg *PackerConfig) getBuilds(onlyGlobs []glob.Glob, exceptGlobs []glob.Glo } // -except - if len(exceptGlobs) > 0 { + if len(except) > 0 { + exceptGlobs, diags := convertFilterOption(except, "except") + if diags.HasErrors() { + return nil, diags + } exclude := false for _, exceptGlob := range exceptGlobs { if exceptGlob.Match(buildName) { @@ -356,60 +362,3 @@ func (cfg *PackerConfig) getBuilds(onlyGlobs []glob.Glob, exceptGlobs []glob.Glo } return res, diags } - -// Convert -only and -except globs to glob.Glob instances. -func convertFilterOption(patterns []string, optionName string) ([]glob.Glob, hcl.Diagnostics) { - var globs []glob.Glob - var diags hcl.Diagnostics - - for _, pattern := range patterns { - g, err := glob.Compile(pattern) - if err != nil { - diags = append(diags, &hcl.Diagnostic{ - Summary: fmt.Sprintf("Invalid -%s pattern %s: %s", optionName, pattern, err), - Severity: hcl.DiagError, - }) - } - globs = append(globs, g) - } - - return globs, diags -} - -// Parse will parse HCL file(s) in path. Path can be a folder or a file. -// -// Parse will first parse variables and then the rest; so that interpolation -// can happen. -// -// For each build block a packer.Build will be started, and for each builder, -// all provisioners and post-processors will be started. -// -// Parse then return a slice of packer.Builds; which are what packer core uses -// to run builds. -func (p *Parser) Parse(path string, varFiles []string, argVars map[string]string, onlyBuilds []string, exceptBuilds []string) ([]packer.Build, hcl.Diagnostics) { - var onlyGlobs []glob.Glob - if len(onlyBuilds) > 0 { - og, diags := convertFilterOption(onlyBuilds, "only") - if diags.HasErrors() { - return nil, diags - } - onlyGlobs = og - } - - var exceptGlobs []glob.Glob - if len(exceptBuilds) > 0 { - eg, diags := convertFilterOption(exceptBuilds, "except") - if diags.HasErrors() { - return nil, diags - } - exceptGlobs = eg - } - - cfg, diags := p.parse(path, varFiles, argVars) - if diags.HasErrors() { - return nil, diags - } - - builds, moreDiags := cfg.getBuilds(onlyGlobs, exceptGlobs) - return builds, append(diags, moreDiags...) -} diff --git a/hcl2template/utils.go b/hcl2template/utils.go index bbb5d697b..06aa60864 100644 --- a/hcl2template/utils.go +++ b/hcl2template/utils.go @@ -1,11 +1,13 @@ package hcl2template import ( + "fmt" "io/ioutil" "os" "path/filepath" "strings" + "github.com/gobwas/glob" "github.com/hashicorp/hcl/v2" ) @@ -88,3 +90,22 @@ func GetHCL2Files(filename, hclSuffix, jsonSuffix string) (hclFiles, jsonFiles [ return hclFiles, jsonFiles, diags } + +// Convert -only and -except globs to glob.Glob instances. +func convertFilterOption(patterns []string, optionName string) ([]glob.Glob, hcl.Diagnostics) { + var globs []glob.Glob + var diags hcl.Diagnostics + + for _, pattern := range patterns { + g, err := glob.Compile(pattern) + if err != nil { + diags = append(diags, &hcl.Diagnostic{ + Summary: fmt.Sprintf("Invalid -%s pattern %s: %s", optionName, pattern, err), + Severity: hcl.DiagError, + }) + } + globs = append(globs, g) + } + + return globs, diags +} From 526d04053434565eb6ce22e9833e3ab2a3a845a9 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Thu, 30 Apr 2020 11:51:24 +0200 Subject: [PATCH 04/34] document Parser.Parse better --- hcl2template/parser.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hcl2template/parser.go b/hcl2template/parser.go index 169d336f3..59efd69c0 100644 --- a/hcl2template/parser.go +++ b/hcl2template/parser.go @@ -52,10 +52,14 @@ const ( hcl2VarJsonFileExt = ".auto.pkrvars.json" ) -// Parse will Parse HCL file(s) in path. Path can be a folder or a file. +// Parse will Parse all HCL files in filename. Path can be a folder or a file. // // Parse will first Parse variables and then the rest; so that interpolation // can happen. +// +// Parse returns a PackerConfig that contains configuration layout of a packer +// build; sources(builders)/provisioners/posts-processors will not be started +// and their contents wont be verified; Most syntax errors will cause an error. func (p *Parser) Parse(filename string, varFiles []string, argVars map[string]string) (*PackerConfig, hcl.Diagnostics) { var files []*hcl.File From 7aaee629703aa79401dc8d8794c85cfe07aeb458 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Thu, 30 Apr 2020 12:05:20 +0200 Subject: [PATCH 05/34] command/build: don't reset error code in case an error hapened --- command/build.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/command/build.go b/command/build.go index 6765b3128..9017ae471 100644 --- a/command/build.go +++ b/command/build.go @@ -120,6 +120,8 @@ func (c *BuildCommand) GetBuildsFromHCL(path string) ([]packer.Build, int) { ret := 0 if diags.HasErrors() { ret = 1 + // TODO(azr): Should we stop here or partially build ? Other builds could be + // working; should this be an option ? } builds, diags := cfg.GetBuilds(c.CoreConfig.Only, c.CoreConfig.Except) @@ -135,7 +137,6 @@ func (c *BuildCommand) GetBuildsFromHCL(path string) ([]packer.Build, int) { c.Ui.Message(b.String()) } } - ret = 0 if diags.HasErrors() { ret = 1 } From c71a79218623edb453a72a15750ce005dd9bae06 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Thu, 30 Apr 2020 16:36:01 +0200 Subject: [PATCH 06/34] simplify/refactor core for build & validate --- command/build.go | 115 ++++++++++++++++++++++++++------------------ command/meta.go | 48 ------------------ command/validate.go | 2 +- packer/core.go | 15 +++++- 4 files changed, 83 insertions(+), 97 deletions(-) diff --git a/command/build.go b/command/build.go index 9017ae471..d815f6f26 100644 --- a/command/build.go +++ b/command/build.go @@ -96,25 +96,25 @@ func (c *BuildCommand) ParseArgs(args []string) (Config, int) { return cfg, 0 } -func (c *BuildCommand) GetBuildsFromHCL(path string) ([]packer.Build, int) { +func (m *Meta) GetConfigFromHCL(path string) (BuildStarter, int) { parser := &hcl2template.Parser{ Parser: hclparse.NewParser(), - BuilderSchemas: c.CoreConfig.Components.BuilderStore, - ProvisionersSchemas: c.CoreConfig.Components.ProvisionerStore, - PostProcessorsSchemas: c.CoreConfig.Components.PostProcessorStore, + BuilderSchemas: m.CoreConfig.Components.BuilderStore, + ProvisionersSchemas: m.CoreConfig.Components.ProvisionerStore, + PostProcessorsSchemas: m.CoreConfig.Components.PostProcessorStore, } - cfg, diags := parser.Parse(path, c.varFiles, c.flagVars) + cfg, diags := parser.Parse(path, m.varFiles, m.flagVars) { // write HCL errors/diagnostics if any. b := bytes.NewBuffer(nil) err := hcl.NewDiagnosticTextWriter(b, parser.Files(), 80, false).WriteDiagnostics(diags) if err != nil { - c.Ui.Error("could not write diagnostic: " + err.Error()) + m.Ui.Error("could not write diagnostic: " + err.Error()) return nil, 1 } if b.Len() != 0 { - c.Ui.Message(b.String()) + m.Ui.Message(b.String()) } } ret := 0 @@ -124,75 +124,88 @@ func (c *BuildCommand) GetBuildsFromHCL(path string) ([]packer.Build, int) { // working; should this be an option ? } - builds, diags := cfg.GetBuilds(c.CoreConfig.Only, c.CoreConfig.Except) - { - // write HCL errors/diagnostics if any. - b := bytes.NewBuffer(nil) - err := hcl.NewDiagnosticTextWriter(b, parser.Files(), 80, false).WriteDiagnostics(diags) - if err != nil { - c.Ui.Error("could not write diagnostic: " + err.Error()) - return nil, 1 + return func(opts buildStarterOptions) ([]packer.Build, int) { + builds, diags := cfg.GetBuilds(opts.only, opts.except) + { + // write HCL errors/diagnostics if any. + b := bytes.NewBuffer(nil) + err := hcl.NewDiagnosticTextWriter(b, parser.Files(), 80, false).WriteDiagnostics(diags) + if err != nil { + m.Ui.Error("could not write diagnostic: " + err.Error()) + return nil, 1 + } + if b.Len() != 0 { + m.Ui.Message(b.String()) + } } - if b.Len() != 0 { - c.Ui.Message(b.String()) + if diags.HasErrors() { + ret = 1 } - } - if diags.HasErrors() { - ret = 1 - } - return builds, ret + return builds, ret + }, ret } -func (c *BuildCommand) GetBuilds(path string) ([]packer.Build, int) { +// GetBuilds will start all packer plugins ( builder, provisioner and +// post-processor ) referenced in the config. These plugins will be in a +// waiting to execute mode. Upon error a non nil error will be returned. +type BuildStarter func(buildStarterOptions) ([]packer.Build, int) +type buildStarterOptions struct { + except, only []string +} + +func (m *Meta) GetConfig(path string) (BuildStarter, int) { isHCLLoaded, err := isHCLLoaded(path) if path != "-" && err != nil { - c.Ui.Error(fmt.Sprintf("could not tell whether %s is hcl enabled: %s", path, err)) + m.Ui.Error(fmt.Sprintf("could not tell whether %s is hcl enabled: %s", path, err)) return nil, 1 } if isHCLLoaded { - return c.GetBuildsFromHCL(path) + return m.GetConfigFromHCL(path) } - // TODO: uncomment in v1.5.1 once we've polished HCL a bit more. + // TODO: uncomment once we've polished HCL a bit more. // c.Ui.Say(`Legacy JSON Configuration Will Be Used. // The template will be parsed in the legacy configuration style. This style // will continue to work but users are encouraged to move to the new style. // See: https://packer.io/guides/hcl // `) + return m.GetConfigFromJSON(path) +} +func (m *Meta) GetConfigFromJSON(path string) (BuildStarter, int) { // Parse the template - var tpl *template.Template - tpl, err = template.ParseFile(path) + tpl, err := template.ParseFile(path) if err != nil { - c.Ui.Error(fmt.Sprintf("Failed to parse template: %s", err)) + m.Ui.Error(fmt.Sprintf("Failed to parse template: %s", err)) return nil, 1 } // Get the core - core, err := c.Meta.Core(tpl) + core, err := m.Core(tpl) if err != nil { - c.Ui.Error(err.Error()) + m.Ui.Error(err.Error()) return nil, 1 } + return func(opts buildStarterOptions) ([]packer.Build, int) { + ret := 0 + buildNames := core.BuildNames(opts.only, opts.except) + builds := make([]packer.Build, 0, len(buildNames)) + for _, n := range buildNames { + b, err := core.Build(n) + if err != nil { + m.Ui.Error(fmt.Sprintf( + "Failed to initialize build '%s': %s", + n, err)) + ret = 1 + continue + } - ret := 0 - buildNames := c.Meta.BuildNames(core) - builds := make([]packer.Build, 0, len(buildNames)) - for _, n := range buildNames { - b, err := core.Build(n) - if err != nil { - c.Ui.Error(fmt.Sprintf( - "Failed to initialize build '%s': %s", - n, err)) - ret = 1 - continue + builds = append(builds, b) } - - builds = append(builds, b) - } - return builds, ret + return builds, ret + }, 0 } func (c *BuildCommand) RunContext(buildCtx context.Context, args []string) int { @@ -201,7 +214,15 @@ func (c *BuildCommand) RunContext(buildCtx context.Context, args []string) int { return ret } - builds, ret := c.GetBuilds(cfg.Path) + packerStarter, ret := c.GetConfig(cfg.Path) + if ret != 0 { + return ret + } + + builds, ret := packerStarter(buildStarterOptions{ + except: c.CoreConfig.Except, + only: c.CoreConfig.Only, + }) if cfg.Debug { c.Ui.Say("Debug mode enabled. Builds will not be parallelized.") diff --git a/command/meta.go b/command/meta.go index 58d9a9359..a42a463f0 100644 --- a/command/meta.go +++ b/command/meta.go @@ -73,54 +73,6 @@ func (m *Meta) Core(tpl *template.Template) (*packer.Core, error) { return core, nil } -// BuildNames returns the list of builds that are in the given core -// that we care about taking into account the only and except flags. -func (m *Meta) BuildNames(c *packer.Core) []string { - // TODO: test - - // Filter the "only" - if len(m.CoreConfig.Only) > 0 { - // Build a set of all the available names - nameSet := make(map[string]struct{}) - for _, n := range c.BuildNames() { - nameSet[n] = struct{}{} - } - - // Build our result set which we pre-allocate some sane number - result := make([]string, 0, len(m.CoreConfig.Only)) - for _, n := range m.CoreConfig.Only { - if _, ok := nameSet[n]; ok { - result = append(result, n) - } - } - - return result - } - - // Filter the "except" - if len(m.CoreConfig.Except) > 0 { - // Build a set of the things we don't want - nameSet := make(map[string]struct{}) - for _, n := range m.CoreConfig.Except { - nameSet[n] = struct{}{} - } - - // Build our result set which is the names of all builds except - // those in the given set. - names := c.BuildNames() - result := make([]string, 0, len(names)) - for _, n := range names { - if _, ok := nameSet[n]; !ok { - result = append(result, n) - } - } - return result - } - - // We care about everything - return c.BuildNames() -} - // FlagSet returns a FlagSet with the common flags that every // command implements. The exact behavior of FlagSet can be configured // using the flags as the second parameter, for example to disable diff --git a/command/validate.go b/command/validate.go index a84eb6637..8f08b44bc 100644 --- a/command/validate.go +++ b/command/validate.go @@ -57,7 +57,7 @@ func (c *ValidateCommand) Run(args []string) int { warnings := make(map[string][]string) // Get the builds we care about - buildNames := c.Meta.BuildNames(core) + buildNames := core.BuildNames(c.CoreConfig.Only, c.CoreConfig.Except) builds := make([]packer.Build, 0, len(buildNames)) for _, n := range buildNames { b, err := core.Build(n) diff --git a/packer/core.go b/packer/core.go index 05cb720ff..04be127c3 100644 --- a/packer/core.go +++ b/packer/core.go @@ -126,9 +126,22 @@ func NewCore(c *CoreConfig) (*Core, error) { } // BuildNames returns the builds that are available in this configured core. -func (c *Core) BuildNames() []string { +func (c *Core) BuildNames(only, except []string) []string { + + sort.Strings(only) + sort.Strings(except) + r := make([]string, 0, len(c.builds)) for n := range c.builds { + onlyPos := sort.SearchStrings(only, n) + foundInOnly := onlyPos < len(only) && only[onlyPos] == n + if len(only) > 0 && !foundInOnly { + continue + } + + if pos := sort.SearchStrings(except, n); pos < len(except) && except[pos] == n { + continue + } r = append(r, n) } sort.Strings(r) From 2c556ed8c033ac4011d615b7100f6f4c3612a9c7 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Thu, 30 Apr 2020 16:37:23 +0200 Subject: [PATCH 07/34] remove clarified comment --- command/build.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/command/build.go b/command/build.go index d815f6f26..8aa7a3ee3 100644 --- a/command/build.go +++ b/command/build.go @@ -120,8 +120,6 @@ func (m *Meta) GetConfigFromHCL(path string) (BuildStarter, int) { ret := 0 if diags.HasErrors() { ret = 1 - // TODO(azr): Should we stop here or partially build ? Other builds could be - // working; should this be an option ? } return func(opts buildStarterOptions) ([]packer.Build, int) { From 4047113746572d8f7182f78a2938982997445568 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Thu, 30 Apr 2020 16:40:16 +0200 Subject: [PATCH 08/34] Update build.go --- command/build.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/command/build.go b/command/build.go index 8aa7a3ee3..7a835707f 100644 --- a/command/build.go +++ b/command/build.go @@ -182,9 +182,10 @@ func (m *Meta) GetConfigFromJSON(path string) (BuildStarter, int) { // Get the core core, err := m.Core(tpl) + ret := 0 if err != nil { m.Ui.Error(err.Error()) - return nil, 1 + ret = 1 } return func(opts buildStarterOptions) ([]packer.Build, int) { ret := 0 @@ -203,7 +204,7 @@ func (m *Meta) GetConfigFromJSON(path string) (BuildStarter, int) { builds = append(builds, b) } return builds, ret - }, 0 + }, ret } func (c *BuildCommand) RunContext(buildCtx context.Context, args []string) int { From e50eb341bf5acc2812697ee7a77cf2f2cf0f566e Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Thu, 30 Apr 2020 16:40:58 +0200 Subject: [PATCH 09/34] Update core_test.go --- packer/core_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packer/core_test.go b/packer/core_test.go index 90b8409cb..1f9cfb816 100644 --- a/packer/core_test.go +++ b/packer/core_test.go @@ -45,7 +45,7 @@ func TestCoreBuildNames(t *testing.T) { t.Fatalf("err: %s\n\n%s", tc.File, err) } - names := core.BuildNames() + names := core.BuildNames(nil, nil) if !reflect.DeepEqual(names, tc.Result) { t.Fatalf("err: %s\n\n%#v", tc.File, names) } From a5ab87ca44bd8660831eef54d1e4c935c5174902 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Thu, 7 May 2020 17:52:49 +0200 Subject: [PATCH 10/34] add scaffolding for the new packer command layout --- command/cli.go | 128 +++++++++++++++++++++++++++++++++++++++++++++ command/command.go | 13 +++++ 2 files changed, 141 insertions(+) create mode 100644 command/cli.go create mode 100644 command/command.go diff --git a/command/cli.go b/command/cli.go new file mode 100644 index 000000000..7b81998a9 --- /dev/null +++ b/command/cli.go @@ -0,0 +1,128 @@ +package command + +import ( + "flag" + "math" + + "github.com/hashicorp/packer/helper/enumflag" + kvflag "github.com/hashicorp/packer/helper/flag-kv" + sliceflag "github.com/hashicorp/packer/helper/flag-slice" +) + +// NewMetaArgs parses cli args and put possible values +func (ma *MetaArgs) AddFlagSets(fs *flag.FlagSet) { + fs.Var((*sliceflag.StringFlag)(&ma.Only), "only", "") + fs.Var((*sliceflag.StringFlag)(&ma.Except), "except", "") + fs.Var((*kvflag.Flag)(&ma.Vars), "var", "") + fs.Var((*kvflag.StringSlice)(&ma.VarFiles), "var-file", "") +} + +// MetaArgs defines commonalities between all comands +type MetaArgs struct { + Args []string + Only, Except []string + Vars map[string]string + VarFiles []string +} + +func (ba *BuildArgs) AddFlagSets(flags *flag.FlagSet) { + flags.BoolVar(&ba.Color, "color", true, "") + flags.BoolVar(&ba.Debug, "debug", false, "") + flags.BoolVar(&ba.Force, "force", false, "") + flags.BoolVar(&ba.TimestampUi, "timestamp-ui", false, "") + flags.BoolVar(&ba.MachineReadable, "machine-readable", false, "") + + flags.Int64Var(&ba.ParallelBuilds, "parallel-builds", 0, "") + + flagOnError := enumflag.New(&ba.OnError, "cleanup", "abort", "ask") + flags.Var(flagOnError, "on-error", "") + + ba.MetaArgs.AddFlagSets(flags) +} + +func (ba *BuildArgs) ParseArgvs(args []string) int { + flags := flag.NewFlagSet("build", flag.ContinueOnError) + ba.AddFlagSets(flags) + err := flags.Parse(args) + if err != nil { + return 1 + } + + if ba.ParallelBuilds < 1 { + ba.ParallelBuilds = math.MaxInt64 + } + + ba.Args = flags.Args() + return 0 +} + +// BuildArgs represents a parsed cli line for a `packer build` +type BuildArgs struct { + MetaArgs + Color, Debug, Force, TimestampUi, MachineReadable bool + ParallelBuilds int64 + OnError string +} + +func (ca *ConsoleArgs) ParseArgvs(args []string) int { + flags := flag.NewFlagSet("console", flag.ContinueOnError) + ca.AddFlagSets(flags) + err := flags.Parse(args) + if err != nil { + return 1 + } + + ca.Args = flags.Args() + return 0 +} + +// ConsoleArgs represents a parsed cli line for a `packer console` +type ConsoleArgs struct{ MetaArgs } + +func (fa *FixArgs) AddFlagSets(flags *flag.FlagSet) { + flags.BoolVar(&fa.Validate, "validate", true, "") + + fa.MetaArgs.AddFlagSets(flags) +} + +func (fa *FixArgs) ParseArgvs(args []string) int { + flags := flag.NewFlagSet("build", flag.ContinueOnError) + fa.AddFlagSets(flags) + err := flags.Parse(args) + if err != nil { + return 1 + } + + fa.Args = flags.Args() + return 0 +} + +// FixArgs represents a parsed cli line for a `packer fix` +type FixArgs struct { + MetaArgs + Validate bool +} + +func (va *ValidateArgs) AddFlagSets(flags *flag.FlagSet) { + flags.BoolVar(&va.SyntaxOnly, "syntax-only", true, "") + + va.MetaArgs.AddFlagSets(flags) +} + +func (va *ValidateArgs) ParseArgvs(args []string) int { + flags := flag.NewFlagSet("build", flag.ContinueOnError) + va.AddFlagSets(flags) + err := flags.Parse(args) + if err != nil { + return 1 + } + + va.Args = flags.Args() + return 0 +} + +// ValidateArgs represents a parsed cli line for a `packer validate` +type ValidateArgs struct { + MetaArgs + SyntaxOnly bool +} diff --git a/command/command.go b/command/command.go new file mode 100644 index 000000000..e71e3ddaa --- /dev/null +++ b/command/command.go @@ -0,0 +1,13 @@ +package command + +import "context" + +// PackerInterface is the interface to use packer; it represents ways users can +// use Packer. A call returns a int that will be the exit code of Packer, +// everything else is up to the implementer. +type PackerInterface interface { + Build(ctx context.Context, args BuildArgs) int + Console(ctx context.Context, args ConsoleArgs) int + Fix(ctx context.Context, args FixArgs) int + Validate(ctx context.Context, args ValidateArgs) int +} From 5290beb23edfe817397901bac835d86a7a2f9599 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Fri, 8 May 2020 11:59:10 +0200 Subject: [PATCH 11/34] Update cli.go --- command/cli.go | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/command/cli.go b/command/cli.go index 7b81998a9..02ec5973f 100644 --- a/command/cli.go +++ b/command/cli.go @@ -2,11 +2,14 @@ package command import ( "flag" + "fmt" "math" + "strings" "github.com/hashicorp/packer/helper/enumflag" kvflag "github.com/hashicorp/packer/helper/flag-kv" sliceflag "github.com/hashicorp/packer/helper/flag-slice" + "github.com/hashicorp/packer/packer" ) // NewMetaArgs parses cli args and put possible values @@ -17,12 +20,38 @@ func (ma *MetaArgs) AddFlagSets(fs *flag.FlagSet) { fs.Var((*kvflag.StringSlice)(&ma.VarFiles), "var-file", "") } +// ConfigType tells what type of config we should use, it can return values +// like "hcl" or "json". +// Make sure Args was correctly set before. +func (ma *MetaArgs) ConfigType() (string, error) { + switch len(ma.Args) { + // TODO(azr): in the future, I want to allow passing multiple arguments to + // merge HCL confs together; but this will probably need an RFC first. + // TODO(azr): To allow piping HCL2 confs (when args is "-"), we probably + // will need to add a setting that says "this is an HCL config". + case 1: + name := ma.Args[0] + if strings.HasSuffix(name, ".pkr.hcl") || + strings.HasSuffix(name, ".pkr.json") { + return "hcl", nil + } + isDir, err := isDir(name) + if isDir { + return "hcl", err + } + return "json", err + default: + return "", fmt.Errorf("packer only takes on argument: %q", ma.Args) + } +} + // MetaArgs defines commonalities between all comands type MetaArgs struct { Args []string Only, Except []string Vars map[string]string VarFiles []string + Ui packer.Ui } func (ba *BuildArgs) AddFlagSets(flags *flag.FlagSet) { @@ -42,6 +71,7 @@ func (ba *BuildArgs) AddFlagSets(flags *flag.FlagSet) { func (ba *BuildArgs) ParseArgvs(args []string) int { flags := flag.NewFlagSet("build", flag.ContinueOnError) + flags.Usage = func() { ba.Ui.Say(ba.Help()) } ba.AddFlagSets(flags) err := flags.Parse(args) if err != nil { @@ -66,6 +96,7 @@ type BuildArgs struct { func (ca *ConsoleArgs) ParseArgvs(args []string) int { flags := flag.NewFlagSet("console", flag.ContinueOnError) + flags.Usage = func() { ca.Ui.Say(ca.Help()) } ca.AddFlagSets(flags) err := flags.Parse(args) if err != nil { @@ -86,7 +117,8 @@ func (fa *FixArgs) AddFlagSets(flags *flag.FlagSet) { } func (fa *FixArgs) ParseArgvs(args []string) int { - flags := flag.NewFlagSet("build", flag.ContinueOnError) + flags := flag.NewFlagSet("fix", flag.ContinueOnError) + flags.Usage = func() { fa.Ui.Say(fa.Help()) } fa.AddFlagSets(flags) err := flags.Parse(args) if err != nil { @@ -110,7 +142,8 @@ func (va *ValidateArgs) AddFlagSets(flags *flag.FlagSet) { } func (va *ValidateArgs) ParseArgvs(args []string) int { - flags := flag.NewFlagSet("build", flag.ContinueOnError) + flags := flag.NewFlagSet("validate", flag.ContinueOnError) + flags.Usage = func() { va.Ui.Say(va.Help()) } va.AddFlagSets(flags) err := flags.Parse(args) if err != nil { From 532a69c968bdf96d7cfbb4a50af79a0b42b4514e Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Fri, 8 May 2020 12:00:06 +0200 Subject: [PATCH 12/34] Update command.go --- command/command.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/command/command.go b/command/command.go index e71e3ddaa..3a11c4d7b 100644 --- a/command/command.go +++ b/command/command.go @@ -6,8 +6,8 @@ import "context" // use Packer. A call returns a int that will be the exit code of Packer, // everything else is up to the implementer. type PackerInterface interface { - Build(ctx context.Context, args BuildArgs) int - Console(ctx context.Context, args ConsoleArgs) int - Fix(ctx context.Context, args FixArgs) int - Validate(ctx context.Context, args ValidateArgs) int + Build(ctx context.Context, args *BuildArgs) int + Console(ctx context.Context, args *ConsoleArgs) int + Fix(ctx context.Context, args *FixArgs) int + Validate(ctx context.Context, args *ValidateArgs) int } From 2f63e4e79d2b1cd4ef7890812c8a477d0ddb2d6f Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Fri, 8 May 2020 12:05:14 +0200 Subject: [PATCH 13/34] refactor term interrupts & have RunContext take a conf struct now --- command/build.go | 40 +++++++++------------------------------- command/cli.go | 8 ++++---- command/signal.go | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 35 deletions(-) create mode 100644 command/signal.go diff --git a/command/build.go b/command/build.go index 7a835707f..40130ac52 100644 --- a/command/build.go +++ b/command/build.go @@ -6,12 +6,9 @@ import ( "fmt" "log" "math" - "os" - "os/signal" "strconv" "strings" "sync" - "syscall" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclparse" @@ -29,30 +26,15 @@ type BuildCommand struct { } func (c *BuildCommand) Run(args []string) int { - buildCtx, cancelBuildCtx := context.WithCancel(context.Background()) - // Handle interrupts for this build - sigCh := make(chan os.Signal, 1) - signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM) - defer func() { - cancelBuildCtx() - signal.Stop(sigCh) - close(sigCh) - }() - go func() { - select { - case sig := <-sigCh: - if sig == nil { - // context got cancelled and this closed chan probably - // triggered first - return - } - c.Ui.Error(fmt.Sprintf("Cancelling build after receiving %s", sig)) - cancelBuildCtx() - case <-buildCtx.Done(): - } - }() + buildCtx, cleanup := handleTermInterrupt(c.Ui) + defer cleanup() - return c.RunContext(buildCtx, args) + cfg, ret := c.ParseArgs(args) + if ret != 0 { + return ret + } + + return c.RunContext(buildCtx, cfg) } // Config is the command-configuration parsed from the command line. @@ -207,11 +189,7 @@ func (m *Meta) GetConfigFromJSON(path string) (BuildStarter, int) { }, ret } -func (c *BuildCommand) RunContext(buildCtx context.Context, args []string) int { - cfg, ret := c.ParseArgs(args) - if ret != 0 { - return ret - } +func (c *BuildCommand) RunContext(buildCtx context.Context, cfg Config) int { packerStarter, ret := c.GetConfig(cfg.Path) if ret != 0 { diff --git a/command/cli.go b/command/cli.go index 02ec5973f..e1af60a22 100644 --- a/command/cli.go +++ b/command/cli.go @@ -71,7 +71,7 @@ func (ba *BuildArgs) AddFlagSets(flags *flag.FlagSet) { func (ba *BuildArgs) ParseArgvs(args []string) int { flags := flag.NewFlagSet("build", flag.ContinueOnError) - flags.Usage = func() { ba.Ui.Say(ba.Help()) } + // flags.Usage = func() { ba.Ui.Say(ba.Help()) } ba.AddFlagSets(flags) err := flags.Parse(args) if err != nil { @@ -96,7 +96,7 @@ type BuildArgs struct { func (ca *ConsoleArgs) ParseArgvs(args []string) int { flags := flag.NewFlagSet("console", flag.ContinueOnError) - flags.Usage = func() { ca.Ui.Say(ca.Help()) } + // flags.Usage = func() { ca.Ui.Say(ca.Help()) } ca.AddFlagSets(flags) err := flags.Parse(args) if err != nil { @@ -118,7 +118,7 @@ func (fa *FixArgs) AddFlagSets(flags *flag.FlagSet) { func (fa *FixArgs) ParseArgvs(args []string) int { flags := flag.NewFlagSet("fix", flag.ContinueOnError) - flags.Usage = func() { fa.Ui.Say(fa.Help()) } + // flags.Usage = func() { fa.Ui.Say(fa.Help()) } fa.AddFlagSets(flags) err := flags.Parse(args) if err != nil { @@ -143,7 +143,7 @@ func (va *ValidateArgs) AddFlagSets(flags *flag.FlagSet) { func (va *ValidateArgs) ParseArgvs(args []string) int { flags := flag.NewFlagSet("validate", flag.ContinueOnError) - flags.Usage = func() { va.Ui.Say(va.Help()) } + // flags.Usage = func() { va.Ui.Say(va.Help()) } va.AddFlagSets(flags) err := flags.Parse(args) if err != nil { diff --git a/command/signal.go b/command/signal.go new file mode 100644 index 000000000..5fcbacae7 --- /dev/null +++ b/command/signal.go @@ -0,0 +1,37 @@ +package command + +import ( + "context" + "fmt" + "os" + "os/signal" + "syscall" + + "github.com/hashicorp/packer/packer" +) + +func handleTermInterrupt(ui packer.Ui) (context.Context, func()) { + ctx, cancelCtx := context.WithCancel(context.Background()) + // Handle interrupts for this build + sigCh := make(chan os.Signal, 1) + signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM) + cleanup := func() { + cancelCtx() + signal.Stop(sigCh) + close(sigCh) + } + go func() { + select { + case sig := <-sigCh: + if sig == nil { + // context got cancelled and this closed chan probably + // triggered first + return + } + ui.Error(fmt.Sprintf("Cancelling build after receiving %s", sig)) + cancelCtx() + case <-ctx.Done(): + } + }() + return ctx, cleanup +} From 2ef758763fdbb6b33250afe5d380a6f01c8ae160 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Fri, 8 May 2020 12:06:41 +0200 Subject: [PATCH 14/34] Update build_cancellation_test.go --- command/build_cancellation_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/command/build_cancellation_test.go b/command/build_cancellation_test.go index f1a5959db..8ae637660 100644 --- a/command/build_cancellation_test.go +++ b/command/build_cancellation_test.go @@ -62,7 +62,11 @@ func TestBuildCommand_RunContext_CtxCancel(t *testing.T) { codeC := make(chan int) go func() { defer close(codeC) - codeC <- c.RunContext(ctx, tt.args) + cfg, ret := c.ParseArgs(tt.args) + if ret != 0 { + t.Fatal("ParseArgs failed.") + } + codeC <- c.RunContext(ctx, cfg) }() t.Logf("waiting for passing tests if any") b.wg.Wait() // ran `tt.parallelPassingTests` times From 42a05e1e80ae831f6f91a8e44505582f178109de Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Fri, 8 May 2020 16:41:47 +0200 Subject: [PATCH 15/34] more refactoring --- command/build.go | 154 +++++++++------------------- command/build_test.go | 22 ++-- command/cli.go | 90 ++++------------ command/command.go | 12 --- hcl2template/types.packer_config.go | 12 ++- packer/core.go | 20 ++++ packer/new_stuff.go | 33 ++++++ 7 files changed, 137 insertions(+), 206 deletions(-) create mode 100644 packer/new_stuff.go diff --git a/command/build.go b/command/build.go index 40130ac52..af529f15c 100644 --- a/command/build.go +++ b/command/build.go @@ -13,7 +13,6 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclparse" "github.com/hashicorp/packer/hcl2template" - "github.com/hashicorp/packer/helper/enumflag" "github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/template" "golang.org/x/sync/semaphore" @@ -37,34 +36,15 @@ func (c *BuildCommand) Run(args []string) int { return c.RunContext(buildCtx, cfg) } -// Config is the command-configuration parsed from the command line. -type Config struct { - Color, Debug, Force, Timestamp bool - ParallelBuilds int64 - OnError string - Path string -} - -func (c *BuildCommand) ParseArgs(args []string) (Config, int) { - var cfg Config - var parallel bool +func (c *BuildCommand) ParseArgs(args []string) (*BuildArgs, int) { + var cfg *BuildArgs flags := c.Meta.FlagSet("build", FlagSetBuildFilter|FlagSetVars) flags.Usage = func() { c.Ui.Say(c.Help()) } - flags.BoolVar(&cfg.Color, "color", true, "") - flags.BoolVar(&cfg.Debug, "debug", false, "") - flags.BoolVar(&cfg.Force, "force", false, "") - flags.BoolVar(&cfg.Timestamp, "timestamp-ui", false, "") - flagOnError := enumflag.New(&cfg.OnError, "cleanup", "abort", "ask") - flags.Var(flagOnError, "on-error", "") - flags.BoolVar(¶llel, "parallel", true, "") - flags.Int64Var(&cfg.ParallelBuilds, "parallel-builds", 0, "") + cfg.AddFlagSets(flags) if err := flags.Parse(args); err != nil { return cfg, 1 } - if parallel == false && cfg.ParallelBuilds == 0 { - cfg.ParallelBuilds = 1 - } if cfg.ParallelBuilds < 1 { cfg.ParallelBuilds = math.MaxInt64 } @@ -78,7 +58,7 @@ func (c *BuildCommand) ParseArgs(args []string) (Config, int) { return cfg, 0 } -func (m *Meta) GetConfigFromHCL(path string) (BuildStarter, int) { +func (m *Meta) GetConfigFromHCL(path string) (packer.BuildGetter, int) { parser := &hcl2template.Parser{ Parser: hclparse.NewParser(), BuilderSchemas: m.CoreConfig.Components.BuilderStore, @@ -87,74 +67,50 @@ func (m *Meta) GetConfigFromHCL(path string) (BuildStarter, int) { } cfg, diags := parser.Parse(path, m.varFiles, m.flagVars) - { - // write HCL errors/diagnostics if any. - b := bytes.NewBuffer(nil) - err := hcl.NewDiagnosticTextWriter(b, parser.Files(), 80, false).WriteDiagnostics(diags) - if err != nil { - m.Ui.Error("could not write diagnostic: " + err.Error()) - return nil, 1 - } - if b.Len() != 0 { - m.Ui.Message(b.String()) - } - } - ret := 0 - if diags.HasErrors() { - ret = 1 - } + return cfg, writeDiags(m.Ui, parser.Files(), diags) +} - return func(opts buildStarterOptions) ([]packer.Build, int) { - builds, diags := cfg.GetBuilds(opts.only, opts.except) - { - // write HCL errors/diagnostics if any. - b := bytes.NewBuffer(nil) - err := hcl.NewDiagnosticTextWriter(b, parser.Files(), 80, false).WriteDiagnostics(diags) - if err != nil { - m.Ui.Error("could not write diagnostic: " + err.Error()) - return nil, 1 - } - if b.Len() != 0 { - m.Ui.Message(b.String()) - } - } +func writeDiags(ui packer.Ui, files map[string]*hcl.File, diags hcl.Diagnostics) int { + // write HCL errors/diagnostics if any. + b := bytes.NewBuffer(nil) + err := hcl.NewDiagnosticTextWriter(b, files, 80, false).WriteDiagnostics(diags) + if err != nil { + ui.Error("could not write diagnostic: " + err.Error()) + return 1 + } + if b.Len() != 0 { if diags.HasErrors() { - ret = 1 + ui.Error(b.String()) + return 1 } - - return builds, ret - }, ret + ui.Say(b.String()) + } + return 0 } -// GetBuilds will start all packer plugins ( builder, provisioner and -// post-processor ) referenced in the config. These plugins will be in a -// waiting to execute mode. Upon error a non nil error will be returned. -type BuildStarter func(buildStarterOptions) ([]packer.Build, int) - -type buildStarterOptions struct { - except, only []string -} - -func (m *Meta) GetConfig(path string) (BuildStarter, int) { - isHCLLoaded, err := isHCLLoaded(path) - if path != "-" && err != nil { - m.Ui.Error(fmt.Sprintf("could not tell whether %s is hcl enabled: %s", path, err)) +func (m *Meta) GetConfig(path ...string) (packer.BuildGetter, int) { + cfgType, err := ConfigType(path...) + if err != nil { + m.Ui.Error(fmt.Sprintf("could not tell config type: %s", err)) return nil, 1 } - if isHCLLoaded { - return m.GetConfigFromHCL(path) - } - // TODO: uncomment once we've polished HCL a bit more. - // c.Ui.Say(`Legacy JSON Configuration Will Be Used. - // The template will be parsed in the legacy configuration style. This style - // will continue to work but users are encouraged to move to the new style. - // See: https://packer.io/guides/hcl - // `) - return m.GetConfigFromJSON(path) + switch cfgType { + case "hcl": + // TODO(azr): allow to pass a slice of files here. + return m.GetConfigFromHCL(path[0]) + default: + // TODO: uncomment once we've polished HCL a bit more. + // c.Ui.Say(`Legacy JSON Configuration Will Be Used. + // The template will be parsed in the legacy configuration style. This style + // will continue to work but users are encouraged to move to the new style. + // See: https://packer.io/guides/hcl + // `) + return m.GetConfigFromJSON(path[0]) + } } -func (m *Meta) GetConfigFromJSON(path string) (BuildStarter, int) { +func (m *Meta) GetConfigFromJSON(path string) (packer.BuildGetter, int) { // Parse the template tpl, err := template.ParseFile(path) if err != nil { @@ -169,38 +125,24 @@ func (m *Meta) GetConfigFromJSON(path string) (BuildStarter, int) { m.Ui.Error(err.Error()) ret = 1 } - return func(opts buildStarterOptions) ([]packer.Build, int) { - ret := 0 - buildNames := core.BuildNames(opts.only, opts.except) - builds := make([]packer.Build, 0, len(buildNames)) - for _, n := range buildNames { - b, err := core.Build(n) - if err != nil { - m.Ui.Error(fmt.Sprintf( - "Failed to initialize build '%s': %s", - n, err)) - ret = 1 - continue - } - - builds = append(builds, b) - } - return builds, ret - }, ret + return core, ret } -func (c *BuildCommand) RunContext(buildCtx context.Context, cfg Config) int { - +func (c *BuildCommand) RunContext(buildCtx context.Context, cfg *BuildArgs) int { packerStarter, ret := c.GetConfig(cfg.Path) if ret != 0 { return ret } - builds, ret := packerStarter(buildStarterOptions{ - except: c.CoreConfig.Except, - only: c.CoreConfig.Only, + builds, diags := packerStarter.GetBuilds(packer.GetBuildsOptions{ + Only: cfg.Only, + Except: cfg.Except, }) + if ret := writeDiags(c.Ui, nil, diags); ret != 0 { + return ret + } + if cfg.Debug { c.Ui.Say("Debug mode enabled. Builds will not be parallelized.") } @@ -230,7 +172,7 @@ func (c *BuildCommand) RunContext(buildCtx context.Context, cfg Config) int { } } // Now add timestamps if requested - if cfg.Timestamp { + if cfg.TimestampUi { ui = &packer.TimestampedUi{ Ui: ui, } diff --git a/command/build_test.go b/command/build_test.go index 63eb53ff7..dd2d84390 100644 --- a/command/build_test.go +++ b/command/build_test.go @@ -630,13 +630,13 @@ func TestBuildCommand_ParseArgs(t *testing.T) { tests := []struct { fields fields args args - wantCfg Config + wantCfg BuildArgs wantExitCode int }{ {fields{defaultMeta}, args{[]string{"file.json"}}, - Config{ - Path: "file.json", + BuildArgs{ + MetaArgs: MetaArgs{Path: "file.json"}, ParallelBuilds: math.MaxInt64, Color: true, }, @@ -644,8 +644,8 @@ func TestBuildCommand_ParseArgs(t *testing.T) { }, {fields{defaultMeta}, args{[]string{"-parallel=true", "file.json"}}, - Config{ - Path: "file.json", + BuildArgs{ + MetaArgs: MetaArgs{Path: "file.json"}, ParallelBuilds: math.MaxInt64, Color: true, }, @@ -653,8 +653,8 @@ func TestBuildCommand_ParseArgs(t *testing.T) { }, {fields{defaultMeta}, args{[]string{"-parallel=false", "file.json"}}, - Config{ - Path: "file.json", + BuildArgs{ + MetaArgs: MetaArgs{Path: "file.json"}, ParallelBuilds: 1, Color: true, }, @@ -662,8 +662,8 @@ func TestBuildCommand_ParseArgs(t *testing.T) { }, {fields{defaultMeta}, args{[]string{"-parallel-builds=5", "file.json"}}, - Config{ - Path: "file.json", + BuildArgs{ + MetaArgs: MetaArgs{Path: "file.json"}, ParallelBuilds: 5, Color: true, }, @@ -671,8 +671,8 @@ func TestBuildCommand_ParseArgs(t *testing.T) { }, {fields{defaultMeta}, args{[]string{"-parallel=false", "-parallel-builds=5", "otherfile.json"}}, - Config{ - Path: "otherfile.json", + BuildArgs{ + MetaArgs: MetaArgs{Path: "otherfile.json"}, ParallelBuilds: 5, Color: true, }, diff --git a/command/cli.go b/command/cli.go index e1af60a22..b10ce4153 100644 --- a/command/cli.go +++ b/command/cli.go @@ -3,7 +3,6 @@ package command import ( "flag" "fmt" - "math" "strings" "github.com/hashicorp/packer/helper/enumflag" @@ -12,25 +11,20 @@ import ( "github.com/hashicorp/packer/packer" ) -// NewMetaArgs parses cli args and put possible values -func (ma *MetaArgs) AddFlagSets(fs *flag.FlagSet) { - fs.Var((*sliceflag.StringFlag)(&ma.Only), "only", "") - fs.Var((*sliceflag.StringFlag)(&ma.Except), "except", "") - fs.Var((*kvflag.Flag)(&ma.Vars), "var", "") - fs.Var((*kvflag.StringSlice)(&ma.VarFiles), "var-file", "") -} - // ConfigType tells what type of config we should use, it can return values // like "hcl" or "json". // Make sure Args was correctly set before. -func (ma *MetaArgs) ConfigType() (string, error) { - switch len(ma.Args) { +func ConfigType(args ...string) (string, error) { + switch len(args) { // TODO(azr): in the future, I want to allow passing multiple arguments to // merge HCL confs together; but this will probably need an RFC first. - // TODO(azr): To allow piping HCL2 confs (when args is "-"), we probably - // will need to add a setting that says "this is an HCL config". case 1: - name := ma.Args[0] + name := args[0] + if name == "-" { + // TODO(azr): To allow piping HCL2 confs (when args is "-"), we probably + // will need to add a setting that says "this is an HCL config". + return "json", nil + } if strings.HasSuffix(name, ".pkr.hcl") || strings.HasSuffix(name, ".pkr.json") { return "hcl", nil @@ -41,13 +35,21 @@ func (ma *MetaArgs) ConfigType() (string, error) { } return "json", err default: - return "", fmt.Errorf("packer only takes on argument: %q", ma.Args) + return "", fmt.Errorf("packer only takes one argument: %q", args) } } +// NewMetaArgs parses cli args and put possible values +func (ma *MetaArgs) AddFlagSets(fs *flag.FlagSet) { + fs.Var((*sliceflag.StringFlag)(&ma.Only), "only", "") + fs.Var((*sliceflag.StringFlag)(&ma.Except), "except", "") + fs.Var((*kvflag.Flag)(&ma.Vars), "var", "") + fs.Var((*kvflag.StringSlice)(&ma.VarFiles), "var-file", "") +} + // MetaArgs defines commonalities between all comands type MetaArgs struct { - Args []string + Path string Only, Except []string Vars map[string]string VarFiles []string @@ -69,23 +71,6 @@ func (ba *BuildArgs) AddFlagSets(flags *flag.FlagSet) { ba.MetaArgs.AddFlagSets(flags) } -func (ba *BuildArgs) ParseArgvs(args []string) int { - flags := flag.NewFlagSet("build", flag.ContinueOnError) - // flags.Usage = func() { ba.Ui.Say(ba.Help()) } - ba.AddFlagSets(flags) - err := flags.Parse(args) - if err != nil { - return 1 - } - - if ba.ParallelBuilds < 1 { - ba.ParallelBuilds = math.MaxInt64 - } - - ba.Args = flags.Args() - return 0 -} - // BuildArgs represents a parsed cli line for a `packer build` type BuildArgs struct { MetaArgs @@ -94,19 +79,6 @@ type BuildArgs struct { OnError string } -func (ca *ConsoleArgs) ParseArgvs(args []string) int { - flags := flag.NewFlagSet("console", flag.ContinueOnError) - // flags.Usage = func() { ca.Ui.Say(ca.Help()) } - ca.AddFlagSets(flags) - err := flags.Parse(args) - if err != nil { - return 1 - } - - ca.Args = flags.Args() - return 0 -} - // ConsoleArgs represents a parsed cli line for a `packer console` type ConsoleArgs struct{ MetaArgs } @@ -116,19 +88,6 @@ func (fa *FixArgs) AddFlagSets(flags *flag.FlagSet) { fa.MetaArgs.AddFlagSets(flags) } -func (fa *FixArgs) ParseArgvs(args []string) int { - flags := flag.NewFlagSet("fix", flag.ContinueOnError) - // flags.Usage = func() { fa.Ui.Say(fa.Help()) } - fa.AddFlagSets(flags) - err := flags.Parse(args) - if err != nil { - return 1 - } - - fa.Args = flags.Args() - return 0 -} - // FixArgs represents a parsed cli line for a `packer fix` type FixArgs struct { MetaArgs @@ -141,19 +100,6 @@ func (va *ValidateArgs) AddFlagSets(flags *flag.FlagSet) { va.MetaArgs.AddFlagSets(flags) } -func (va *ValidateArgs) ParseArgvs(args []string) int { - flags := flag.NewFlagSet("validate", flag.ContinueOnError) - // flags.Usage = func() { va.Ui.Say(va.Help()) } - va.AddFlagSets(flags) - err := flags.Parse(args) - if err != nil { - return 1 - } - - va.Args = flags.Args() - return 0 -} - // ValidateArgs represents a parsed cli line for a `packer validate` type ValidateArgs struct { MetaArgs diff --git a/command/command.go b/command/command.go index 3a11c4d7b..d47dcf0d9 100644 --- a/command/command.go +++ b/command/command.go @@ -1,13 +1 @@ package command - -import "context" - -// PackerInterface is the interface to use packer; it represents ways users can -// use Packer. A call returns a int that will be the exit code of Packer, -// everything else is up to the implementer. -type PackerInterface interface { - Build(ctx context.Context, args *BuildArgs) int - Console(ctx context.Context, args *ConsoleArgs) int - Fix(ctx context.Context, args *FixArgs) int - Validate(ctx context.Context, args *ValidateArgs) int -} diff --git a/hcl2template/types.packer_config.go b/hcl2template/types.packer_config.go index 86b3702cc..2a2ca2285 100644 --- a/hcl2template/types.packer_config.go +++ b/hcl2template/types.packer_config.go @@ -12,6 +12,8 @@ import ( // PackerConfig represents a loaded Packer HCL config. It will contain // references to all possible blocks of the allowed configuration. type PackerConfig struct { + parser *Parser + // Directory where the config files are defined Basedir string @@ -254,7 +256,7 @@ func (cfg *PackerConfig) getCoreBuildPostProcessors(source *SourceBlock, blocks // GetBuilds returns a list of packer Build based on the HCL2 parsed build // blocks. All Builders, Provisioners and Post Processors will be started and // configured. -func (cfg *PackerConfig) GetBuilds(only, except []string) ([]packer.Build, hcl.Diagnostics) { +func (cfg *PackerConfig) GetBuilds(opts packer.GetBuildsOptions) ([]packer.Build, hcl.Diagnostics) { res := []packer.Build{} var diags hcl.Diagnostics @@ -274,8 +276,8 @@ func (cfg *PackerConfig) GetBuilds(only, except []string) ([]packer.Build, hcl.D buildName := fmt.Sprintf("%s.%s", src.Type, src.Name) // -only - if len(only) > 0 { - onlyGlobs, diags := convertFilterOption(only, "only") + if len(opts.Only) > 0 { + onlyGlobs, diags := convertFilterOption(opts.Only, "only") if diags.HasErrors() { return nil, diags } @@ -292,8 +294,8 @@ func (cfg *PackerConfig) GetBuilds(only, except []string) ([]packer.Build, hcl.D } // -except - if len(except) > 0 { - exceptGlobs, diags := convertFilterOption(except, "except") + if len(opts.Except) > 0 { + exceptGlobs, diags := convertFilterOption(opts.Except, "except") if diags.HasErrors() { return nil, diags } diff --git a/packer/core.go b/packer/core.go index 04be127c3..5faf56ae7 100644 --- a/packer/core.go +++ b/packer/core.go @@ -11,6 +11,7 @@ import ( multierror "github.com/hashicorp/go-multierror" version "github.com/hashicorp/go-version" + "github.com/hashicorp/hcl/v2" "github.com/hashicorp/packer/template" "github.com/hashicorp/packer/template/interpolate" ) @@ -198,6 +199,25 @@ func (c *Core) generateCoreBuildProvisioner(rawP *template.Provisioner, rawName return cbp, nil } +func (c *Core) GetBuilds(opts GetBuildsOptions) ([]Build, hcl.Diagnostics) { + buildNames := c.BuildNames(opts.Only, opts.Except) + builds := []Build{} + diags := hcl.Diagnostics{} + for _, n := range buildNames { + b, err := c.Build(n) + if err != nil { + diags = append(diags, &hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: fmt.Sprintf("Failed to initialize build %q", n), + Detail: err.Error(), + }) + continue + } + builds = append(builds, b) + } + return builds, diags +} + // Build returns the Build object for the given name. func (c *Core) Build(n string) (Build, error) { // Setup the builder diff --git a/packer/new_stuff.go b/packer/new_stuff.go new file mode 100644 index 000000000..00d252fa4 --- /dev/null +++ b/packer/new_stuff.go @@ -0,0 +1,33 @@ +package packer + +import "github.com/hashicorp/hcl/v2" + +type GetBuildsOptions struct { + // Get builds except the ones that match with except and with only the ones + // that match with. When those are empty everything matches. + Except, Only []string +} + +type BuildGetter interface { + // GetBuilds return all possible builds for a config. It also starts them. + // TODO(azr): rename to builder starter ? + GetBuilds(GetBuildsOptions) ([]Build, hcl.Diagnostics) +} + +//go:generate enumer -type FixMode +type FixConfigMode int + +const ( + Stdout FixConfigMode = 0 + Inplace FixConfigMode = 1 + Diff FixConfigMode = 2 +) + +type FixConfigOptions struct { + DiffOnly bool +} + +type OtherInterfaceyMacOtherInterfaceFace interface { + // FixConfig will output the config in a fixed manner. + FixConfig(FixConfigOptions) hcl.Diagnostics +} From 7e45a1e950aa5abb82778e3d90b2f88a5adc273f Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Fri, 8 May 2020 16:54:44 +0200 Subject: [PATCH 16/34] fix enum --- packer/fixconfigmode_enumer.go | 51 ++++++++++++++++++++++++++++++++++ packer/new_stuff.go | 8 +++--- 2 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 packer/fixconfigmode_enumer.go diff --git a/packer/fixconfigmode_enumer.go b/packer/fixconfigmode_enumer.go new file mode 100644 index 000000000..82b09a633 --- /dev/null +++ b/packer/fixconfigmode_enumer.go @@ -0,0 +1,51 @@ +// Code generated by "enumer -type FixConfigMode"; DO NOT EDIT. + +// +package packer + +import ( + "fmt" +) + +const _FixConfigModeName = "StdoutInplaceDiff" + +var _FixConfigModeIndex = [...]uint8{0, 6, 13, 17} + +func (i FixConfigMode) String() string { + if i < 0 || i >= FixConfigMode(len(_FixConfigModeIndex)-1) { + return fmt.Sprintf("FixConfigMode(%d)", i) + } + return _FixConfigModeName[_FixConfigModeIndex[i]:_FixConfigModeIndex[i+1]] +} + +var _FixConfigModeValues = []FixConfigMode{0, 1, 2} + +var _FixConfigModeNameToValueMap = map[string]FixConfigMode{ + _FixConfigModeName[0:6]: 0, + _FixConfigModeName[6:13]: 1, + _FixConfigModeName[13:17]: 2, +} + +// FixConfigModeString retrieves an enum value from the enum constants string name. +// Throws an error if the param is not part of the enum. +func FixConfigModeString(s string) (FixConfigMode, error) { + if val, ok := _FixConfigModeNameToValueMap[s]; ok { + return val, nil + } + return 0, fmt.Errorf("%s does not belong to FixConfigMode values", s) +} + +// FixConfigModeValues returns all values of the enum +func FixConfigModeValues() []FixConfigMode { + return _FixConfigModeValues +} + +// IsAFixConfigMode returns "true" if the value is listed in the enum definition. "false" otherwise +func (i FixConfigMode) IsAFixConfigMode() bool { + for _, v := range _FixConfigModeValues { + if i == v { + return true + } + } + return false +} diff --git a/packer/new_stuff.go b/packer/new_stuff.go index 00d252fa4..0df4af30f 100644 --- a/packer/new_stuff.go +++ b/packer/new_stuff.go @@ -14,13 +14,13 @@ type BuildGetter interface { GetBuilds(GetBuildsOptions) ([]Build, hcl.Diagnostics) } -//go:generate enumer -type FixMode +//go:generate enumer -type FixConfigMode type FixConfigMode int const ( - Stdout FixConfigMode = 0 - Inplace FixConfigMode = 1 - Diff FixConfigMode = 2 + Stdout FixConfigMode = iota + Inplace + Diff ) type FixConfigOptions struct { From ec083083ce9c7990f9c156c400555fc98e2cf2ca Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Fri, 8 May 2020 16:59:19 +0200 Subject: [PATCH 17/34] Update new_stuff.go --- packer/new_stuff.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packer/new_stuff.go b/packer/new_stuff.go index 0df4af30f..baede1edf 100644 --- a/packer/new_stuff.go +++ b/packer/new_stuff.go @@ -4,7 +4,7 @@ import "github.com/hashicorp/hcl/v2" type GetBuildsOptions struct { // Get builds except the ones that match with except and with only the ones - // that match with. When those are empty everything matches. + // that match with Only. When those are empty everything matches. Except, Only []string } From 0062160581f53a7d4191c0a7d5f18905c328bbcc Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Fri, 8 May 2020 17:01:42 +0200 Subject: [PATCH 18/34] Update common_test.go --- hcl2template/common_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hcl2template/common_test.go b/hcl2template/common_test.go index b64295057..61b41a186 100644 --- a/hcl2template/common_test.go +++ b/hcl2template/common_test.go @@ -116,7 +116,7 @@ func testParse(t *testing.T, tests []parseTest) { return } - gotBuilds, gotDiags := gotCfg.GetBuilds(nil, nil) + gotBuilds, gotDiags := gotCfg.GetBuilds(packer.GetBuildsOptions{}) if tt.getBuildsWantDiags == (gotDiags == nil) { t.Fatalf("Parser.getBuilds() unexpected diagnostics. %s", gotDiags) } From a93a45e4d38e6e4aaa75e43b1a9e544ab07b248a Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Fri, 8 May 2020 17:15:00 +0200 Subject: [PATCH 19/34] more fixes to refactor --- command/cli.go | 12 ++++++++++++ command/meta.go | 14 -------------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/command/cli.go b/command/cli.go index b10ce4153..cf104c762 100644 --- a/command/cli.go +++ b/command/cli.go @@ -41,6 +41,9 @@ func ConfigType(args ...string) (string, error) { // NewMetaArgs parses cli args and put possible values func (ma *MetaArgs) AddFlagSets(fs *flag.FlagSet) { + if ma == nil { + ma = &MetaArgs{} + } fs.Var((*sliceflag.StringFlag)(&ma.Only), "only", "") fs.Var((*sliceflag.StringFlag)(&ma.Except), "except", "") fs.Var((*kvflag.Flag)(&ma.Vars), "var", "") @@ -57,6 +60,9 @@ type MetaArgs struct { } func (ba *BuildArgs) AddFlagSets(flags *flag.FlagSet) { + if ba == nil { + ba = &BuildArgs{} + } flags.BoolVar(&ba.Color, "color", true, "") flags.BoolVar(&ba.Debug, "debug", false, "") flags.BoolVar(&ba.Force, "force", false, "") @@ -83,6 +89,9 @@ type BuildArgs struct { type ConsoleArgs struct{ MetaArgs } func (fa *FixArgs) AddFlagSets(flags *flag.FlagSet) { + if fa == nil { + fa = &FixArgs{} + } flags.BoolVar(&fa.Validate, "validate", true, "") fa.MetaArgs.AddFlagSets(flags) @@ -95,6 +104,9 @@ type FixArgs struct { } func (va *ValidateArgs) AddFlagSets(flags *flag.FlagSet) { + if va == nil { + va = &ValidateArgs{} + } flags.BoolVar(&va.SyntaxOnly, "syntax-only", true, "") va.MetaArgs.AddFlagSets(flags) diff --git a/command/meta.go b/command/meta.go index a42a463f0..6e0543e2c 100644 --- a/command/meta.go +++ b/command/meta.go @@ -8,7 +8,6 @@ import ( "os" kvflag "github.com/hashicorp/packer/helper/flag-kv" - sliceflag "github.com/hashicorp/packer/helper/flag-slice" "github.com/hashicorp/packer/helper/wrappedstreams" "github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/template" @@ -80,19 +79,6 @@ func (m *Meta) Core(tpl *template.Template) (*packer.Core, error) { func (m *Meta) FlagSet(n string, fs FlagSetFlags) *flag.FlagSet { f := flag.NewFlagSet(n, flag.ContinueOnError) - // FlagSetBuildFilter tells us to enable the settings for selecting - // builds we care about. - if fs&FlagSetBuildFilter != 0 { - f.Var((*sliceflag.StringFlag)(&m.CoreConfig.Except), "except", "") - f.Var((*sliceflag.StringFlag)(&m.CoreConfig.Only), "only", "") - } - - // FlagSetVars tells us what variables to use - if fs&FlagSetVars != 0 { - f.Var((*kvflag.Flag)(&m.flagVars), "var", "") - f.Var((*kvflag.StringSlice)(&m.varFiles), "var-file", "") - } - // Create an io.Writer that writes to our Ui properly for errors. // This is kind of a hack, but it does the job. Basically: create // a pipe, use a scanner to break it into lines, and output each line From 1f3e85185ef42cc22b5a6bc402429a9cc3966f33 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Fri, 8 May 2020 17:19:49 +0200 Subject: [PATCH 20/34] Update types.packer_config.go --- hcl2template/types.packer_config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hcl2template/types.packer_config.go b/hcl2template/types.packer_config.go index 2a2ca2285..96293eb18 100644 --- a/hcl2template/types.packer_config.go +++ b/hcl2template/types.packer_config.go @@ -12,7 +12,7 @@ import ( // PackerConfig represents a loaded Packer HCL config. It will contain // references to all possible blocks of the allowed configuration. type PackerConfig struct { - parser *Parser + // parser *Parser // Directory where the config files are defined Basedir string From efcc6af06c6f3bcb4f997c06c639736857b17c0c Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Fri, 8 May 2020 17:46:33 +0200 Subject: [PATCH 21/34] fix tests --- command/build.go | 10 +++++----- command/build_cancellation_test.go | 12 ++++++------ command/build_cleanup_script_test.go | 2 +- command/build_parallel_test.go | 2 +- command/build_test.go | 20 ++++++++++---------- command/cli.go | 12 ------------ website/pages/docs/commands/build.mdx | 5 ----- 7 files changed, 23 insertions(+), 40 deletions(-) diff --git a/command/build.go b/command/build.go index af529f15c..d4ae94a19 100644 --- a/command/build.go +++ b/command/build.go @@ -37,12 +37,12 @@ func (c *BuildCommand) Run(args []string) int { } func (c *BuildCommand) ParseArgs(args []string) (*BuildArgs, int) { - var cfg *BuildArgs + var cfg BuildArgs flags := c.Meta.FlagSet("build", FlagSetBuildFilter|FlagSetVars) flags.Usage = func() { c.Ui.Say(c.Help()) } cfg.AddFlagSets(flags) if err := flags.Parse(args); err != nil { - return cfg, 1 + return &cfg, 1 } if cfg.ParallelBuilds < 1 { @@ -52,10 +52,10 @@ func (c *BuildCommand) ParseArgs(args []string) (*BuildArgs, int) { args = flags.Args() if len(args) != 1 { flags.Usage() - return cfg, 1 + return &cfg, 1 } cfg.Path = args[0] - return cfg, 0 + return &cfg, 0 } func (m *Meta) GetConfigFromHCL(path string) (packer.BuildGetter, int) { @@ -374,7 +374,7 @@ Options: -force Force a build to continue if artifacts exist, deletes existing artifacts. -machine-readable Produce machine-readable output. -on-error=[cleanup|abort|ask] If the build fails do: clean up (default), abort, or ask. - -parallel=false Disable parallelization. (Default: true) + -parallel-builds=1 Disable parallelization. (Default: true) -parallel-builds=1 Number of builds to run in parallel. 0 means no limit (Default: 0) -timestamp-ui Enable prefixing of each ui output with an RFC3339 timestamp. -var 'key=value' Variable for templates, can be used multiple times. diff --git a/command/build_cancellation_test.go b/command/build_cancellation_test.go index 8ae637660..f85828da6 100644 --- a/command/build_cancellation_test.go +++ b/command/build_cancellation_test.go @@ -18,32 +18,32 @@ func TestBuildCommand_RunContext_CtxCancel(t *testing.T) { expected int }{ {"cancel 1 pending build - parallel=true", - []string{"-parallel=true", filepath.Join(testFixture("parallel"), "1lock-5wg.json")}, + []string{"-parallel-builds=10", filepath.Join(testFixture("parallel"), "1lock-5wg.json")}, 5, 1, }, {"cancel in the middle with 2 pending builds - parallel=true", - []string{"-parallel=true", filepath.Join(testFixture("parallel"), "2lock-4wg.json")}, + []string{"-parallel-builds=10", filepath.Join(testFixture("parallel"), "2lock-4wg.json")}, 4, 1, }, {"cancel 1 locked build - debug - parallel=true", - []string{"-parallel=true", "-debug=true", filepath.Join(testFixture("parallel"), "1lock.json")}, + []string{"-parallel-builds=10", "-debug=true", filepath.Join(testFixture("parallel"), "1lock.json")}, 0, 1, }, {"cancel 2 locked builds - debug - parallel=true", - []string{"-parallel=true", "-debug=true", filepath.Join(testFixture("parallel"), "2lock.json")}, + []string{"-parallel-builds=10", "-debug=true", filepath.Join(testFixture("parallel"), "2lock.json")}, 0, 1, }, {"cancel 1 locked build - debug - parallel=false", - []string{"-parallel=false", "-debug=true", filepath.Join(testFixture("parallel"), "1lock.json")}, + []string{"-parallel-builds=1", "-debug=true", filepath.Join(testFixture("parallel"), "1lock.json")}, 0, 1, }, {"cancel 2 locked builds - debug - parallel=false", - []string{"-parallel=false", "-debug=true", filepath.Join(testFixture("parallel"), "2lock.json")}, + []string{"-parallel-builds=1", "-debug=true", filepath.Join(testFixture("parallel"), "2lock.json")}, 0, 1, }, diff --git a/command/build_cleanup_script_test.go b/command/build_cleanup_script_test.go index de309d437..38c3c4f29 100644 --- a/command/build_cleanup_script_test.go +++ b/command/build_cleanup_script_test.go @@ -11,7 +11,7 @@ func TestBuildWithCleanupScript(t *testing.T) { } args := []string{ - "-parallel=false", + "-parallel-builds=1", filepath.Join(testFixture("cleanup-script"), "template.json"), } diff --git a/command/build_parallel_test.go b/command/build_parallel_test.go index cf4e7b40a..abfc34d85 100644 --- a/command/build_parallel_test.go +++ b/command/build_parallel_test.go @@ -95,7 +95,7 @@ func TestBuildParallel_1(t *testing.T) { } args := []string{ - fmt.Sprintf("-parallel=true"), + fmt.Sprintf("-parallel-builds=10"), filepath.Join(testFixture("parallel"), "1lock-5wg.json"), } diff --git a/command/build_test.go b/command/build_test.go index dd2d84390..8179372c6 100644 --- a/command/build_test.go +++ b/command/build_test.go @@ -224,7 +224,7 @@ func TestBuildOnlyFileCommaFlags(t *testing.T) { } args := []string{ - "-parallel=false", + "-parallel-builds=1", "-only=chocolate,vanilla", filepath.Join(testFixture("build-only"), "template.json"), } @@ -266,7 +266,7 @@ func TestBuildStdin(t *testing.T) { defer func() { os.Stdin = stdin }() defer cleanup() - if code := c.Run([]string{"-parallel=false", "-"}); code != 0 { + if code := c.Run([]string{"-parallel-builds=1", "-"}); code != 0 { fatalCommand(t, c.Meta) } @@ -284,7 +284,7 @@ func TestBuildOnlyFileMultipleFlags(t *testing.T) { } args := []string{ - "-parallel=false", + "-parallel-builds=1", "-only=chocolate", "-only=cherry", "-only=apple", // ignored @@ -345,7 +345,7 @@ func TestBuildEverything(t *testing.T) { } args := []string{ - "-parallel=false", + "-parallel-builds=1", `-except=`, filepath.Join(testFixture("build-only"), "template.json"), } @@ -370,7 +370,7 @@ func TestBuildExceptFileCommaFlags(t *testing.T) { } args := []string{ - "-parallel=false", + "-parallel-builds=1", "-except=chocolate,vanilla", filepath.Join(testFixture("build-only"), "template.json"), } @@ -401,7 +401,7 @@ func testHCLOnlyExceptFlags(t *testing.T, args, present, notPresent []string) { defer cleanup() - finalArgs := []string{"-parallel=false"} + finalArgs := []string{"-parallel-builds=1"} finalArgs = append(finalArgs, args...) finalArgs = append(finalArgs, testFixture("hcl-only-except")) @@ -482,7 +482,7 @@ func TestBuildWithNonExistingBuilder(t *testing.T) { } args := []string{ - "-parallel=false", + "-parallel-builds=1", `-except=`, filepath.Join(testFixture("build-only"), "not-found.json"), } @@ -643,7 +643,7 @@ func TestBuildCommand_ParseArgs(t *testing.T) { 0, }, {fields{defaultMeta}, - args{[]string{"-parallel=true", "file.json"}}, + args{[]string{"-parallel-builds=10", "file.json"}}, BuildArgs{ MetaArgs: MetaArgs{Path: "file.json"}, ParallelBuilds: math.MaxInt64, @@ -652,7 +652,7 @@ func TestBuildCommand_ParseArgs(t *testing.T) { 0, }, {fields{defaultMeta}, - args{[]string{"-parallel=false", "file.json"}}, + args{[]string{"-parallel-builds=1", "file.json"}}, BuildArgs{ MetaArgs: MetaArgs{Path: "file.json"}, ParallelBuilds: 1, @@ -670,7 +670,7 @@ func TestBuildCommand_ParseArgs(t *testing.T) { 0, }, {fields{defaultMeta}, - args{[]string{"-parallel=false", "-parallel-builds=5", "otherfile.json"}}, + args{[]string{"-parallel-builds=1", "-parallel-builds=5", "otherfile.json"}}, BuildArgs{ MetaArgs: MetaArgs{Path: "otherfile.json"}, ParallelBuilds: 5, diff --git a/command/cli.go b/command/cli.go index cf104c762..b10ce4153 100644 --- a/command/cli.go +++ b/command/cli.go @@ -41,9 +41,6 @@ func ConfigType(args ...string) (string, error) { // NewMetaArgs parses cli args and put possible values func (ma *MetaArgs) AddFlagSets(fs *flag.FlagSet) { - if ma == nil { - ma = &MetaArgs{} - } fs.Var((*sliceflag.StringFlag)(&ma.Only), "only", "") fs.Var((*sliceflag.StringFlag)(&ma.Except), "except", "") fs.Var((*kvflag.Flag)(&ma.Vars), "var", "") @@ -60,9 +57,6 @@ type MetaArgs struct { } func (ba *BuildArgs) AddFlagSets(flags *flag.FlagSet) { - if ba == nil { - ba = &BuildArgs{} - } flags.BoolVar(&ba.Color, "color", true, "") flags.BoolVar(&ba.Debug, "debug", false, "") flags.BoolVar(&ba.Force, "force", false, "") @@ -89,9 +83,6 @@ type BuildArgs struct { type ConsoleArgs struct{ MetaArgs } func (fa *FixArgs) AddFlagSets(flags *flag.FlagSet) { - if fa == nil { - fa = &FixArgs{} - } flags.BoolVar(&fa.Validate, "validate", true, "") fa.MetaArgs.AddFlagSets(flags) @@ -104,9 +95,6 @@ type FixArgs struct { } func (va *ValidateArgs) AddFlagSets(flags *flag.FlagSet) { - if va == nil { - va = &ValidateArgs{} - } flags.BoolVar(&va.SyntaxOnly, "syntax-only", true, "") va.MetaArgs.AddFlagSets(flags) diff --git a/website/pages/docs/commands/build.mdx b/website/pages/docs/commands/build.mdx index 3e8533ef5..40cc1309f 100644 --- a/website/pages/docs/commands/build.mdx +++ b/website/pages/docs/commands/build.mdx @@ -52,11 +52,6 @@ artifacts that are created will be outputted at the end of the build. attribute is specified within the configuration. `-only` does not apply to post-processors. -- `-parallel=false` - /!\ Deprecated, use `-parallel-builds=1` instead, - setting `-parallel-builds=N` to more that 0 will ignore the `-parallel` - setting. Set `-parallel=false` to disable parallelization of multiple - builders (on by default). - - `-parallel-builds=N` - Limit the number of builds to run in parallel, 0 means no limit (defaults to 0). From e6aac8cd6f56593307c5606302094b1dd639357a Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Fri, 8 May 2020 17:50:48 +0200 Subject: [PATCH 22/34] Update build_test.go --- command/build_test.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/command/build_test.go b/command/build_test.go index 8179372c6..a1c9a2f71 100644 --- a/command/build_test.go +++ b/command/build_test.go @@ -630,12 +630,12 @@ func TestBuildCommand_ParseArgs(t *testing.T) { tests := []struct { fields fields args args - wantCfg BuildArgs + wantCfg *BuildArgs wantExitCode int }{ {fields{defaultMeta}, args{[]string{"file.json"}}, - BuildArgs{ + &BuildArgs{ MetaArgs: MetaArgs{Path: "file.json"}, ParallelBuilds: math.MaxInt64, Color: true, @@ -644,16 +644,16 @@ func TestBuildCommand_ParseArgs(t *testing.T) { }, {fields{defaultMeta}, args{[]string{"-parallel-builds=10", "file.json"}}, - BuildArgs{ + &BuildArgs{ MetaArgs: MetaArgs{Path: "file.json"}, - ParallelBuilds: math.MaxInt64, + ParallelBuilds: 10, Color: true, }, 0, }, {fields{defaultMeta}, args{[]string{"-parallel-builds=1", "file.json"}}, - BuildArgs{ + &BuildArgs{ MetaArgs: MetaArgs{Path: "file.json"}, ParallelBuilds: 1, Color: true, @@ -662,7 +662,7 @@ func TestBuildCommand_ParseArgs(t *testing.T) { }, {fields{defaultMeta}, args{[]string{"-parallel-builds=5", "file.json"}}, - BuildArgs{ + &BuildArgs{ MetaArgs: MetaArgs{Path: "file.json"}, ParallelBuilds: 5, Color: true, @@ -671,7 +671,7 @@ func TestBuildCommand_ParseArgs(t *testing.T) { }, {fields{defaultMeta}, args{[]string{"-parallel-builds=1", "-parallel-builds=5", "otherfile.json"}}, - BuildArgs{ + &BuildArgs{ MetaArgs: MetaArgs{Path: "otherfile.json"}, ParallelBuilds: 5, Color: true, From b35ec44d06454b61ff2ebdb9704d60fc36021dfd Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Fri, 8 May 2020 18:01:34 +0200 Subject: [PATCH 23/34] Update build.go --- command/build.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/command/build.go b/command/build.go index d4ae94a19..60514a1e6 100644 --- a/command/build.go +++ b/command/build.go @@ -139,9 +139,9 @@ func (c *BuildCommand) RunContext(buildCtx context.Context, cfg *BuildArgs) int Except: cfg.Except, }) - if ret := writeDiags(c.Ui, nil, diags); ret != 0 { - return ret - } + // here, something could have gone wrong but we still want to run valid + // builds. + ret = writeDiags(c.Ui, nil, diags) if cfg.Debug { c.Ui.Say("Debug mode enabled. Builds will not be parallelized.") From 534e98c4efa2ffe74a3c99b6441933eaaaaa62ee Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Mon, 11 May 2020 17:56:14 +0200 Subject: [PATCH 24/34] pass Meta command line arguments around --- command/build.go | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/command/build.go b/command/build.go index 60514a1e6..238b8df51 100644 --- a/command/build.go +++ b/command/build.go @@ -58,7 +58,7 @@ func (c *BuildCommand) ParseArgs(args []string) (*BuildArgs, int) { return &cfg, 0 } -func (m *Meta) GetConfigFromHCL(path string) (packer.BuildGetter, int) { +func (m *Meta) GetConfigFromHCL(cla *MetaArgs) (packer.BuildGetter, int) { parser := &hcl2template.Parser{ Parser: hclparse.NewParser(), BuilderSchemas: m.CoreConfig.Components.BuilderStore, @@ -66,7 +66,7 @@ func (m *Meta) GetConfigFromHCL(path string) (packer.BuildGetter, int) { PostProcessorsSchemas: m.CoreConfig.Components.PostProcessorStore, } - cfg, diags := parser.Parse(path, m.varFiles, m.flagVars) + cfg, diags := parser.Parse(cla.Path, cla.VarFiles, cla.Vars) return cfg, writeDiags(m.Ui, parser.Files(), diags) } @@ -88,8 +88,8 @@ func writeDiags(ui packer.Ui, files map[string]*hcl.File, diags hcl.Diagnostics) return 0 } -func (m *Meta) GetConfig(path ...string) (packer.BuildGetter, int) { - cfgType, err := ConfigType(path...) +func (m *Meta) GetConfig(cla *MetaArgs) (packer.BuildGetter, int) { + cfgType, err := ConfigType(cla.Path) if err != nil { m.Ui.Error(fmt.Sprintf("could not tell config type: %s", err)) return nil, 1 @@ -98,7 +98,7 @@ func (m *Meta) GetConfig(path ...string) (packer.BuildGetter, int) { switch cfgType { case "hcl": // TODO(azr): allow to pass a slice of files here. - return m.GetConfigFromHCL(path[0]) + return m.GetConfigFromHCL(cla) default: // TODO: uncomment once we've polished HCL a bit more. // c.Ui.Say(`Legacy JSON Configuration Will Be Used. @@ -106,7 +106,7 @@ func (m *Meta) GetConfig(path ...string) (packer.BuildGetter, int) { // will continue to work but users are encouraged to move to the new style. // See: https://packer.io/guides/hcl // `) - return m.GetConfigFromJSON(path[0]) + return m.GetConfigFromJSON(cla.Path) } } @@ -128,22 +128,22 @@ func (m *Meta) GetConfigFromJSON(path string) (packer.BuildGetter, int) { return core, ret } -func (c *BuildCommand) RunContext(buildCtx context.Context, cfg *BuildArgs) int { - packerStarter, ret := c.GetConfig(cfg.Path) +func (c *BuildCommand) RunContext(buildCtx context.Context, cla *BuildArgs) int { + packerStarter, ret := c.GetConfig(&cla.MetaArgs) if ret != 0 { return ret } builds, diags := packerStarter.GetBuilds(packer.GetBuildsOptions{ - Only: cfg.Only, - Except: cfg.Except, + Only: cla.Only, + Except: cla.Except, }) // here, something could have gone wrong but we still want to run valid // builds. ret = writeDiags(c.Ui, nil, diags) - if cfg.Debug { + if cla.Debug { c.Ui.Say("Debug mode enabled. Builds will not be parallelized.") } @@ -158,7 +158,7 @@ func (c *BuildCommand) RunContext(buildCtx context.Context, cfg *BuildArgs) int buildUis := make(map[packer.Build]packer.Ui) for i := range builds { ui := c.Ui - if cfg.Color { + if cla.Color { ui = &packer.ColoredUi{ Color: colors[i%len(colors)], Ui: ui, @@ -172,7 +172,7 @@ func (c *BuildCommand) RunContext(buildCtx context.Context, cfg *BuildArgs) int } } // Now add timestamps if requested - if cfg.TimestampUi { + if cla.TimestampUi { ui = &packer.TimestampedUi{ Ui: ui, } @@ -181,17 +181,17 @@ func (c *BuildCommand) RunContext(buildCtx context.Context, cfg *BuildArgs) int buildUis[builds[i]] = ui } - log.Printf("Build debug mode: %v", cfg.Debug) - log.Printf("Force build: %v", cfg.Force) - log.Printf("On error: %v", cfg.OnError) + log.Printf("Build debug mode: %v", cla.Debug) + log.Printf("Force build: %v", cla.Force) + log.Printf("On error: %v", cla.OnError) // Set the debug and force mode and prepare all the builds for i := range builds { b := builds[i] log.Printf("Preparing build: %s", b.Name()) - b.SetDebug(cfg.Debug) - b.SetForce(cfg.Force) - b.SetOnError(cfg.OnError) + b.SetDebug(cla.Debug) + b.SetForce(cla.Force) + b.SetOnError(cla.OnError) warnings, err := b.Prepare() if err != nil { @@ -219,7 +219,7 @@ func (c *BuildCommand) RunContext(buildCtx context.Context, cfg *BuildArgs) int sync.RWMutex m map[string]error }{m: make(map[string]error)} - limitParallel := semaphore.NewWeighted(cfg.ParallelBuilds) + limitParallel := semaphore.NewWeighted(cla.ParallelBuilds) for i := range builds { if err := buildCtx.Err(); err != nil { log.Println("Interrupted, not going to start any more builds.") @@ -263,12 +263,12 @@ func (c *BuildCommand) RunContext(buildCtx context.Context, cfg *BuildArgs) int } }() - if cfg.Debug { + if cla.Debug { log.Printf("Debug enabled, so waiting for build to finish: %s", b.Name()) wg.Wait() } - if cfg.ParallelBuilds == 1 { + if cla.ParallelBuilds == 1 { log.Printf("Parallelization disabled, waiting for build to finish: %s", b.Name()) wg.Wait() } From 22a36ef97a2fe40e7c26fdc121f92a22e365640a Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Tue, 12 May 2020 11:24:22 +0200 Subject: [PATCH 25/34] Move vars from Meta to cla args; this forces us to use it in GetConfigFromJSON which in turn forces us into updating console and validate --- command/build.go | 12 ++++++------ command/console.go | 47 ++++++++++++++++++++++++++++++++------------- command/meta.go | 18 +++++++---------- command/validate.go | 32 +++++++++++++++++++++++------- 4 files changed, 72 insertions(+), 37 deletions(-) diff --git a/command/build.go b/command/build.go index 238b8df51..5a9413ba8 100644 --- a/command/build.go +++ b/command/build.go @@ -25,7 +25,7 @@ type BuildCommand struct { } func (c *BuildCommand) Run(args []string) int { - buildCtx, cleanup := handleTermInterrupt(c.Ui) + ctx, cleanup := handleTermInterrupt(c.Ui) defer cleanup() cfg, ret := c.ParseArgs(args) @@ -33,7 +33,7 @@ func (c *BuildCommand) Run(args []string) int { return ret } - return c.RunContext(buildCtx, cfg) + return c.RunContext(ctx, cfg) } func (c *BuildCommand) ParseArgs(args []string) (*BuildArgs, int) { @@ -106,20 +106,20 @@ func (m *Meta) GetConfig(cla *MetaArgs) (packer.BuildGetter, int) { // will continue to work but users are encouraged to move to the new style. // See: https://packer.io/guides/hcl // `) - return m.GetConfigFromJSON(cla.Path) + return m.GetConfigFromJSON(cla) } } -func (m *Meta) GetConfigFromJSON(path string) (packer.BuildGetter, int) { +func (m *Meta) GetConfigFromJSON(cla *MetaArgs) (packer.BuildGetter, int) { // Parse the template - tpl, err := template.ParseFile(path) + tpl, err := template.ParseFile(cla.Path) if err != nil { m.Ui.Error(fmt.Sprintf("Failed to parse template: %s", err)) return nil, 1 } // Get the core - core, err := m.Core(tpl) + core, err := m.Core(tpl, cla) ret := 0 if err != nil { m.Ui.Error(err.Error()) diff --git a/command/console.go b/command/console.go index f63fc3211..2db92e846 100644 --- a/command/console.go +++ b/command/console.go @@ -2,6 +2,7 @@ package command import ( "bufio" + "context" "errors" "fmt" "io" @@ -30,16 +31,40 @@ type ConsoleCommand struct { } func (c *ConsoleCommand) Run(args []string) int { - flags := c.Meta.FlagSet("console", FlagSetVars) - flags.Usage = func() { c.Ui.Say(c.Help()) } - if err := flags.Parse(args); err != nil { - return 1 + ctx, cleanup := handleTermInterrupt(c.Ui) + defer cleanup() + + cfg, ret := c.ParseArgs(args) + if ret != 0 { + return ret } - var templ *template.Template + return c.RunContext(ctx, cfg) +} + +func (c *ConsoleCommand) ParseArgs(args []string) (*ConsoleArgs, int) { + var cfg ConsoleArgs + flags := c.Meta.FlagSet("console", FlagSetVars) + flags.Usage = func() { c.Ui.Say(c.Help()) } + cfg.AddFlagSets(flags) + if err := flags.Parse(args); err != nil { + return &cfg, 1 + } + + if len(args) > 1 { + // User provided too many arguments + flags.Usage() + return &cfg, 1 + } args = flags.Args() - if len(args) < 1 { + return &cfg, 0 +} + +func (c *ConsoleCommand) RunContext(ctx context.Context, cla *ConsoleArgs) int { + + var templ *template.Template + if cla.Path == "" { // If user has not defined a builder, create a tiny null placeholder // builder so that we can properly initialize the core tpl, err := template.Parse(strings.NewReader(TiniestBuilder)) @@ -48,22 +73,18 @@ func (c *ConsoleCommand) Run(args []string) int { return 1 } templ = tpl - } else if len(args) == 1 { + } else { // Parse the provided template - tpl, err := template.ParseFile(args[0]) + tpl, err := template.ParseFile(cla.Path) if err != nil { c.Ui.Error(fmt.Sprintf("Failed to parse template: %s", err)) return 1 } templ = tpl - } else { - // User provided too many arguments - flags.Usage() - return 1 } // Get the core - core, err := c.Meta.Core(templ) + core, err := c.Meta.Core(templ, &cla.MetaArgs) if err != nil { c.Ui.Error(err.Error()) return 1 diff --git a/command/meta.go b/command/meta.go index 6e0543e2c..6f37f14c4 100644 --- a/command/meta.go +++ b/command/meta.go @@ -29,22 +29,18 @@ type Meta struct { CoreConfig *packer.CoreConfig Ui packer.Ui Version string - - // These are set by command-line flags - varFiles []string - flagVars map[string]string } // Core returns the core for the given template given the configured // CoreConfig and user variables on this Meta. -func (m *Meta) Core(tpl *template.Template) (*packer.Core, error) { +func (m *Meta) Core(tpl *template.Template, cla *MetaArgs) (*packer.Core, error) { // Copy the config so we don't modify it config := *m.CoreConfig config.Template = tpl fj := &kvflag.FlagJSON{} // First populate fj with contents from var files - for _, file := range m.varFiles { + for _, file := range cla.VarFiles { err := fj.Set(file) if err != nil { return nil, err @@ -53,15 +49,15 @@ func (m *Meta) Core(tpl *template.Template) (*packer.Core, error) { // Now read fj values back into flagvars and set as config.Variables. Only // add to flagVars if the key doesn't already exist, because flagVars comes // from the command line and should not be overridden by variable files. - if m.flagVars == nil { - m.flagVars = map[string]string{} + if cla.Vars == nil { + cla.Vars = map[string]string{} } for k, v := range *fj { - if _, exists := m.flagVars[k]; !exists { - m.flagVars[k] = v + if _, exists := cla.Vars[k]; !exists { + cla.Vars[k] = v } } - config.Variables = m.flagVars + config.Variables = cla.Vars // Init the core core, err := packer.NewCore(&config) diff --git a/command/validate.go b/command/validate.go index 8f08b44bc..fb6cd324a 100644 --- a/command/validate.go +++ b/command/validate.go @@ -1,6 +1,7 @@ package command import ( + "context" "encoding/json" "fmt" "log" @@ -19,35 +20,52 @@ type ValidateCommand struct { } func (c *ValidateCommand) Run(args []string) int { - var cfgSyntaxOnly bool + ctx, cleanup := handleTermInterrupt(c.Ui) + defer cleanup() + + cfg, ret := c.ParseArgs(args) + if ret != 0 { + return ret + } + + return c.RunContext(ctx, cfg) +} + +func (c *ValidateCommand) ParseArgs(args []string) (*ValidateArgs, int) { + var cfg ValidateArgs + flags := c.Meta.FlagSet("validate", FlagSetBuildFilter|FlagSetVars) flags.Usage = func() { c.Ui.Say(c.Help()) } - flags.BoolVar(&cfgSyntaxOnly, "syntax-only", false, "check syntax only") + cfg.AddFlagSets(flags) if err := flags.Parse(args); err != nil { - return 1 + return &cfg, 1 } args = flags.Args() if len(args) != 1 { flags.Usage() - return 1 + return &cfg, 1 } + cfg.Path = args[0] + return &cfg, 0 +} +func (c *ValidateCommand) RunContext(ctx context.Context, cla *ValidateArgs) int { // Parse the template - tpl, err := template.ParseFile(args[0]) + tpl, err := template.ParseFile(cla.Path) if err != nil { c.Ui.Error(fmt.Sprintf("Failed to parse template: %s", err)) return 1 } // If we're only checking syntax, then we're done already - if cfgSyntaxOnly { + if cla.SyntaxOnly { c.Ui.Say("Syntax-only check passed. Everything looks okay.") return 0 } // Get the core - core, err := c.Meta.Core(tpl) + core, err := c.Meta.Core(tpl, &cla.MetaArgs) if err != nil { c.Ui.Error(err.Error()) return 1 From 14f18f42364be53b1e3b4e48e6d9f0923092411f Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Tue, 12 May 2020 11:29:09 +0200 Subject: [PATCH 26/34] dont catch signals in console, as it seems unecessary for now --- command/console.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/command/console.go b/command/console.go index 2db92e846..eeeba14d4 100644 --- a/command/console.go +++ b/command/console.go @@ -31,8 +31,7 @@ type ConsoleCommand struct { } func (c *ConsoleCommand) Run(args []string) int { - ctx, cleanup := handleTermInterrupt(c.Ui) - defer cleanup() + ctx := context.Background() cfg, ret := c.ParseArgs(args) if ret != 0 { From 49c2a8cb1759140ddeaf831b97d827637cb202c7 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Tue, 12 May 2020 11:33:44 +0200 Subject: [PATCH 27/34] update fix command with new synthax --- command/fix.go | 67 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/command/fix.go b/command/fix.go index 8b33fa895..7e382eed9 100644 --- a/command/fix.go +++ b/command/fix.go @@ -2,6 +2,7 @@ package command import ( "bytes" + "context" "encoding/json" "fmt" "log" @@ -19,22 +20,38 @@ type FixCommand struct { } func (c *FixCommand) Run(args []string) int { - var flagValidate bool + ctx, cleanup := handleTermInterrupt(c.Ui) + defer cleanup() + + cfg, ret := c.ParseArgs(args) + if ret != 0 { + return ret + } + + return c.RunContext(ctx, cfg) +} + +func (c *FixCommand) ParseArgs(args []string) (*FixArgs, int) { + var cfg FixArgs flags := c.Meta.FlagSet("fix", FlagSetNone) - flags.BoolVar(&flagValidate, "validate", true, "") flags.Usage = func() { c.Ui.Say(c.Help()) } + cfg.AddFlagSets(flags) if err := flags.Parse(args); err != nil { - return 1 + return &cfg, 1 } args = flags.Args() if len(args) != 1 { flags.Usage() - return 1 + return &cfg, 1 } + cfg.Path = args[0] + return &cfg, 0 +} +func (c *FixCommand) RunContext(ctx context.Context, cla *FixArgs) int { // Read the file for decoding - tplF, err := os.Open(args[0]) + tplF, err := os.Open(cla.Path) if err != nil { c.Ui.Error(fmt.Sprintf("Error opening template: %s", err)) return 1 @@ -86,25 +103,27 @@ func (c *FixCommand) Run(args []string) int { result = strings.Replace(result, `\u003e`, ">", -1) c.Ui.Say(result) - if flagValidate { - // Attempt to parse and validate the template - tpl, err := template.Parse(strings.NewReader(result)) - if err != nil { - c.Ui.Error(fmt.Sprintf( - "Error! Fixed template fails to parse: %s\n\n"+ - "This is usually caused by an error in the input template.\n"+ - "Please fix the error and try again.", - err)) - return 1 - } - if err := tpl.Validate(); err != nil { - c.Ui.Error(fmt.Sprintf( - "Error! Fixed template failed to validate: %s\n\n"+ - "This is usually caused by an error in the input template.\n"+ - "Please fix the error and try again.", - err)) - return 1 - } + if cla.Validate == false { + return 0 + } + + // Attempt to parse and validate the template + tpl, err := template.Parse(strings.NewReader(result)) + if err != nil { + c.Ui.Error(fmt.Sprintf( + "Error! Fixed template fails to parse: %s\n\n"+ + "This is usually caused by an error in the input template.\n"+ + "Please fix the error and try again.", + err)) + return 1 + } + if err := tpl.Validate(); err != nil { + c.Ui.Error(fmt.Sprintf( + "Error! Fixed template failed to validate: %s\n\n"+ + "This is usually caused by an error in the input template.\n"+ + "Please fix the error and try again.", + err)) + return 1 } return 0 From 77297e49e90e754f509b3a81c33a9365fd31da08 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Tue, 12 May 2020 12:07:02 +0200 Subject: [PATCH 28/34] Update cli.go --- command/cli.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/command/cli.go b/command/cli.go index b10ce4153..75a712017 100644 --- a/command/cli.go +++ b/command/cli.go @@ -95,7 +95,7 @@ type FixArgs struct { } func (va *ValidateArgs) AddFlagSets(flags *flag.FlagSet) { - flags.BoolVar(&va.SyntaxOnly, "syntax-only", true, "") + flags.BoolVar(&va.SyntaxOnly, "syntax-only", false, "check syntax only") va.MetaArgs.AddFlagSets(flags) } From 7ca0a80a86df0dfdd50f4e4b41f9e5a06b15c0fe Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Tue, 12 May 2020 12:14:30 +0200 Subject: [PATCH 29/34] remove Ui from command.MetaArgs --- command/cli.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/command/cli.go b/command/cli.go index 75a712017..bbd555d18 100644 --- a/command/cli.go +++ b/command/cli.go @@ -8,7 +8,6 @@ import ( "github.com/hashicorp/packer/helper/enumflag" kvflag "github.com/hashicorp/packer/helper/flag-kv" sliceflag "github.com/hashicorp/packer/helper/flag-slice" - "github.com/hashicorp/packer/packer" ) // ConfigType tells what type of config we should use, it can return values @@ -53,7 +52,6 @@ type MetaArgs struct { Only, Except []string Vars map[string]string VarFiles []string - Ui packer.Ui } func (ba *BuildArgs) AddFlagSets(flags *flag.FlagSet) { From 466358a13ee93e439da240b88ab940aea8100f52 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Tue, 12 May 2020 12:17:00 +0200 Subject: [PATCH 30/34] Delete command.go --- command/command.go | 1 - 1 file changed, 1 deletion(-) delete mode 100644 command/command.go diff --git a/command/command.go b/command/command.go deleted file mode 100644 index d47dcf0d9..000000000 --- a/command/command.go +++ /dev/null @@ -1 +0,0 @@ -package command From d34cecc66811df8b73e930174a3c09b856305c85 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Tue, 12 May 2020 12:29:31 +0200 Subject: [PATCH 31/34] Update new_stuff.go --- packer/new_stuff.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packer/new_stuff.go b/packer/new_stuff.go index baede1edf..a7c79ff58 100644 --- a/packer/new_stuff.go +++ b/packer/new_stuff.go @@ -9,7 +9,8 @@ type GetBuildsOptions struct { } type BuildGetter interface { - // GetBuilds return all possible builds for a config. It also starts them. + // GetBuilds return all possible builds for a config. It also starts all + // builders. // TODO(azr): rename to builder starter ? GetBuilds(GetBuildsOptions) ([]Build, hcl.Diagnostics) } @@ -19,15 +20,20 @@ type FixConfigMode int const ( Stdout FixConfigMode = iota + // Inplace fixes your files on the spot. Inplace + // Diff shows a full diff. Diff + // SimpleOutput will simply print what the config should be; it will only + // work when a single file is passed. + SimpleOutput ) type FixConfigOptions struct { DiffOnly bool } -type OtherInterfaceyMacOtherInterfaceFace interface { +type ConfigFixer interface { // FixConfig will output the config in a fixed manner. FixConfig(FixConfigOptions) hcl.Diagnostics } From d147ebe79f2337d5e68bcd4964a6a07e5de76a8d Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Tue, 12 May 2020 12:31:05 +0200 Subject: [PATCH 32/34] packer/new_stuff.go => packer/run_interfaces.go --- packer/{new_stuff.go => run_interfaces.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packer/{new_stuff.go => run_interfaces.go} (100%) diff --git a/packer/new_stuff.go b/packer/run_interfaces.go similarity index 100% rename from packer/new_stuff.go rename to packer/run_interfaces.go From 52b2151b21b362833257df7e04f8c6ad50501628 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Tue, 12 May 2020 13:03:43 +0200 Subject: [PATCH 33/34] go generate ./packer --- CHANGELOG.md | 2 ++ command/build.go | 3 +-- packer/run_interfaces.go | 5 ++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e23cd8679..20e0a5894 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ### BACKWARDS INCOMPATIBILITIES: * core/hcl2: Maps are now treated as settable arguments as opposed to blocks. For example `tags = {}` instead of `tags {}` [GH-9035] +* `packer build` command: removed option to set `parallel=false`, use + `-parallel-builds=1` for this. ### FEATURES: * **New Builder** azure-dtl allows creation of devtestlabs images in Azure diff --git a/command/build.go b/command/build.go index 5a9413ba8..d77dd1da8 100644 --- a/command/build.go +++ b/command/build.go @@ -374,8 +374,7 @@ Options: -force Force a build to continue if artifacts exist, deletes existing artifacts. -machine-readable Produce machine-readable output. -on-error=[cleanup|abort|ask] If the build fails do: clean up (default), abort, or ask. - -parallel-builds=1 Disable parallelization. (Default: true) - -parallel-builds=1 Number of builds to run in parallel. 0 means no limit (Default: 0) + -parallel-builds=1 Number of builds to run in parallel. 1 disables parallelization. 0 means no limit (Default: 0) -timestamp-ui Enable prefixing of each ui output with an RFC3339 timestamp. -var 'key=value' Variable for templates, can be used multiple times. -var-file=path JSON file containing user variables. [ Note that even in HCL mode this expects file to contain JSON, a fix is comming soon ] diff --git a/packer/run_interfaces.go b/packer/run_interfaces.go index a7c79ff58..8403a0b53 100644 --- a/packer/run_interfaces.go +++ b/packer/run_interfaces.go @@ -19,14 +19,13 @@ type BuildGetter interface { type FixConfigMode int const ( + // Stdout will make FixConfig simply print what the config should be; it + // will only work when a single file is passed. Stdout FixConfigMode = iota // Inplace fixes your files on the spot. Inplace // Diff shows a full diff. Diff - // SimpleOutput will simply print what the config should be; it will only - // work when a single file is passed. - SimpleOutput ) type FixConfigOptions struct { From 2f26168adc3f0f8db923de8759497f688c953e20 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Thu, 14 May 2020 12:21:42 +0200 Subject: [PATCH 34/34] ConsoleCommand.ParseArgs: don't fail if no buildfile was passed --- command/console.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/command/console.go b/command/console.go index eeeba14d4..79609520f 100644 --- a/command/console.go +++ b/command/console.go @@ -50,12 +50,6 @@ func (c *ConsoleCommand) ParseArgs(args []string) (*ConsoleArgs, int) { return &cfg, 1 } - if len(args) > 1 { - // User provided too many arguments - flags.Usage() - return &cfg, 1 - } - args = flags.Args() return &cfg, 0 }