diff --git a/common/shell-local/config.go b/common/shell-local/config.go index 2d31b7f01..8c73d0f57 100644 --- a/common/shell-local/config.go +++ b/common/shell-local/config.go @@ -67,6 +67,11 @@ func Decode(config *Config, raws ...interface{}) error { func Validate(config *Config) error { var errs *packer.MultiError + // Do not treat these defaults as a source of truth; the shell-local + // provisioner sets these defaults before Validate is called. Eventually + // we will have to bring the provisioner and post-processor defaults in + // line with one another, but for now the following may or may not be + // applied depending on where Validate is being called from. if runtime.GOOS == "windows" { if len(config.ExecuteCommand) == 0 { config.ExecuteCommand = []string{ @@ -84,8 +89,7 @@ func Validate(config *Config) error { config.ExecuteCommand = []string{ "/bin/sh", "-c", - "{{.Vars}}", - "{{.Script}}", + "{{.Vars}} {{.Script}}", } } } diff --git a/common/shell-local/run.go b/common/shell-local/run.go index 04d653389..5545d56d7 100644 --- a/common/shell-local/run.go +++ b/common/shell-local/run.go @@ -41,7 +41,7 @@ func Run(ui packer.Ui, config *Config) (bool, error) { if err != nil { return false, err } - ui.Say(fmt.Sprintf("Post processing with local shell script: %s", script)) + ui.Say(fmt.Sprintf("Running local shell script: %s", script)) comm := &Communicator{ ExecuteCommand: interpolatedCmds, @@ -93,6 +93,10 @@ func createInlineScriptFile(config *Config) (string, error) { } tf.Close() + err = os.Chmod(tf.Name(), 0555) + if err != nil { + log.Printf("error modifying permissions of temp script file: %s", err.Error()) + } return tf.Name(), nil } diff --git a/post-processor/shell-local/post-processor.go b/post-processor/shell-local/post-processor.go index cc1f2845e..c761a19f4 100644 --- a/post-processor/shell-local/post-processor.go +++ b/post-processor/shell-local/post-processor.go @@ -1,8 +1,6 @@ package shell_local import ( - "runtime" - sl "github.com/hashicorp/packer/common/shell-local" "github.com/hashicorp/packer/packer" ) @@ -21,20 +19,16 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { if err != nil { return err } - if len(p.config.ExecuteCommand) == 0 && runtime.GOOS != "windows" { - // Backwards compatibility from before post-processor merge with - // provisioner. Don't need to default separately for windows becuase the - // post-processor never worked for windows before the merge with the - // provisioner code, so the provisioner defaults are fine. - p.config.ExecuteCommand = []string{"sh", "-c", `chmod +x "{{.Script}}"; {{.Vars}} "{{.Script}}"`} - } else if len(p.config.ExecuteCommand) == 1 { - // Backwards compatibility -- before merge, post-processor didn't have - // configurable call to shell program, meaning users may not have - // defined this in their call. If users are still using the old way of - // defining ExecuteCommand (e.g. just supplying a single string that is - // now being interpolated as a slice with one item), then assume we need - // to prepend this call still, and use the one that the post-processor - // defaulted to before. + if len(p.config.ExecuteCommand) == 1 { + // Backwards compatibility -- before we merged the shell-local + // post-processor and provisioners, the post-processor accepted + // execute_command as a string rather than a slice of strings. It didn't + // have a configurable call to shell program, automatically prepending + // the user-supplied execute_command string with "sh -c". If users are + // still using the old way of defining ExecuteCommand (by supplying a + // single string rather than a slice of strings) then we need to + // prepend this command with the call that the post-processor defaulted + // to before. p.config.ExecuteCommand = append([]string{"sh", "-c"}, p.config.ExecuteCommand...) } diff --git a/provisioner/shell-local/provisioner.go b/provisioner/shell-local/provisioner.go index a56553245..a58f0c859 100644 --- a/provisioner/shell-local/provisioner.go +++ b/provisioner/shell-local/provisioner.go @@ -1,6 +1,11 @@ package shell import ( + "fmt" + "path/filepath" + "runtime" + "strings" + sl "github.com/hashicorp/packer/common/shell-local" "github.com/hashicorp/packer/packer" ) @@ -10,12 +15,46 @@ type Provisioner struct { } func (p *Provisioner) Prepare(raws ...interface{}) error { - err := sl.Decode(&p.config, raws) + err := sl.Decode(&p.config, raws...) if err != nil { return err } + convertPath := false + if len(p.config.ExecuteCommand) == 0 && runtime.GOOS == "windows" { + convertPath = true + p.config.ExecuteCommand = []string{ + "bash", + "-c", + "{{.Vars}} {{.Script}}", + } + } - return sl.Validate(&p.config) + err = sl.Validate(&p.config) + if err != nil { + return err + } + + if convertPath { + for index, script := range p.config.Scripts { + p.config.Scripts[index], err = convertToWindowsBashPath(script) + if err != nil { + return err + } + } + } + + return nil +} + +func convertToWindowsBashPath(winPath string) (string, error) { + // get absolute path of script, and morph it into the bash path + winAbsPath, err := filepath.Abs(winPath) + if err != nil { + return "", fmt.Errorf("Error converting %s to absolute path: %s", winPath, err.Error()) + } + winAbsPath = strings.Replace(winAbsPath, "\\", "/", -1) + winBashPath := strings.Replace(winAbsPath, "C:/", "/mnt/c/", 1) + return winBashPath, nil } func (p *Provisioner) Provision(ui packer.Ui, _ packer.Communicator) error {