2014-10-27 23:34:49 -04:00
|
|
|
package command
|
2013-07-14 02:29:19 -04:00
|
|
|
|
|
|
|
import (
|
2013-07-14 04:05:26 -04:00
|
|
|
"bytes"
|
2013-07-14 02:29:19 -04:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2013-08-08 20:12:04 -04:00
|
|
|
"log"
|
2013-07-14 02:29:19 -04:00
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
|
2017-04-04 16:39:01 -04:00
|
|
|
"github.com/hashicorp/packer/fix"
|
|
|
|
"github.com/hashicorp/packer/template"
|
2014-10-27 23:34:49 -04:00
|
|
|
)
|
2013-07-14 02:29:19 -04:00
|
|
|
|
2014-10-27 23:34:49 -04:00
|
|
|
type FixCommand struct {
|
|
|
|
Meta
|
2013-07-14 02:29:19 -04:00
|
|
|
}
|
|
|
|
|
2014-10-27 23:34:49 -04:00
|
|
|
func (c *FixCommand) Run(args []string) int {
|
2015-06-13 13:56:09 -04:00
|
|
|
var flagValidate bool
|
2015-05-25 20:29:10 -04:00
|
|
|
flags := c.Meta.FlagSet("fix", FlagSetNone)
|
2015-06-13 13:56:09 -04:00
|
|
|
flags.BoolVar(&flagValidate, "validate", true, "")
|
2015-05-25 20:29:10 -04:00
|
|
|
flags.Usage = func() { c.Ui.Say(c.Help()) }
|
|
|
|
if err := flags.Parse(args); err != nil {
|
2013-07-14 02:29:19 -04:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
2015-05-25 20:29:10 -04:00
|
|
|
args = flags.Args()
|
2013-07-14 02:29:19 -04:00
|
|
|
if len(args) != 1 {
|
2015-05-25 20:29:10 -04:00
|
|
|
flags.Usage()
|
2013-07-14 02:29:19 -04:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read the file for decoding
|
|
|
|
tplF, err := os.Open(args[0])
|
|
|
|
if err != nil {
|
2015-05-25 20:29:10 -04:00
|
|
|
c.Ui.Error(fmt.Sprintf("Error opening template: %s", err))
|
2013-07-14 02:29:19 -04:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
defer tplF.Close()
|
|
|
|
|
|
|
|
// Decode the JSON into a generic map structure
|
|
|
|
var templateData map[string]interface{}
|
|
|
|
decoder := json.NewDecoder(tplF)
|
|
|
|
if err := decoder.Decode(&templateData); err != nil {
|
2015-05-25 20:29:10 -04:00
|
|
|
c.Ui.Error(fmt.Sprintf("Error parsing template: %s", err))
|
2013-07-14 02:29:19 -04:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close the file since we're done with that
|
|
|
|
tplF.Close()
|
|
|
|
|
2013-07-14 04:05:26 -04:00
|
|
|
input := templateData
|
2014-10-27 23:34:49 -04:00
|
|
|
for _, name := range fix.FixerOrder {
|
2013-07-14 04:05:26 -04:00
|
|
|
var err error
|
2014-10-27 23:34:49 -04:00
|
|
|
fixer, ok := fix.Fixers[name]
|
2013-08-08 20:11:39 -04:00
|
|
|
if !ok {
|
|
|
|
panic("fixer not found: " + name)
|
|
|
|
}
|
|
|
|
|
2013-08-08 20:12:04 -04:00
|
|
|
log.Printf("Running fixer: %s", name)
|
2013-07-14 04:05:26 -04:00
|
|
|
input, err = fixer.Fix(input)
|
|
|
|
if err != nil {
|
2015-05-25 20:29:10 -04:00
|
|
|
c.Ui.Error(fmt.Sprintf("Error fixing: %s", err))
|
2013-07-14 04:05:26 -04:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var output bytes.Buffer
|
|
|
|
encoder := json.NewEncoder(&output)
|
|
|
|
if err := encoder.Encode(input); err != nil {
|
2015-05-25 20:29:10 -04:00
|
|
|
c.Ui.Error(fmt.Sprintf("Error encoding: %s", err))
|
2013-07-14 04:05:26 -04:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
var indented bytes.Buffer
|
|
|
|
if err := json.Indent(&indented, output.Bytes(), "", " "); err != nil {
|
2015-05-25 20:29:10 -04:00
|
|
|
c.Ui.Error(fmt.Sprintf("Error encoding: %s", err))
|
2013-07-14 04:05:26 -04:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
2013-07-14 04:10:50 -04:00
|
|
|
result := indented.String()
|
|
|
|
result = strings.Replace(result, `\u003c`, "<", -1)
|
|
|
|
result = strings.Replace(result, `\u003e`, ">", -1)
|
2015-05-25 20:29:10 -04:00
|
|
|
c.Ui.Say(result)
|
2015-06-13 13:56:09 -04:00
|
|
|
|
|
|
|
if flagValidate {
|
|
|
|
// Attemot 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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-14 02:29:19 -04:00
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2014-10-27 23:34:49 -04:00
|
|
|
func (*FixCommand) Help() string {
|
|
|
|
helpText := `
|
|
|
|
Usage: packer fix [options] TEMPLATE
|
|
|
|
|
|
|
|
Reads the JSON template and attempts to fix known backwards
|
|
|
|
incompatibilities. The fixed template will be outputted to standard out.
|
|
|
|
|
|
|
|
If the template cannot be fixed due to an error, the command will exit
|
|
|
|
with a non-zero exit status. Error messages will appear on standard error.
|
|
|
|
|
|
|
|
Fixes that are run:
|
|
|
|
|
|
|
|
iso-md5 Replaces "iso_md5" in builders with newer "iso_checksum"
|
|
|
|
createtime Replaces ".CreateTime" in builder configs with "{{timestamp}}"
|
|
|
|
virtualbox-gaattach Updates VirtualBox builders using "guest_additions_attach"
|
|
|
|
to use "guest_additions_mode"
|
|
|
|
pp-vagrant-override Replaces old-style provider overrides for the Vagrant
|
|
|
|
post-processor to new-style as of Packer 0.5.0.
|
|
|
|
virtualbox-rename Updates "virtualbox" builders to "virtualbox-iso"
|
2015-08-24 14:19:49 -04:00
|
|
|
vmware-rename Updates "vmware" builders to "vmware-iso"
|
2015-06-13 13:56:09 -04:00
|
|
|
|
|
|
|
Options:
|
|
|
|
|
|
|
|
-validate=true If true (default), validates the fixed template.
|
2014-10-27 23:34:49 -04:00
|
|
|
`
|
|
|
|
|
|
|
|
return strings.TrimSpace(helpText)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *FixCommand) Synopsis() string {
|
2013-07-14 02:29:19 -04:00
|
|
|
return "fixes templates from old versions of packer"
|
|
|
|
}
|