github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/command/fix.go (about) 1 package command 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "log" 8 "os" 9 "strings" 10 11 "github.com/hashicorp/packer/fix" 12 "github.com/hashicorp/packer/template" 13 ) 14 15 type FixCommand struct { 16 Meta 17 } 18 19 func (c *FixCommand) Run(args []string) int { 20 var flagValidate bool 21 flags := c.Meta.FlagSet("fix", FlagSetNone) 22 flags.BoolVar(&flagValidate, "validate", true, "") 23 flags.Usage = func() { c.Ui.Say(c.Help()) } 24 if err := flags.Parse(args); err != nil { 25 return 1 26 } 27 28 args = flags.Args() 29 if len(args) != 1 { 30 flags.Usage() 31 return 1 32 } 33 34 // Read the file for decoding 35 tplF, err := os.Open(args[0]) 36 if err != nil { 37 c.Ui.Error(fmt.Sprintf("Error opening template: %s", err)) 38 return 1 39 } 40 defer tplF.Close() 41 42 // Decode the JSON into a generic map structure 43 var templateData map[string]interface{} 44 decoder := json.NewDecoder(tplF) 45 if err := decoder.Decode(&templateData); err != nil { 46 c.Ui.Error(fmt.Sprintf("Error parsing template: %s", err)) 47 return 1 48 } 49 50 // Close the file since we're done with that 51 tplF.Close() 52 53 input := templateData 54 for _, name := range fix.FixerOrder { 55 var err error 56 fixer, ok := fix.Fixers[name] 57 if !ok { 58 panic("fixer not found: " + name) 59 } 60 61 log.Printf("Running fixer: %s", name) 62 input, err = fixer.Fix(input) 63 if err != nil { 64 c.Ui.Error(fmt.Sprintf("Error fixing: %s", err)) 65 return 1 66 } 67 } 68 69 var output bytes.Buffer 70 encoder := json.NewEncoder(&output) 71 if err := encoder.Encode(input); err != nil { 72 c.Ui.Error(fmt.Sprintf("Error encoding: %s", err)) 73 return 1 74 } 75 76 var indented bytes.Buffer 77 if err := json.Indent(&indented, output.Bytes(), "", " "); err != nil { 78 c.Ui.Error(fmt.Sprintf("Error encoding: %s", err)) 79 return 1 80 } 81 82 result := indented.String() 83 result = strings.Replace(result, `\u003c`, "<", -1) 84 result = strings.Replace(result, `\u003e`, ">", -1) 85 c.Ui.Say(result) 86 87 if flagValidate { 88 // Attemot to parse and validate the template 89 tpl, err := template.Parse(strings.NewReader(result)) 90 if err != nil { 91 c.Ui.Error(fmt.Sprintf( 92 "Error! Fixed template fails to parse: %s\n\n"+ 93 "This is usually caused by an error in the input template.\n"+ 94 "Please fix the error and try again.", 95 err)) 96 return 1 97 } 98 if err := tpl.Validate(); err != nil { 99 c.Ui.Error(fmt.Sprintf( 100 "Error! Fixed template failed to validate: %s\n\n"+ 101 "This is usually caused by an error in the input template.\n"+ 102 "Please fix the error and try again.", 103 err)) 104 return 1 105 } 106 } 107 108 return 0 109 } 110 111 func (*FixCommand) Help() string { 112 helpText := ` 113 Usage: packer fix [options] TEMPLATE 114 115 Reads the JSON template and attempts to fix known backwards 116 incompatibilities. The fixed template will be outputted to standard out. 117 118 If the template cannot be fixed due to an error, the command will exit 119 with a non-zero exit status. Error messages will appear on standard error. 120 121 Fixes that are run: 122 123 iso-md5 Replaces "iso_md5" in builders with newer "iso_checksum" 124 createtime Replaces ".CreateTime" in builder configs with "{{timestamp}}" 125 virtualbox-gaattach Updates VirtualBox builders using "guest_additions_attach" 126 to use "guest_additions_mode" 127 pp-vagrant-override Replaces old-style provider overrides for the Vagrant 128 post-processor to new-style as of Packer 0.5.0. 129 virtualbox-rename Updates "virtualbox" builders to "virtualbox-iso" 130 vmware-rename Updates "vmware" builders to "vmware-iso" 131 132 Options: 133 134 -validate=true If true (default), validates the fixed template. 135 ` 136 137 return strings.TrimSpace(helpText) 138 } 139 140 func (c *FixCommand) Synopsis() string { 141 return "fixes templates from old versions of packer" 142 }