add new feature for telling shell-local whether to use linux pathing on windows; update docs with some examples.

This commit is contained in:
Megan Marsh 2018-03-08 16:42:17 -08:00
parent e983a94a88
commit 51bcc7aa13
4 changed files with 75 additions and 43 deletions

View File

@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
@ -44,6 +45,8 @@ type Config struct {
// can be used to inject the environment_vars into the environment.
ExecuteCommand []string `mapstructure:"execute_command"`
UseLinuxPathing bool `mapstructure:"use_linux_pathing"`
Ctx interpolate.Context
}
@ -67,11 +70,6 @@ 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{
@ -89,7 +87,8 @@ func Validate(config *Config) error {
config.ExecuteCommand = []string{
"/bin/sh",
"-c",
"{{.Vars}} {{.Script}}",
"{{.Vars}}",
"{{.Script}}",
}
}
}
@ -146,6 +145,15 @@ func Validate(config *Config) error {
fmt.Errorf("Bad script '%s': %s", path, err))
}
}
if config.UseLinuxPathing {
for index, script := range config.Scripts {
converted, err := convertToLinuxPath(script)
if err != nil {
return err
}
config.Scripts[index] = converted
}
}
// Do a check for bad environment variables, such as '=foo', 'foobar'
for _, kv := range config.Vars {
@ -162,3 +170,16 @@ func Validate(config *Config) error {
return nil
}
// C:/path/to/your/file becomes /mnt/c/path/to/your/file
func convertToLinuxPath(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)
splitPath := strings.SplitN(winAbsPath, ":/", 2)
winBashPath := fmt.Sprintf("/mnt/%s/%s", strings.ToLower(splitPath[0]), splitPath[1])
return winBashPath, nil
}

View File

@ -6,6 +6,7 @@ import (
"io/ioutil"
"log"
"os"
"runtime"
"sort"
"strings"
@ -144,8 +145,17 @@ func createFlattenedEnvVars(config *Config) (flattened string) {
sort.Strings(keys)
// Re-assemble vars surrounding value with single quotes and flatten
if runtime.GOOS == "windows" {
log.Printf("MEGAN NEED TO IMPLEMENT")
// createEnvVarsSourceFileWindows()
}
for _, key := range keys {
flattened += fmt.Sprintf("%s='%s' ", key, envVars[key])
}
return
}
// func createFlattenedEnvVarsWindows(
// // The default shell, cmd, can set vars via dot sourcing
// // set TESTXYZ=XYZ
// )

View File

@ -1,11 +1,6 @@
package shell
import (
"fmt"
"path/filepath"
"runtime"
"strings"
sl "github.com/hashicorp/packer/common/shell-local"
"github.com/hashicorp/packer/packer"
)
@ -19,44 +14,15 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
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}}",
}
}
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 {
_, retErr := sl.Run(ui, &p.config)
if retErr != nil {

View File

@ -60,7 +60,7 @@ Optional parameters:
as well, which are covered in the section below.
- `execute_command` (array of strings) - The command used to execute the script. By
default this is `["sh", "-c", "chmod +x \"{{.Script}}\"; {{.Vars}} \"{{.Script}}\""]`
default this is `["/bin/sh", "-c", "{{.Vars}}, "{{.Script}}"]`
on unix and `["cmd", "/c", "{{.Vars}}", "{{.Script}}"]` on windows.
This is treated as a [template engine](/docs/templates/engine.html).
There are two available variables: `Script`, which is the path to the script
@ -69,7 +69,9 @@ Optional parameters:
array is the shell program you want to use (for example, "sh" or
"/usr/local/bin/zsh" or even "powershell.exe" although anything other than
a flavor of the shell command language is not explicitly supported and may
be broken by assumptions made within Packer).
be broken by assumptions made within Packer). It's worth noting that if you
choose to try to use shell-local for Powershell or other Windows commands,
the environment variables will not be set properly for your environment.
For backwards compatibility, `execute_command` will accept a string insetad
of an array of strings. If a single string or an array of strings with only
@ -89,13 +91,46 @@ Optional parameters:
**Important:** If you customize this, be sure to include something like the
`-e` flag, otherwise individual steps failing won't fail the provisioner.
## Execute Command Example
- `use_linux_pathing` (bool) - This is only relevant to windows hosts. If you
are running Packer in a Windows environment with the Windows Subsystem for
Linux feature enabled, and would like to invoke a bash script rather than
invoking a Cmd script, you'll need to set this flag to true; it tells Packer
to use the linux subsystem path for your script rather than the Windows path.
(e.g. /mnt/c/path/to/your/file instead of C:/path/to/your/file).
## Execute Command
To many new users, the `execute_command` is puzzling. However, it provides an
important function: customization of how the command is executed. The most
common use case for this is dealing with **sudo password prompts**. You may also
need to customize this if you use a non-POSIX shell, such as `tcsh` on FreeBSD.
### The Windows Linux Subsystem
If you have a bash script that you'd like to run on your Windows Linux
Subsystem as part of the shell-local post-processor, you must set
`execute_command` and `use_linux_pathing`.
The example below is a fully functional test config.
```
{
"builders": [
{
"type": "null",
"communicator": "none"
}
],
"provisioners": [
{
"type": "shell-local",
"environment_vars": ["PROVISIONERTEST=ProvisionerTest1"],
"execute_command": ["bash", "-c", "{{.Vars}} {{.Script}}"]
"use_linux_pathing": true
"scripts": ["./scripts/.sh"]
},
```
## Default Environmental Variables
In addition to being able to specify custom environmental variables using the