From e983a94a88251a32d6426269d321117d58e33266 Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Fri, 2 Mar 2018 12:32:34 -0800 Subject: [PATCH] fix default windows bash call for shell-local provisioner and move chmod command from the execute_command array into the portion of code where we actually generate inline scripts, sparing users the need to think about this modification which Packer should really handle on its own make bash call work on windows --- common/shell-local/config.go | 8 +++- common/shell-local/run.go | 6 ++- post-processor/shell-local/post-processor.go | 26 +++++------- provisioner/shell-local/provisioner.go | 43 +++++++++++++++++++- 4 files changed, 62 insertions(+), 21 deletions(-) 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 {