simplify/refactor core for build & validate

This commit is contained in:
Adrien Delorme 2020-04-30 16:36:01 +02:00
parent 7aaee62970
commit c71a792186
4 changed files with 83 additions and 97 deletions

View file

@ -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.")

View file

@ -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

View file

@ -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)

View file

@ -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)