2025-11-30 18:32:15 +00:00
|
|
|
// Copyright IBM Corp. 2013, 2025
|
2023-08-10 15:53:29 -07:00
|
|
|
// SPDX-License-Identifier: BUSL-1.1
|
2023-03-02 15:37:05 -05:00
|
|
|
|
2014-10-27 20:21:13 -07:00
|
|
|
package command
|
|
|
|
|
|
|
|
|
|
import (
|
2015-05-23 16:30:45 -07:00
|
|
|
"bufio"
|
|
|
|
|
"flag"
|
2022-07-26 09:30:30 -04:00
|
|
|
"fmt"
|
2015-05-23 16:30:45 -07:00
|
|
|
"io"
|
2019-06-06 10:52:12 -07:00
|
|
|
"os"
|
2015-05-23 16:30:45 -07:00
|
|
|
|
2022-07-26 09:30:30 -04:00
|
|
|
"github.com/hashicorp/hcl/v2/hclparse"
|
2020-12-17 13:29:25 -08:00
|
|
|
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
|
|
|
|
"github.com/hashicorp/packer-plugin-sdk/template"
|
2020-11-16 14:23:35 -08:00
|
|
|
kvflag "github.com/hashicorp/packer/command/flag-kv"
|
2022-07-26 09:30:30 -04:00
|
|
|
"github.com/hashicorp/packer/hcl2template"
|
2020-04-09 14:38:17 -07:00
|
|
|
"github.com/hashicorp/packer/helper/wrappedstreams"
|
2017-04-04 13:39:01 -07:00
|
|
|
"github.com/hashicorp/packer/packer"
|
2022-07-26 09:30:30 -04:00
|
|
|
"github.com/hashicorp/packer/version"
|
2015-05-23 16:30:45 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Meta contains the meta-options and functionality that nearly every
|
|
|
|
|
// Packer command inherits.
|
2014-10-27 20:21:13 -07:00
|
|
|
type Meta struct {
|
2015-05-23 16:30:45 -07:00
|
|
|
CoreConfig *packer.CoreConfig
|
2020-11-19 11:54:31 -08:00
|
|
|
Ui packersdk.Ui
|
2015-06-29 11:49:45 -07:00
|
|
|
Version string
|
2015-05-23 16:30:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Core returns the core for the given template given the configured
|
|
|
|
|
// CoreConfig and user variables on this Meta.
|
2020-05-12 11:24:22 +02:00
|
|
|
func (m *Meta) Core(tpl *template.Template, cla *MetaArgs) (*packer.Core, error) {
|
2015-05-23 16:30:45 -07:00
|
|
|
// Copy the config so we don't modify it
|
|
|
|
|
config := *m.CoreConfig
|
|
|
|
|
config.Template = tpl
|
2020-03-12 14:27:56 +01:00
|
|
|
|
|
|
|
|
fj := &kvflag.FlagJSON{}
|
2020-03-30 01:31:59 -07:00
|
|
|
// First populate fj with contents from var files
|
2020-05-12 11:24:22 +02:00
|
|
|
for _, file := range cla.VarFiles {
|
2020-03-12 14:27:56 +01:00
|
|
|
err := fj.Set(file)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-03-30 01:31:59 -07:00
|
|
|
// 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.
|
2020-05-12 11:24:22 +02:00
|
|
|
if cla.Vars == nil {
|
|
|
|
|
cla.Vars = map[string]string{}
|
2020-03-19 13:57:22 +01:00
|
|
|
}
|
2020-03-12 14:27:56 +01:00
|
|
|
for k, v := range *fj {
|
2020-05-12 11:24:22 +02:00
|
|
|
if _, exists := cla.Vars[k]; !exists {
|
|
|
|
|
cla.Vars[k] = v
|
2020-03-30 01:31:59 -07:00
|
|
|
}
|
2020-03-12 14:27:56 +01:00
|
|
|
}
|
2020-05-12 11:24:22 +02:00
|
|
|
config.Variables = cla.Vars
|
2015-05-23 16:30:45 -07:00
|
|
|
|
2020-07-24 10:58:03 +02:00
|
|
|
core := packer.NewCore(&config)
|
2015-05-23 16:30:45 -07:00
|
|
|
return core, nil
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-06 10:48:31 -04:00
|
|
|
// FlagSet returns a FlagSet with Packer SDK Ui support built-in
|
|
|
|
|
func (m *Meta) FlagSet(n string) *flag.FlagSet {
|
2015-05-23 16:30:45 -07:00
|
|
|
f := flag.NewFlagSet(n, flag.ContinueOnError)
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
// to the UI. Do this forever.
|
|
|
|
|
errR, errW := io.Pipe()
|
|
|
|
|
errScanner := bufio.NewScanner(errR)
|
|
|
|
|
go func() {
|
|
|
|
|
for errScanner.Scan() {
|
|
|
|
|
m.Ui.Error(errScanner.Text())
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
f.SetOutput(errW)
|
|
|
|
|
|
|
|
|
|
return f
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ValidateFlags should be called after parsing flags to validate the
|
|
|
|
|
// given flags
|
|
|
|
|
func (m *Meta) ValidateFlags() error {
|
|
|
|
|
// TODO
|
|
|
|
|
return nil
|
2014-10-27 20:21:13 -07:00
|
|
|
}
|
2019-06-06 10:52:12 -07:00
|
|
|
|
|
|
|
|
// StdinPiped returns true if the input is piped.
|
|
|
|
|
func (m *Meta) StdinPiped() bool {
|
2020-04-09 14:38:17 -07:00
|
|
|
fi, err := wrappedstreams.Stdin().Stat()
|
2019-06-06 10:52:12 -07:00
|
|
|
if err != nil {
|
|
|
|
|
// If there is an error, let's just say its not piped
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fi.Mode()&os.ModeNamedPipe != 0
|
|
|
|
|
}
|
2022-07-26 09:30:30 -04:00
|
|
|
|
|
|
|
|
func (m *Meta) GetConfig(cla *MetaArgs) (packer.Handler, int) {
|
|
|
|
|
cfgType, err := cla.GetConfigType()
|
|
|
|
|
if err != nil {
|
|
|
|
|
m.Ui.Error(fmt.Sprintf("%q: %s", cla.Path, err))
|
|
|
|
|
return nil, 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch cfgType {
|
|
|
|
|
case ConfigTypeHCL2:
|
2023-03-20 10:13:04 -04:00
|
|
|
packer.CheckpointReporter.SetTemplateType(packer.HCL2Template)
|
2022-07-26 09:30:30 -04:00
|
|
|
// TODO(azr): allow to pass a slice of files here.
|
|
|
|
|
return m.GetConfigFromHCL(cla)
|
|
|
|
|
default:
|
2023-03-20 10:13:04 -04:00
|
|
|
packer.CheckpointReporter.SetTemplateType(packer.JSONTemplate)
|
2022-07-26 09:30:30 -04:00
|
|
|
// 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)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (m *Meta) GetConfigFromHCL(cla *MetaArgs) (*hcl2template.PackerConfig, int) {
|
|
|
|
|
parser := &hcl2template.Parser{
|
|
|
|
|
CorePackerVersion: version.SemVer,
|
|
|
|
|
CorePackerVersionString: version.FormattedVersion(),
|
|
|
|
|
Parser: hclparse.NewParser(),
|
|
|
|
|
PluginConfig: m.CoreConfig.Components.PluginConfig,
|
2022-11-14 17:06:45 -05:00
|
|
|
ValidationOptions: hcl2template.ValidationOptions{
|
|
|
|
|
WarnOnUndeclaredVar: cla.WarnOnUndeclaredVar,
|
|
|
|
|
},
|
2022-07-26 09:30:30 -04:00
|
|
|
}
|
|
|
|
|
cfg, diags := parser.Parse(cla.Path, cla.VarFiles, cla.Vars)
|
|
|
|
|
return cfg, writeDiags(m.Ui, parser.Files(), diags)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (m *Meta) GetConfigFromJSON(cla *MetaArgs) (packer.Handler, int) {
|
|
|
|
|
// Parse the template
|
|
|
|
|
var tpl *template.Template
|
|
|
|
|
var err error
|
|
|
|
|
if cla.Path == "" {
|
|
|
|
|
// here cla validation passed so this means we want a default builder
|
|
|
|
|
// and we probably are in the console command
|
|
|
|
|
tpl, err = template.Parse(TiniestBuilder)
|
|
|
|
|
} else {
|
|
|
|
|
tpl, err = template.ParseFile(cla.Path)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
m.Ui.Error(fmt.Sprintf("Failed to parse file as legacy JSON template: "+
|
|
|
|
|
"if you are using an HCL template, check your file extensions; they "+
|
|
|
|
|
"should be either *.pkr.hcl or *.pkr.json; see the docs for more "+
|
|
|
|
|
"details: https://www.packer.io/docs/templates/hcl_templates. \n"+
|
|
|
|
|
"Original error: %s", err))
|
|
|
|
|
return nil, 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get the core
|
|
|
|
|
core, err := m.Core(tpl, cla)
|
|
|
|
|
ret := 0
|
|
|
|
|
if err != nil {
|
|
|
|
|
m.Ui.Error(err.Error())
|
|
|
|
|
ret = 1
|
|
|
|
|
}
|
2022-09-06 17:26:49 -04:00
|
|
|
return core, ret
|
2022-07-26 09:30:30 -04:00
|
|
|
}
|