Merge pull request #9139 from hashicorp/hcl2_commands_refactor
Hcl2 commands refactor
This commit is contained in:
commit
533fbc1381
|
@ -39,6 +39,8 @@
|
|||
the service names things [GH-9078]
|
||||
* 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
|
||||
|
|
214
command/build.go
214
command/build.go
|
@ -6,17 +6,13 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"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"
|
||||
|
@ -29,60 +25,26 @@ 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():
|
||||
}
|
||||
}()
|
||||
ctx, cleanup := handleTermInterrupt(c.Ui)
|
||||
defer cleanup()
|
||||
|
||||
return c.RunContext(buildCtx, args)
|
||||
cfg, ret := c.ParseArgs(args)
|
||||
if ret != 0 {
|
||||
return ret
|
||||
}
|
||||
|
||||
return c.RunContext(ctx, 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
|
||||
return &cfg, 1
|
||||
}
|
||||
|
||||
if parallel == false && cfg.ParallelBuilds == 0 {
|
||||
cfg.ParallelBuilds = 1
|
||||
}
|
||||
if cfg.ParallelBuilds < 1 {
|
||||
cfg.ParallelBuilds = math.MaxInt64
|
||||
}
|
||||
|
@ -90,101 +52,98 @@ func (c *BuildCommand) ParseArgs(args []string) (Config, 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 (c *BuildCommand) GetBuildsFromHCL(path string) ([]packer.Build, int) {
|
||||
func (m *Meta) GetConfigFromHCL(cla *MetaArgs) (packer.BuildGetter, 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,
|
||||
}
|
||||
|
||||
builds, diags := parser.Parse(path, c.varFiles, c.flagVars, 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
|
||||
cfg, diags := parser.Parse(cla.Path, cla.VarFiles, cla.Vars)
|
||||
return cfg, writeDiags(m.Ui, parser.Files(), diags)
|
||||
}
|
||||
|
||||
func (c *BuildCommand) GetBuilds(path string) ([]packer.Build, int) {
|
||||
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() {
|
||||
ui.Error(b.String())
|
||||
return 1
|
||||
}
|
||||
ui.Say(b.String())
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
isHCLLoaded, err := isHCLLoaded(path)
|
||||
if path != "-" && err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("could not tell whether %s is hcl enabled: %s", path, err))
|
||||
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
|
||||
}
|
||||
if isHCLLoaded {
|
||||
return c.GetBuildsFromHCL(path)
|
||||
|
||||
switch cfgType {
|
||||
case "hcl":
|
||||
// TODO(azr): allow to pass a slice of files here.
|
||||
return m.GetConfigFromHCL(cla)
|
||||
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(cla)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: uncomment in v1.5.1 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
|
||||
// `)
|
||||
|
||||
func (m *Meta) GetConfigFromJSON(cla *MetaArgs) (packer.BuildGetter, int) {
|
||||
// Parse the template
|
||||
var tpl *template.Template
|
||||
tpl, err = template.ParseFile(path)
|
||||
tpl, err := template.ParseFile(cla.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)
|
||||
if err != nil {
|
||||
c.Ui.Error(err.Error())
|
||||
return nil, 1
|
||||
}
|
||||
|
||||
core, err := m.Core(tpl, cla)
|
||||
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)
|
||||
if err != nil {
|
||||
m.Ui.Error(err.Error())
|
||||
ret = 1
|
||||
}
|
||||
return builds, ret
|
||||
return core, ret
|
||||
}
|
||||
|
||||
func (c *BuildCommand) RunContext(buildCtx context.Context, args []string) int {
|
||||
cfg, ret := c.ParseArgs(args)
|
||||
func (c *BuildCommand) RunContext(buildCtx context.Context, cla *BuildArgs) int {
|
||||
packerStarter, ret := c.GetConfig(&cla.MetaArgs)
|
||||
if ret != 0 {
|
||||
return ret
|
||||
}
|
||||
|
||||
builds, ret := c.GetBuilds(cfg.Path)
|
||||
builds, diags := packerStarter.GetBuilds(packer.GetBuildsOptions{
|
||||
Only: cla.Only,
|
||||
Except: cla.Except,
|
||||
})
|
||||
|
||||
if cfg.Debug {
|
||||
// here, something could have gone wrong but we still want to run valid
|
||||
// builds.
|
||||
ret = writeDiags(c.Ui, nil, diags)
|
||||
|
||||
if cla.Debug {
|
||||
c.Ui.Say("Debug mode enabled. Builds will not be parallelized.")
|
||||
}
|
||||
|
||||
|
@ -199,7 +158,7 @@ func (c *BuildCommand) RunContext(buildCtx context.Context, args []string) 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,
|
||||
|
@ -213,7 +172,7 @@ func (c *BuildCommand) RunContext(buildCtx context.Context, args []string) int {
|
|||
}
|
||||
}
|
||||
// Now add timestamps if requested
|
||||
if cfg.Timestamp {
|
||||
if cla.TimestampUi {
|
||||
ui = &packer.TimestampedUi{
|
||||
Ui: ui,
|
||||
}
|
||||
|
@ -222,17 +181,17 @@ func (c *BuildCommand) RunContext(buildCtx context.Context, args []string) 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 {
|
||||
|
@ -260,7 +219,7 @@ func (c *BuildCommand) RunContext(buildCtx context.Context, args []string) 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.")
|
||||
|
@ -304,12 +263,12 @@ func (c *BuildCommand) RunContext(buildCtx context.Context, args []string) 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()
|
||||
}
|
||||
|
@ -415,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=false 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.
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
|
@ -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
|
||||
|
|
|
@ -11,7 +11,7 @@ func TestBuildWithCleanupScript(t *testing.T) {
|
|||
}
|
||||
|
||||
args := []string{
|
||||
"-parallel=false",
|
||||
"-parallel-builds=1",
|
||||
filepath.Join(testFixture("cleanup-script"), "template.json"),
|
||||
}
|
||||
|
||||
|
|
|
@ -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"),
|
||||
}
|
||||
|
||||
|
|
|
@ -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"),
|
||||
}
|
||||
|
@ -630,31 +630,31 @@ 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,
|
||||
},
|
||||
0,
|
||||
},
|
||||
{fields{defaultMeta},
|
||||
args{[]string{"-parallel=true", "file.json"}},
|
||||
Config{
|
||||
Path: "file.json",
|
||||
ParallelBuilds: math.MaxInt64,
|
||||
args{[]string{"-parallel-builds=10", "file.json"}},
|
||||
&BuildArgs{
|
||||
MetaArgs: MetaArgs{Path: "file.json"},
|
||||
ParallelBuilds: 10,
|
||||
Color: true,
|
||||
},
|
||||
0,
|
||||
},
|
||||
{fields{defaultMeta},
|
||||
args{[]string{"-parallel=false", "file.json"}},
|
||||
Config{
|
||||
Path: "file.json",
|
||||
args{[]string{"-parallel-builds=1", "file.json"}},
|
||||
&BuildArgs{
|
||||
MetaArgs: MetaArgs{Path: "file.json"},
|
||||
ParallelBuilds: 1,
|
||||
Color: true,
|
||||
},
|
||||
|
@ -662,17 +662,17 @@ 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,
|
||||
},
|
||||
0,
|
||||
},
|
||||
{fields{defaultMeta},
|
||||
args{[]string{"-parallel=false", "-parallel-builds=5", "otherfile.json"}},
|
||||
Config{
|
||||
Path: "otherfile.json",
|
||||
args{[]string{"-parallel-builds=1", "-parallel-builds=5", "otherfile.json"}},
|
||||
&BuildArgs{
|
||||
MetaArgs: MetaArgs{Path: "otherfile.json"},
|
||||
ParallelBuilds: 5,
|
||||
Color: true,
|
||||
},
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/packer/helper/enumflag"
|
||||
kvflag "github.com/hashicorp/packer/helper/flag-kv"
|
||||
sliceflag "github.com/hashicorp/packer/helper/flag-slice"
|
||||
)
|
||||
|
||||
// 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 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.
|
||||
case 1:
|
||||
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
|
||||
}
|
||||
isDir, err := isDir(name)
|
||||
if isDir {
|
||||
return "hcl", err
|
||||
}
|
||||
return "json", err
|
||||
default:
|
||||
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 {
|
||||
Path 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)
|
||||
}
|
||||
|
||||
// BuildArgs represents a parsed cli line for a `packer build`
|
||||
type BuildArgs struct {
|
||||
MetaArgs
|
||||
Color, Debug, Force, TimestampUi, MachineReadable bool
|
||||
ParallelBuilds int64
|
||||
OnError string
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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", false, "check syntax only")
|
||||
|
||||
va.MetaArgs.AddFlagSets(flags)
|
||||
}
|
||||
|
||||
// ValidateArgs represents a parsed cli line for a `packer validate`
|
||||
type ValidateArgs struct {
|
||||
MetaArgs
|
||||
SyntaxOnly bool
|
||||
}
|
|
@ -2,6 +2,7 @@ package command
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
@ -30,16 +31,33 @@ 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 := context.Background()
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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 +66,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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
@ -30,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
|
||||
|
@ -54,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)
|
||||
|
@ -73,54 +68,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
|
||||
|
@ -128,19 +75,6 @@ func (m *Meta) BuildNames(c *packer.Core) []string {
|
|||
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
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
|
@ -57,7 +75,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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
@ -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(packer.GetBuildsOptions{})
|
||||
if tt.getBuildsWantDiags == (gotDiags == nil) {
|
||||
t.Fatalf("Parser.getBuilds() unexpected diagnostics. %s", gotDiags)
|
||||
}
|
||||
|
|
|
@ -52,7 +52,15 @@ const (
|
|||
hcl2VarJsonFileExt = ".auto.pkrvars.json"
|
||||
)
|
||||
|
||||
func (p *Parser) parse(filename string, varFiles []string, argVars map[string]string) (*PackerConfig, hcl.Diagnostics) {
|
||||
// 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
|
||||
var diags hcl.Diagnostics
|
||||
|
@ -89,7 +97,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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -7,13 +7,13 @@ 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
|
||||
// references to all possible blocks of the allowed configuration.
|
||||
type PackerConfig struct {
|
||||
// parser *Parser
|
||||
|
||||
// Directory where the config files are defined
|
||||
Basedir string
|
||||
|
||||
|
@ -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
|
||||
|
@ -247,10 +253,10 @@ func (p *Parser) getCoreBuildPostProcessors(source *SourceBlock, blocks []*PostP
|
|||
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 (p *Parser) getBuilds(cfg *PackerConfig, onlyGlobs []glob.Glob, exceptGlobs []glob.Glob) ([]packer.Build, hcl.Diagnostics) {
|
||||
func (cfg *PackerConfig) GetBuilds(opts packer.GetBuildsOptions) ([]packer.Build, hcl.Diagnostics) {
|
||||
res := []packer.Build{}
|
||||
var diags hcl.Diagnostics
|
||||
|
||||
|
@ -270,7 +276,11 @@ func (p *Parser) getBuilds(cfg *PackerConfig, onlyGlobs []glob.Glob, exceptGlobs
|
|||
buildName := fmt.Sprintf("%s.%s", src.Type, src.Name)
|
||||
|
||||
// -only
|
||||
if len(onlyGlobs) > 0 {
|
||||
if len(opts.Only) > 0 {
|
||||
onlyGlobs, diags := convertFilterOption(opts.Only, "only")
|
||||
if diags.HasErrors() {
|
||||
return nil, diags
|
||||
}
|
||||
include := false
|
||||
for _, onlyGlob := range onlyGlobs {
|
||||
if onlyGlob.Match(buildName) {
|
||||
|
@ -284,7 +294,11 @@ func (p *Parser) getBuilds(cfg *PackerConfig, onlyGlobs []glob.Glob, exceptGlobs
|
|||
}
|
||||
|
||||
// -except
|
||||
if len(exceptGlobs) > 0 {
|
||||
if len(opts.Except) > 0 {
|
||||
exceptGlobs, diags := convertFilterOption(opts.Except, "except")
|
||||
if diags.HasErrors() {
|
||||
return nil, diags
|
||||
}
|
||||
exclude := false
|
||||
for _, exceptGlob := range exceptGlobs {
|
||||
if exceptGlob.Match(buildName) {
|
||||
|
@ -297,7 +311,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 +337,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}
|
||||
|
@ -350,60 +364,3 @@ func (p *Parser) getBuilds(cfg *PackerConfig, onlyGlobs []glob.Glob, exceptGlobs
|
|||
}
|
||||
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 := p.getBuilds(cfg, onlyGlobs, exceptGlobs)
|
||||
return builds, append(diags, moreDiags...)
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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"
|
||||
)
|
||||
|
@ -126,9 +127,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)
|
||||
|
@ -185,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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
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 Only. When those are empty everything matches.
|
||||
Except, Only []string
|
||||
}
|
||||
|
||||
type BuildGetter interface {
|
||||
// GetBuilds return all possible builds for a config. It also starts all
|
||||
// builders.
|
||||
// TODO(azr): rename to builder starter ?
|
||||
GetBuilds(GetBuildsOptions) ([]Build, hcl.Diagnostics)
|
||||
}
|
||||
|
||||
//go:generate enumer -type FixConfigMode
|
||||
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
|
||||
)
|
||||
|
||||
type FixConfigOptions struct {
|
||||
DiffOnly bool
|
||||
}
|
||||
|
||||
type ConfigFixer interface {
|
||||
// FixConfig will output the config in a fixed manner.
|
||||
FixConfig(FixConfigOptions) hcl.Diagnostics
|
||||
}
|
|
@ -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).
|
||||
|
||||
|
|
Loading…
Reference in New Issue