From 6c20861af507cd41940f9c9496cf3f646d9e6eea Mon Sep 17 00:00:00 2001 From: Wayne Starr Date: Sat, 8 Apr 2023 17:10:14 -0500 Subject: [PATCH 01/10] Allow the selection between CMD and Powershell and prefer CMD for dataInjections --- docs/4-user-guide/3-zarf-schema.md | 16 ++++++++++++++++ src/internal/cluster/data.go | 2 +- src/pkg/packager/actions.go | 12 ++++++------ src/pkg/utils/exec/exec.go | 11 ++++++++--- src/types/component.go | 1 + src/ui/lib/api-types.ts | 7 +++++++ zarf.schema.json | 4 ++++ 7 files changed, 43 insertions(+), 10 deletions(-) diff --git a/docs/4-user-guide/3-zarf-schema.md b/docs/4-user-guide/3-zarf-schema.md index f9ad04f416..38ddd5ba3e 100644 --- a/docs/4-user-guide/3-zarf-schema.md +++ b/docs/4-user-guide/3-zarf-schema.md @@ -990,6 +990,22 @@ Must be one of: +
+ + preferLegacyShell + +  +
+ +**Description:** (Windows/cmd only) Whether to prefer running the command in the legacy command shell rather than powershell (see https://github.com/orgs/PowerShell/discussions/16569) (note: command conversion of commands like touch to New-Item will be disabled as well) + +| | | +| -------- | --------- | +| **Type** | `boolean` | + +
+
+
setVariables diff --git a/src/internal/cluster/data.go b/src/internal/cluster/data.go index af09a79efa..cc42e7f166 100644 --- a/src/internal/cluster/data.go +++ b/src/internal/cluster/data.go @@ -44,7 +44,7 @@ func (c *Cluster) HandleDataInjection(wg *sync.WaitGroup, data types.ZarfDataInj } // Get the OS shell to execute commands in - shell, shellArgs := exec.GetOSShell() + shell, shellArgs := exec.GetOSShell(true) if _, _, err := exec.Cmd(shell, shellArgs, "tar --version"); err != nil { message.Error(err, "Unable to execute tar on this system. Please ensure it is installed and on your $PATH.") diff --git a/src/pkg/packager/actions.go b/src/pkg/packager/actions.go index f3e469b93f..7bb3ea8046 100644 --- a/src/pkg/packager/actions.go +++ b/src/pkg/packager/actions.go @@ -89,7 +89,7 @@ func (p *Packager) runAction(defaultCfg types.ZarfComponentActionDefaults, actio cfg := actionGetCfg(defaultCfg, action, vars) - if cmd, err = actionCmdMutation(cmd); err != nil { + if cmd, err = actionCmdMutation(cmd, action.PreferLegacyShell); err != nil { spinner.Errorf(err, "Error mutating command: %s", cmdEscaped) } @@ -102,7 +102,7 @@ func (p *Packager) runAction(defaultCfg types.ZarfComponentActionDefaults, actio // Perform the action run. tryCmd := func(ctx context.Context) error { // Try running the command and continue the retry loop if it fails. - if out, err = actionRun(ctx, cfg, cmd, spinner); err != nil { + if out, err = actionRun(ctx, cfg, cmd, action.PreferLegacyShell, spinner); err != nil { return err } @@ -193,7 +193,7 @@ func convertWaitToCmd(wait types.ZarfComponentActionWait, timeout *int) (string, } // Perform some basic string mutations to make commands more useful. -func actionCmdMutation(cmd string) (string, error) { +func actionCmdMutation(cmd string, preferLegacyShell bool) (string, error) { binaryPath, err := os.Executable() if err != nil { return cmd, err @@ -203,7 +203,7 @@ func actionCmdMutation(cmd string) (string, error) { cmd = strings.ReplaceAll(cmd, "./zarf ", binaryPath+" ") // Make commands 'more' compatible with Windows OS PowerShell - if runtime.GOOS == "windows" { + if runtime.GOOS == "windows" && !preferLegacyShell { // Replace "touch" with "New-Item" on Windows as it's a common command, but not POSIX so not aliased by M$. // See https://mathieubuisson.github.io/powershell-linux-bash/ & // http://web.cs.ucla.edu/~miryung/teaching/EE461L-Spring2012/labs/posix.html for more details. @@ -259,8 +259,8 @@ func actionGetCfg(cfg types.ZarfComponentActionDefaults, a types.ZarfComponentAc return cfg } -func actionRun(ctx context.Context, cfg types.ZarfComponentActionDefaults, cmd string, spinner *message.Spinner) (string, error) { - shell, shellArgs := exec.GetOSShell() +func actionRun(ctx context.Context, cfg types.ZarfComponentActionDefaults, cmd string, preferLegacyShell bool, spinner *message.Spinner) (string, error) { + shell, shellArgs := exec.GetOSShell(preferLegacyShell) message.Debug("Running command in %s: %s", shell, cmd) diff --git a/src/pkg/utils/exec/exec.go b/src/pkg/utils/exec/exec.go index c1c000a8e8..c294448f8b 100644 --- a/src/pkg/utils/exec/exec.go +++ b/src/pkg/utils/exec/exec.go @@ -152,13 +152,18 @@ func LaunchURL(url string) error { } // GetOSShell returns the shell and shellArgs based on the current OS -func GetOSShell() (string, string) { +func GetOSShell(preferLegacyShell bool) (string, string) { var shell string var shellArgs string if runtime.GOOS == "windows" { - shell = "powershell" - shellArgs = "-Command" + if preferLegacyShell { + shell = "cmd" + shellArgs = "/c" + } else { + shell = "powershell" + shellArgs = "-Command" + } } else { shell = "sh" shellArgs = "-c" diff --git a/src/types/component.go b/src/types/component.go index 5f1faaa425..0ca0b7ee88 100644 --- a/src/types/component.go +++ b/src/types/component.go @@ -148,6 +148,7 @@ type ZarfComponentAction struct { Dir *string `json:"dir,omitempty" jsonschema:"description=The working directory to run the command in (default is CWD)"` Env []string `json:"env,omitempty" jsonschema:"description=Additional environment variables to set for the command"` Cmd string `json:"cmd,omitempty" jsonschema:"description=The command to run. Must specify either cmd or wait for the action to do anything."` + PreferLegacyShell bool `json:"preferLegacyShell,omitempty" jsonschema:"description=(Windows/cmd only) Whether to prefer running the command in the legacy command shell rather than powershell (see https://github.com/orgs/PowerShell/discussions/16569) (note: command conversion of commands like touch to New-Item will be disabled as well)"` DeprecatedSetVariable string `json:"setVariable,omitempty" jsonschema:"description=[Deprecated] (replaced by setVariables) (onDeploy/cmd only) The name of a variable to update with the output of the command. This variable will be available to all remaining actions and components in the package.,pattern=^[A-Z0-9_]+$"` SetVariables []ZarfComponentActionSetVariable `json:"setVariables,omitempty" jsonschema:"description=(onDeploy/cmd only) An array of variables to update with the output of the command. These variables will be available to all remaining actions and components in the package."` Description string `json:"description,omitempty" jsonschema:"description=Description of the action to be displayed during package execution instead of the command"` diff --git a/src/ui/lib/api-types.ts b/src/ui/lib/api-types.ts index 15bdf0041f..f729b88401 100644 --- a/src/ui/lib/api-types.ts +++ b/src/ui/lib/api-types.ts @@ -389,6 +389,12 @@ export interface ZarfComponentAction { * Hide the output of the command during package deployment (default false) */ mute?: boolean; + /** + * (Windows/cmd only) Whether to prefer running the command in the legacy command shell + * rather than powershell (see https://github.com/orgs/PowerShell/discussions/16569) (note: + * command conversion of commands like touch to New-Item will be disabled as well) + */ + preferLegacyShell?: boolean; /** * [Deprecated] (replaced by setVariables) (onDeploy/cmd only) The name of a variable to * update with the output of the command. This variable will be available to all remaining @@ -1298,6 +1304,7 @@ const typeMap: any = { { json: "maxRetries", js: "maxRetries", typ: u(undefined, 0) }, { json: "maxTotalSeconds", js: "maxTotalSeconds", typ: u(undefined, 0) }, { json: "mute", js: "mute", typ: u(undefined, true) }, + { json: "preferLegacyShell", js: "preferLegacyShell", typ: u(undefined, true) }, { json: "setVariable", js: "setVariable", typ: u(undefined, "") }, { json: "setVariables", js: "setVariables", typ: u(undefined, a(r("ZarfComponentActionSetVariable"))) }, { json: "wait", js: "wait", typ: u(undefined, r("ZarfComponentActionWait")) }, diff --git a/zarf.schema.json b/zarf.schema.json index f786474c9a..783d22babd 100644 --- a/zarf.schema.json +++ b/zarf.schema.json @@ -316,6 +316,10 @@ "type": "string", "description": "The command to run. Must specify either cmd or wait for the action to do anything." }, + "preferLegacyShell": { + "type": "boolean", + "description": "(Windows/cmd only) Whether to prefer running the command in the legacy command shell rather than powershell (see https://github.com/orgs/PowerShell/discussions/16569) (note: command conversion of commands like touch to New-Item will be disabled as well)" + }, "setVariable": { "pattern": "^[A-Z0-9_]+$", "type": "string", From 3cbacb3a67ed9d556beb52d395597e68efcc962b Mon Sep 17 00:00:00 2001 From: Wayne Starr Date: Sat, 8 Apr 2023 17:24:58 -0500 Subject: [PATCH 02/10] Add preferLegacyShell key to our examples --- examples/component-actions/zarf.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/component-actions/zarf.yaml b/examples/component-actions/zarf.yaml index 8ec106b02e..c9fb21d3d8 100644 --- a/examples/component-actions/zarf.yaml +++ b/examples/component-actions/zarf.yaml @@ -39,6 +39,8 @@ components: - cmd: touch test-create-after.txt - cmd: sleep 1 - cmd: echo "I can print!" + # prefer to run the above command in "cmd" instead of "powershell" on Windows + preferLegacyShell: true - cmd: sleep 1 - cmd: | echo "multiline!" From f747d6eb09bb564e0ca319b5a761fc18898cf30f Mon Sep 17 00:00:00 2001 From: Wayne Starr Date: Fri, 14 Apr 2023 14:22:15 -0500 Subject: [PATCH 03/10] Add better chell preferences --- src/internal/cluster/data.go | 2 +- src/pkg/packager/actions.go | 16 ++++++++++------ src/pkg/utils/exec/exec.go | 33 ++++++++++++++++++++++++++------- src/types/component.go | 20 ++++++++++++++------ 4 files changed, 51 insertions(+), 20 deletions(-) diff --git a/src/internal/cluster/data.go b/src/internal/cluster/data.go index cc42e7f166..d1767343c2 100644 --- a/src/internal/cluster/data.go +++ b/src/internal/cluster/data.go @@ -44,7 +44,7 @@ func (c *Cluster) HandleDataInjection(wg *sync.WaitGroup, data types.ZarfDataInj } // Get the OS shell to execute commands in - shell, shellArgs := exec.GetOSShell(true) + shell, shellArgs := exec.GetOSShell(types.ZarfComponentActionShell{Windows: "cmd"}) if _, _, err := exec.Cmd(shell, shellArgs, "tar --version"); err != nil { message.Error(err, "Unable to execute tar on this system. Please ensure it is installed and on your $PATH.") diff --git a/src/pkg/packager/actions.go b/src/pkg/packager/actions.go index 7bb3ea8046..558f4dc6b2 100644 --- a/src/pkg/packager/actions.go +++ b/src/pkg/packager/actions.go @@ -89,7 +89,7 @@ func (p *Packager) runAction(defaultCfg types.ZarfComponentActionDefaults, actio cfg := actionGetCfg(defaultCfg, action, vars) - if cmd, err = actionCmdMutation(cmd, action.PreferLegacyShell); err != nil { + if cmd, err = actionCmdMutation(cmd, cfg.Shell); err != nil { spinner.Errorf(err, "Error mutating command: %s", cmdEscaped) } @@ -102,7 +102,7 @@ func (p *Packager) runAction(defaultCfg types.ZarfComponentActionDefaults, actio // Perform the action run. tryCmd := func(ctx context.Context) error { // Try running the command and continue the retry loop if it fails. - if out, err = actionRun(ctx, cfg, cmd, action.PreferLegacyShell, spinner); err != nil { + if out, err = actionRun(ctx, cfg, cmd, cfg.Shell, spinner); err != nil { return err } @@ -193,7 +193,7 @@ func convertWaitToCmd(wait types.ZarfComponentActionWait, timeout *int) (string, } // Perform some basic string mutations to make commands more useful. -func actionCmdMutation(cmd string, preferLegacyShell bool) (string, error) { +func actionCmdMutation(cmd string, shellPref types.ZarfComponentActionShell) (string, error) { binaryPath, err := os.Executable() if err != nil { return cmd, err @@ -203,7 +203,7 @@ func actionCmdMutation(cmd string, preferLegacyShell bool) (string, error) { cmd = strings.ReplaceAll(cmd, "./zarf ", binaryPath+" ") // Make commands 'more' compatible with Windows OS PowerShell - if runtime.GOOS == "windows" && !preferLegacyShell { + if runtime.GOOS == "windows" && shellPref.Windows == "cmd" { // Replace "touch" with "New-Item" on Windows as it's a common command, but not POSIX so not aliased by M$. // See https://mathieubuisson.github.io/powershell-linux-bash/ & // http://web.cs.ucla.edu/~miryung/teaching/EE461L-Spring2012/labs/posix.html for more details. @@ -246,6 +246,10 @@ func actionGetCfg(cfg types.ZarfComponentActionDefaults, a types.ZarfComponentAc cfg.Env = append(cfg.Env, a.Env...) } + if a.Shell != nil { + cfg.Shell = *a.Shell + } + // Add variables to the environment. for k, v := range vars { // Remove # from env variable name. @@ -259,8 +263,8 @@ func actionGetCfg(cfg types.ZarfComponentActionDefaults, a types.ZarfComponentAc return cfg } -func actionRun(ctx context.Context, cfg types.ZarfComponentActionDefaults, cmd string, preferLegacyShell bool, spinner *message.Spinner) (string, error) { - shell, shellArgs := exec.GetOSShell(preferLegacyShell) +func actionRun(ctx context.Context, cfg types.ZarfComponentActionDefaults, cmd string, shellPref types.ZarfComponentActionShell, spinner *message.Spinner) (string, error) { + shell, shellArgs := exec.GetOSShell(shellPref) message.Debug("Running command in %s: %s", shell, cmd) diff --git a/src/pkg/utils/exec/exec.go b/src/pkg/utils/exec/exec.go index c294448f8b..f23a67ff79 100644 --- a/src/pkg/utils/exec/exec.go +++ b/src/pkg/utils/exec/exec.go @@ -14,6 +14,8 @@ import ( "os/exec" "runtime" "sync" + + "github.com/defenseunicorns/zarf/src/types" ) // Change terminal colors. @@ -152,19 +154,36 @@ func LaunchURL(url string) error { } // GetOSShell returns the shell and shellArgs based on the current OS -func GetOSShell(preferLegacyShell bool) (string, string) { +func GetOSShell(shellPref types.ZarfComponentActionShell) (string, string) { var shell string var shellArgs string - if runtime.GOOS == "windows" { - if preferLegacyShell { - shell = "cmd" + switch runtime.GOOS { + case "windows": + shell = shellPref.Windows + shellArgs = "-Command" + + // Change shellArgs to /c if cmd is chosen + if shellPref.Windows == "cmd" { shellArgs = "/c" - } else { + } else if shellPref.Windows == "" { shell = "powershell" - shellArgs = "-Command" } - } else { + case "darwin": + shell = shellPref.Darwin + shellArgs = "-c" + + if shellPref.Darwin == "" { + shell = "sh" + } + case "linux": + shell = shellPref.Linux + shellArgs = "-c" + + if shellPref.Linux == "" { + shell = "sh" + } + default: shell = "sh" shellArgs = "-c" } diff --git a/src/types/component.go b/src/types/component.go index 0ca0b7ee88..79781ea784 100644 --- a/src/types/component.go +++ b/src/types/component.go @@ -133,11 +133,19 @@ type ZarfComponentActionSet struct { // ZarfComponentActionDefaults sets the default configs for child actions type ZarfComponentActionDefaults struct { - Mute bool `json:"mute,omitempty" jsonschema:"description=Hide the output of commands during execution (default false)"` - MaxTotalSeconds int `json:"maxTotalSeconds,omitempty" jsonschema:"description=Default timeout in seconds for commands (default to 0, no timeout)"` - MaxRetries int `json:"maxRetries,omitempty" jsonschema:"description=Retry commands given number of times if they fail (default 0)"` - Dir string `json:"dir,omitempty" jsonschema:"description=Working directory for commands (default CWD)"` - Env []string `json:"env,omitempty" jsonschema:"description=Additional environment variables for commands"` + Mute bool `json:"mute,omitempty" jsonschema:"description=Hide the output of commands during execution (default false)"` + MaxTotalSeconds int `json:"maxTotalSeconds,omitempty" jsonschema:"description=Default timeout in seconds for commands (default to 0, no timeout)"` + MaxRetries int `json:"maxRetries,omitempty" jsonschema:"description=Retry commands given number of times if they fail (default 0)"` + Dir string `json:"dir,omitempty" jsonschema:"description=Working directory for commands (default CWD)"` + Env []string `json:"env,omitempty" jsonschema:"description=Additional environment variables for commands"` + Shell ZarfComponentActionShell `json:"shell,omitempty" jsonschema:"description=(cmd only) Indicates a preference for a shell for the provided cmd to be executed in on supported operating systems"` +} + +// ZarfComponentActionShell represents the desired shell to use for a given command +type ZarfComponentActionShell struct { + Windows string + Linux string + Darwin string } // ZarfComponentAction represents a single action to run during a zarf package operation @@ -148,7 +156,7 @@ type ZarfComponentAction struct { Dir *string `json:"dir,omitempty" jsonschema:"description=The working directory to run the command in (default is CWD)"` Env []string `json:"env,omitempty" jsonschema:"description=Additional environment variables to set for the command"` Cmd string `json:"cmd,omitempty" jsonschema:"description=The command to run. Must specify either cmd or wait for the action to do anything."` - PreferLegacyShell bool `json:"preferLegacyShell,omitempty" jsonschema:"description=(Windows/cmd only) Whether to prefer running the command in the legacy command shell rather than powershell (see https://github.com/orgs/PowerShell/discussions/16569) (note: command conversion of commands like touch to New-Item will be disabled as well)"` + Shell *ZarfComponentActionShell `json:"shell,omitempty" jsonschema:"description=(cmd only) Indicates a preference for a shell for the provided cmd to be executed in on supported operating systems"` DeprecatedSetVariable string `json:"setVariable,omitempty" jsonschema:"description=[Deprecated] (replaced by setVariables) (onDeploy/cmd only) The name of a variable to update with the output of the command. This variable will be available to all remaining actions and components in the package.,pattern=^[A-Z0-9_]+$"` SetVariables []ZarfComponentActionSetVariable `json:"setVariables,omitempty" jsonschema:"description=(onDeploy/cmd only) An array of variables to update with the output of the command. These variables will be available to all remaining actions and components in the package."` Description string `json:"description,omitempty" jsonschema:"description=Description of the action to be displayed during package execution instead of the command"` From 4fac73f5cc8a676bb83c88156ef460d59f4a93dd Mon Sep 17 00:00:00 2001 From: Wayne Starr Date: Fri, 14 Apr 2023 14:45:31 -0500 Subject: [PATCH 04/10] Add support for more shells --- src/pkg/utils/exec/exec.go | 15 ++++++++++++--- src/types/component.go | 6 +++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/pkg/utils/exec/exec.go b/src/pkg/utils/exec/exec.go index f23a67ff79..4f8daa9e6b 100644 --- a/src/pkg/utils/exec/exec.go +++ b/src/pkg/utils/exec/exec.go @@ -163,9 +163,12 @@ func GetOSShell(shellPref types.ZarfComponentActionShell) (string, string) { shell = shellPref.Windows shellArgs = "-Command" - // Change shellArgs to /c if cmd is chosen if shellPref.Windows == "cmd" { + // Change shellArgs to /c if cmd is chosen shellArgs = "/c" + } else if shellPref.Windows == "sh" || shellPref.Windows == "bash" || shellPref.Windows == "zsh" || shellPref.Windows == "gsh" { + // Change shellArgs to -c if a real shell is chosen + shellArgs = "-c" } else if shellPref.Windows == "" { shell = "powershell" } @@ -173,14 +176,20 @@ func GetOSShell(shellPref types.ZarfComponentActionShell) (string, string) { shell = shellPref.Darwin shellArgs = "-c" - if shellPref.Darwin == "" { + if shellPref.Darwin == "pwsh" { + // Change shellArgs to -Command if pwsh is chosen + shellArgs = "-Command" + } else if shellPref.Darwin == "" { shell = "sh" } case "linux": shell = shellPref.Linux shellArgs = "-c" - if shellPref.Linux == "" { + if shellPref.Linux == "pwsh" { + // Change shellArgs to -Command if pwsh is chosen + shellArgs = "-Command" + } else if shellPref.Linux == "" { shell = "sh" } default: diff --git a/src/types/component.go b/src/types/component.go index 79781ea784..53cf7d7813 100644 --- a/src/types/component.go +++ b/src/types/component.go @@ -143,9 +143,9 @@ type ZarfComponentActionDefaults struct { // ZarfComponentActionShell represents the desired shell to use for a given command type ZarfComponentActionShell struct { - Windows string - Linux string - Darwin string + Windows string `json:"windows,omitempty" jsonschema:"description=(default 'powershell') Indicates a preference for the shell to use on Windows systems (note that choosing 'cmd' will turn off migrations like touch -> New-Item),example=powershell,example=cmd,example=pwsh,example=sh,example=bash,example=gsh"` + Linux string `json:"linux,omitempty" jsonschema:"description=(default 'sh') Indicates a preference for the shell to use on Linux systems,example=sh,example=bash,example=fish,example=zsh,example=pwsh"` + Darwin string `json:"darwin,omitempty" jsonschema:"description=(default 'sh') Indicates a preference for the shell to use on macOS systems,example=sh,example=bash,example=fish,example=zsh,example=pwsh"` } // ZarfComponentAction represents a single action to run during a zarf package operation From 947d4a793d47e48f35a008acac1aa7a04e6038ff Mon Sep 17 00:00:00 2001 From: Wayne Starr Date: Fri, 14 Apr 2023 15:32:40 -0500 Subject: [PATCH 05/10] Fix powershell handling --- src/pkg/packager/actions.go | 4 ++-- src/pkg/utils/exec/exec.go | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/pkg/packager/actions.go b/src/pkg/packager/actions.go index 558f4dc6b2..2a620dae97 100644 --- a/src/pkg/packager/actions.go +++ b/src/pkg/packager/actions.go @@ -203,7 +203,7 @@ func actionCmdMutation(cmd string, shellPref types.ZarfComponentActionShell) (st cmd = strings.ReplaceAll(cmd, "./zarf ", binaryPath+" ") // Make commands 'more' compatible with Windows OS PowerShell - if runtime.GOOS == "windows" && shellPref.Windows == "cmd" { + if runtime.GOOS == "windows" && exec.IsPowershell(shellPref.Windows) { // Replace "touch" with "New-Item" on Windows as it's a common command, but not POSIX so not aliased by M$. // See https://mathieubuisson.github.io/powershell-linux-bash/ & // http://web.cs.ucla.edu/~miryung/teaching/EE461L-Spring2012/labs/posix.html for more details. @@ -266,7 +266,7 @@ func actionGetCfg(cfg types.ZarfComponentActionDefaults, a types.ZarfComponentAc func actionRun(ctx context.Context, cfg types.ZarfComponentActionDefaults, cmd string, shellPref types.ZarfComponentActionShell, spinner *message.Spinner) (string, error) { shell, shellArgs := exec.GetOSShell(shellPref) - message.Debug("Running command in %s: %s", shell, cmd) + message.Debugf("Running command in %s: %s", shell, cmd) execCfg := exec.Config{ Env: cfg.Env, diff --git a/src/pkg/utils/exec/exec.go b/src/pkg/utils/exec/exec.go index 4f8daa9e6b..47f510294f 100644 --- a/src/pkg/utils/exec/exec.go +++ b/src/pkg/utils/exec/exec.go @@ -166,7 +166,7 @@ func GetOSShell(shellPref types.ZarfComponentActionShell) (string, string) { if shellPref.Windows == "cmd" { // Change shellArgs to /c if cmd is chosen shellArgs = "/c" - } else if shellPref.Windows == "sh" || shellPref.Windows == "bash" || shellPref.Windows == "zsh" || shellPref.Windows == "gsh" { + } else if !IsPowershell(shellPref.Windows) { // Change shellArgs to -c if a real shell is chosen shellArgs = "-c" } else if shellPref.Windows == "" { @@ -176,7 +176,7 @@ func GetOSShell(shellPref types.ZarfComponentActionShell) (string, string) { shell = shellPref.Darwin shellArgs = "-c" - if shellPref.Darwin == "pwsh" { + if IsPowershell(shellPref.Darwin) { // Change shellArgs to -Command if pwsh is chosen shellArgs = "-Command" } else if shellPref.Darwin == "" { @@ -186,7 +186,7 @@ func GetOSShell(shellPref types.ZarfComponentActionShell) (string, string) { shell = shellPref.Linux shellArgs = "-c" - if shellPref.Linux == "pwsh" { + if IsPowershell(shellPref.Linux) { // Change shellArgs to -Command if pwsh is chosen shellArgs = "-Command" } else if shellPref.Linux == "" { @@ -199,3 +199,8 @@ func GetOSShell(shellPref types.ZarfComponentActionShell) (string, string) { return shell, shellArgs } + +// IsPowershell returns whether a shell name is powershell +func IsPowershell(shellName string) bool { + return shellName == "powershell" || shellName == "pwsh" +} From 477a9ed30e61c2c2fd309c591cf0fc49739b3ec4 Mon Sep 17 00:00:00 2001 From: Wayne Starr Date: Fri, 14 Apr 2023 15:35:50 -0500 Subject: [PATCH 06/10] Update docs and fix linting --- docs/4-user-guide/3-zarf-schema.md | 99 ++++++++++++++++++++++++-- src/extensions/bigbang/bigbang.go | 8 +-- src/extensions/bigbang/bigbang_test.go | 13 ++-- src/ui/lib/api-types.ts | 44 ++++++++++-- zarf.schema.json | 51 ++++++++++++- 5 files changed, 189 insertions(+), 26 deletions(-) diff --git a/docs/4-user-guide/3-zarf-schema.md b/docs/4-user-guide/3-zarf-schema.md index 38ddd5ba3e..4577812f25 100644 --- a/docs/4-user-guide/3-zarf-schema.md +++ b/docs/4-user-guide/3-zarf-schema.md @@ -852,6 +852,89 @@ Must be one of:
+
+ + shell + +  +
+ + ## components > actions > onCreate > defaults > shell + +**Description:** (cmd only) Indicates a preference for a shell for the provided cmd to be executed in on supported operating systems + +| | | +| ------------------------- | -------------------------------------------------------------------------------------------------------- | +| **Type** | `object` | +| **Additional properties** | [![Not allowed](https://img.shields.io/badge/Not%20allowed-red)](# "Additional Properties not allowed.") | +| **Defined in** | #/definitions/ZarfComponentActionShell | + +
+ + windows + +  +
+ +**Description:** (default 'powershell') Indicates a preference for the shell to use on Windows systems (note that choosing 'cmd' will turn off migrations like touch -> New-Item) + +| | | +| -------- | -------- | +| **Type** | `string` | + +**Examples:** + + +"powershell", "cmd", "pwsh", "sh", "bash", "gsh" + +
+
+ +
+ + linux + +  +
+ +**Description:** (default 'sh') Indicates a preference for the shell to use on Linux systems + +| | | +| -------- | -------- | +| **Type** | `string` | + +**Examples:** + + +"sh", "bash", "fish", "zsh", "pwsh" + +
+
+ +
+ + darwin + +  +
+ +**Description:** (default 'sh') Indicates a preference for the shell to use on macOS systems + +| | | +| -------- | -------- | +| **Type** | `string` | + +**Examples:** + + +"sh", "bash", "fish", "zsh", "pwsh" + +
+
+ +
+
+ @@ -990,18 +1073,22 @@ Must be one of: -
+
- preferLegacyShell + shell  
-**Description:** (Windows/cmd only) Whether to prefer running the command in the legacy command shell rather than powershell (see https://github.com/orgs/PowerShell/discussions/16569) (note: command conversion of commands like touch to New-Item will be disabled as well) + ## components > actions > onCreate > before > shell -| | | -| -------- | --------- | -| **Type** | `boolean` | +**Description:** (cmd only) Indicates a preference for a shell for the provided cmd to be executed in on supported operating systems + +| | | +| ------------------------- | -------------------------------------------------------------------------------------------------------- | +| **Type** | `object` | +| **Additional properties** | [![Not allowed](https://img.shields.io/badge/Not%20allowed-red)](# "Additional Properties not allowed.") | +| **Same definition as** | [shell](#components_items_actions_onCreate_defaults_shell) |
diff --git a/src/extensions/bigbang/bigbang.go b/src/extensions/bigbang/bigbang.go index eeab77575f..e93c2e92af 100644 --- a/src/extensions/bigbang/bigbang.go +++ b/src/extensions/bigbang/bigbang.go @@ -43,7 +43,7 @@ func Run(tmpPaths types.ComponentPaths, c types.ZarfComponent) (types.ZarfCompon cfg := c.Extensions.BigBang manifests := []types.ZarfManifest{} - err, validVersionResponse := isValidVersion(cfg.Version) + validVersionResponse, err := isValidVersion(cfg.Version) if err != nil { return c, fmt.Errorf("invalid Big Bang version: %s, parsing issue %s", cfg.Version, err) @@ -233,11 +233,11 @@ func Run(tmpPaths types.ComponentPaths, c types.ZarfComponent) (types.ZarfCompon } // isValidVersion check if the version is 1.54.0 or greater. -func isValidVersion(version string) (error, bool) { +func isValidVersion(version string) (bool, error) { specifiedVersion, err := semver.NewVersion(version) if err != nil { - return err, false + return false, err } minRequiredVersion, _ := semver.NewVersion(bbMinRequiredVersion) @@ -246,7 +246,7 @@ func isValidVersion(version string) (error, bool) { c, _ := semver.NewConstraint(fmt.Sprintf(">= %s-0", minRequiredVersion)) // This extension requires BB 1.54.0 or greater. - return nil, c.Check(specifiedVersion) + return c.Check(specifiedVersion), nil } // findBBResources takes a list of yaml objects (as a string) and diff --git a/src/extensions/bigbang/bigbang_test.go b/src/extensions/bigbang/bigbang_test.go index e6d1167089..6f8ec30f9c 100644 --- a/src/extensions/bigbang/bigbang_test.go +++ b/src/extensions/bigbang/bigbang_test.go @@ -1,33 +1,34 @@ package bigbang import ( - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestRequiredBigBangVersions(t *testing.T) { // Support 1.54.0 and beyond - err, vv := isValidVersion("1.54.0") + vv, err := isValidVersion("1.54.0") assert.Equal(t, err, nil) assert.Equal(t, vv, true) // Do not support earlier than 1.54.0 - err, vv = isValidVersion("1.53.0") + vv, err = isValidVersion("1.53.0") assert.Equal(t, err, nil) assert.Equal(t, vv, false) // Support for Big Bang release candidates - err, vv = isValidVersion("1.57.0-rc.0") + vv, err = isValidVersion("1.57.0-rc.0") assert.Equal(t, err, nil) assert.Equal(t, vv, true) // Support for Big Bang 2.0.0 - err, vv = isValidVersion("2.0.0") + vv, err = isValidVersion("2.0.0") assert.Equal(t, err, nil) assert.Equal(t, vv, true) // Fail on non-semantic versions - err, vv = isValidVersion("1.57b") + vv, err = isValidVersion("1.57b") Expected := "Invalid Semantic Version" if err.Error() != Expected { t.Errorf("Error actual = %v, and Expected = %v.", err, Expected) diff --git a/src/ui/lib/api-types.ts b/src/ui/lib/api-types.ts index f729b88401..89c2b3ccbb 100644 --- a/src/ui/lib/api-types.ts +++ b/src/ui/lib/api-types.ts @@ -389,12 +389,6 @@ export interface ZarfComponentAction { * Hide the output of the command during package deployment (default false) */ mute?: boolean; - /** - * (Windows/cmd only) Whether to prefer running the command in the legacy command shell - * rather than powershell (see https://github.com/orgs/PowerShell/discussions/16569) (note: - * command conversion of commands like touch to New-Item will be disabled as well) - */ - preferLegacyShell?: boolean; /** * [Deprecated] (replaced by setVariables) (onDeploy/cmd only) The name of a variable to * update with the output of the command. This variable will be available to all remaining @@ -406,6 +400,11 @@ export interface ZarfComponentAction { * variables will be available to all remaining actions and components in the package. */ setVariables?: ZarfComponentActionSetVariable[]; + /** + * (cmd only) Indicates a preference for a shell for the provided cmd to be executed in on + * supported operating systems + */ + shell?: ZarfComponentActionShell; /** * Wait for a condition to be met before continuing. Must specify either cmd or wait for the * action. See the 'zarf tools wait-for' command for more info. @@ -429,6 +428,26 @@ export interface ZarfComponentActionSetVariable { sensitive?: boolean; } +/** + * (cmd only) Indicates a preference for a shell for the provided cmd to be executed in on + * supported operating systems + */ +export interface ZarfComponentActionShell { + /** + * (default 'sh') Indicates a preference for the shell to use on macOS systems + */ + darwin?: string; + /** + * (default 'sh') Indicates a preference for the shell to use on Linux systems + */ + linux?: string; + /** + * (default 'powershell') Indicates a preference for the shell to use on Windows systems + * (note that choosing 'cmd' will turn off migrations like touch -> New-Item) + */ + windows?: string; +} + /** * Wait for a condition to be met before continuing. Must specify either cmd or wait for the * action. See the 'zarf tools wait-for' command for more info. @@ -521,6 +540,11 @@ export interface ZarfComponentActionDefaults { * Hide the output of commands during execution (default false) */ mute?: boolean; + /** + * (cmd only) Indicates a preference for a shell for the provided cmd to be executed in on + * supported operating systems + */ + shell?: ZarfComponentActionShell; } export interface ZarfChart { @@ -1304,9 +1328,9 @@ const typeMap: any = { { json: "maxRetries", js: "maxRetries", typ: u(undefined, 0) }, { json: "maxTotalSeconds", js: "maxTotalSeconds", typ: u(undefined, 0) }, { json: "mute", js: "mute", typ: u(undefined, true) }, - { json: "preferLegacyShell", js: "preferLegacyShell", typ: u(undefined, true) }, { json: "setVariable", js: "setVariable", typ: u(undefined, "") }, { json: "setVariables", js: "setVariables", typ: u(undefined, a(r("ZarfComponentActionSetVariable"))) }, + { json: "shell", js: "shell", typ: u(undefined, r("ZarfComponentActionShell")) }, { json: "wait", js: "wait", typ: u(undefined, r("ZarfComponentActionWait")) }, ], false), "ZarfComponentActionSetVariable": o([ @@ -1314,6 +1338,11 @@ const typeMap: any = { { json: "name", js: "name", typ: "" }, { json: "sensitive", js: "sensitive", typ: u(undefined, true) }, ], false), + "ZarfComponentActionShell": o([ + { json: "darwin", js: "darwin", typ: u(undefined, "") }, + { json: "linux", js: "linux", typ: u(undefined, "") }, + { json: "windows", js: "windows", typ: u(undefined, "") }, + ], false), "ZarfComponentActionWait": o([ { json: "cluster", js: "cluster", typ: u(undefined, r("ZarfComponentActionWaitCluster")) }, { json: "network", js: "network", typ: u(undefined, r("ZarfComponentActionWaitNetwork")) }, @@ -1335,6 +1364,7 @@ const typeMap: any = { { json: "maxRetries", js: "maxRetries", typ: u(undefined, 0) }, { json: "maxTotalSeconds", js: "maxTotalSeconds", typ: u(undefined, 0) }, { json: "mute", js: "mute", typ: u(undefined, true) }, + { json: "shell", js: "shell", typ: u(undefined, r("ZarfComponentActionShell")) }, ], false), "ZarfChart": o([ { json: "gitPath", js: "gitPath", typ: u(undefined, "") }, diff --git a/zarf.schema.json b/zarf.schema.json index 783d22babd..66aa0a2474 100644 --- a/zarf.schema.json +++ b/zarf.schema.json @@ -316,9 +316,9 @@ "type": "string", "description": "The command to run. Must specify either cmd or wait for the action to do anything." }, - "preferLegacyShell": { - "type": "boolean", - "description": "(Windows/cmd only) Whether to prefer running the command in the legacy command shell rather than powershell (see https://github.com/orgs/PowerShell/discussions/16569) (note: command conversion of commands like touch to New-Item will be disabled as well)" + "shell": { + "$ref": "#/definitions/ZarfComponentActionShell", + "description": "(cmd only) Indicates a preference for a shell for the provided cmd to be executed in on supported operating systems" }, "setVariable": { "pattern": "^[A-Z0-9_]+$", @@ -370,6 +370,11 @@ }, "type": "array", "description": "Additional environment variables for commands" + }, + "shell": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/ZarfComponentActionShell", + "description": "(cmd only) Indicates a preference for a shell for the provided cmd to be executed in on supported operating systems" } }, "additionalProperties": false, @@ -437,6 +442,46 @@ "additionalProperties": false, "type": "object" }, + "ZarfComponentActionShell": { + "properties": { + "windows": { + "type": "string", + "description": "(default 'powershell') Indicates a preference for the shell to use on Windows systems (note that choosing 'cmd' will turn off migrations like touch -\u003e New-Item)", + "examples": [ + "powershell", + "cmd", + "pwsh", + "sh", + "bash", + "gsh" + ] + }, + "linux": { + "type": "string", + "description": "(default 'sh') Indicates a preference for the shell to use on Linux systems", + "examples": [ + "sh", + "bash", + "fish", + "zsh", + "pwsh" + ] + }, + "darwin": { + "type": "string", + "description": "(default 'sh') Indicates a preference for the shell to use on macOS systems", + "examples": [ + "sh", + "bash", + "fish", + "zsh", + "pwsh" + ] + } + }, + "additionalProperties": false, + "type": "object" + }, "ZarfComponentActionWait": { "properties": { "cluster": { From d2d1f1c38c8785734c3f9beab339f4f8bc9fea3f Mon Sep 17 00:00:00 2001 From: Wayne Starr Date: Fri, 14 Apr 2023 15:51:53 -0500 Subject: [PATCH 07/10] Make shell logic easier to read --- docs/4-user-guide/3-zarf-schema.md | 24 ++++++++++++------------ src/pkg/utils/exec/exec.go | 29 ++++++++++++++++------------- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/docs/4-user-guide/3-zarf-schema.md b/docs/4-user-guide/3-zarf-schema.md index 4577812f25..f755c68d5c 100644 --- a/docs/4-user-guide/3-zarf-schema.md +++ b/docs/4-user-guide/3-zarf-schema.md @@ -163,7 +163,7 @@ Must be one of: | -------- | -------- | | **Type** | `string` | -**Examples:** +**Examples:** "arm64", "amd64" @@ -882,7 +882,7 @@ Must be one of: | -------- | -------- | | **Type** | `string` | -**Examples:** +**Examples:** "powershell", "cmd", "pwsh", "sh", "bash", "gsh" @@ -903,7 +903,7 @@ Must be one of: | -------- | -------- | | **Type** | `string` | -**Examples:** +**Examples:** "sh", "bash", "fish", "zsh", "pwsh" @@ -924,7 +924,7 @@ Must be one of: | -------- | -------- | | **Type** | `string` | -**Examples:** +**Examples:** "sh", "bash", "fish", "zsh", "pwsh" @@ -1243,7 +1243,7 @@ Must be one of: | -------- | -------- | | **Type** | `string` | -**Examples:** +**Examples:** "Pod", "Deployment)" @@ -1266,7 +1266,7 @@ Must be one of: | -------- | -------- | | **Type** | `string` | -**Examples:** +**Examples:** "podinfo", "app=podinfo" @@ -1303,7 +1303,7 @@ Must be one of: | -------- | -------- | | **Type** | `string` | -**Examples:** +**Examples:** "Ready", "Available" @@ -1371,7 +1371,7 @@ Must be one of: | -------- | -------- | | **Type** | `string` | -**Examples:** +**Examples:** "localhost:8080", "1.1.1.1" @@ -1392,7 +1392,7 @@ Must be one of: | -------- | --------- | | **Type** | `integer` | -**Examples:** +**Examples:** 200, 404 @@ -1789,7 +1789,7 @@ Must be one of: | -------- | -------- | | **Type** | `string` | -**Examples:** +**Examples:** "OCI registry: oci://ghcr.io/stefanprodan/charts/podinfo", "helm chart repo: https://stefanprodan.github.io/podinfo", "git repo: https://github.com/stefanprodan/podinfo" @@ -1873,7 +1873,7 @@ Must be one of: | -------- | -------- | | **Type** | `string` | -**Example:** +**Example:** "charts/your-chart" @@ -2218,7 +2218,7 @@ Must be one of: | -------- | -------- | | **Type** | `string` | -**Example:** +**Example:** "app=data-injection" diff --git a/src/pkg/utils/exec/exec.go b/src/pkg/utils/exec/exec.go index 47f510294f..d407dba727 100644 --- a/src/pkg/utils/exec/exec.go +++ b/src/pkg/utils/exec/exec.go @@ -161,36 +161,39 @@ func GetOSShell(shellPref types.ZarfComponentActionShell) (string, string) { switch runtime.GOOS { case "windows": shell = shellPref.Windows - shellArgs = "-Command" + if shellPref.Windows == "" { + shell = "powershell" + } - if shellPref.Windows == "cmd" { + shellArgs = "-Command" + if shell == "cmd" { // Change shellArgs to /c if cmd is chosen shellArgs = "/c" - } else if !IsPowershell(shellPref.Windows) { + } else if !IsPowershell(shell) { // Change shellArgs to -c if a real shell is chosen shellArgs = "-c" - } else if shellPref.Windows == "" { - shell = "powershell" } case "darwin": shell = shellPref.Darwin - shellArgs = "-c" + if shellPref.Darwin == "" { + shell = "sh" + } - if IsPowershell(shellPref.Darwin) { + shellArgs = "-c" + if IsPowershell(shell) { // Change shellArgs to -Command if pwsh is chosen shellArgs = "-Command" - } else if shellPref.Darwin == "" { - shell = "sh" } case "linux": shell = shellPref.Linux - shellArgs = "-c" + if shellPref.Linux == "" { + shell = "sh" + } - if IsPowershell(shellPref.Linux) { + shellArgs = "-c" + if IsPowershell(shell) { // Change shellArgs to -Command if pwsh is chosen shellArgs = "-Command" - } else if shellPref.Linux == "" { - shell = "sh" } default: shell = "sh" From 9311cb8be61116781abb6a011da9756ed4a3d04b Mon Sep 17 00:00:00 2001 From: Wayne Starr Date: Fri, 14 Apr 2023 15:53:17 -0500 Subject: [PATCH 08/10] Make shell logic _even easier_ to read --- src/pkg/utils/exec/exec.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/pkg/utils/exec/exec.go b/src/pkg/utils/exec/exec.go index d407dba727..09ca2a4794 100644 --- a/src/pkg/utils/exec/exec.go +++ b/src/pkg/utils/exec/exec.go @@ -160,9 +160,9 @@ func GetOSShell(shellPref types.ZarfComponentActionShell) (string, string) { switch runtime.GOOS { case "windows": - shell = shellPref.Windows - if shellPref.Windows == "" { - shell = "powershell" + shell = "powershell" + if shellPref.Windows != "" { + shell = shellPref.Windows } shellArgs = "-Command" @@ -174,9 +174,9 @@ func GetOSShell(shellPref types.ZarfComponentActionShell) (string, string) { shellArgs = "-c" } case "darwin": - shell = shellPref.Darwin - if shellPref.Darwin == "" { - shell = "sh" + shell = "sh" + if shellPref.Darwin != "" { + shell = shellPref.Darwin } shellArgs = "-c" @@ -185,9 +185,9 @@ func GetOSShell(shellPref types.ZarfComponentActionShell) (string, string) { shellArgs = "-Command" } case "linux": - shell = shellPref.Linux - if shellPref.Linux == "" { - shell = "sh" + shell = "sh" + if shellPref.Linux != "" { + shell = shellPref.Linux } shellArgs = "-c" From f29ca7f05a446fce9188fbad5bffa157fb63b3ca Mon Sep 17 00:00:00 2001 From: Wayne Starr Date: Fri, 14 Apr 2023 15:55:37 -0500 Subject: [PATCH 09/10] Fix example --- examples/component-actions/zarf.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/component-actions/zarf.yaml b/examples/component-actions/zarf.yaml index c9fb21d3d8..f84b407d41 100644 --- a/examples/component-actions/zarf.yaml +++ b/examples/component-actions/zarf.yaml @@ -40,7 +40,8 @@ components: - cmd: sleep 1 - cmd: echo "I can print!" # prefer to run the above command in "cmd" instead of "powershell" on Windows - preferLegacyShell: true + shell: + windows: cmd - cmd: sleep 1 - cmd: | echo "multiline!" From 6c14ceb934fd12c070bd8fe09e9ae59cfa6c7147 Mon Sep 17 00:00:00 2001 From: Wayne Starr Date: Fri, 14 Apr 2023 16:09:49 -0500 Subject: [PATCH 10/10] fixup docs --- docs/4-user-guide/3-zarf-schema.md | 24 ++++++++++++------------ src/pkg/packager/actions.go | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/4-user-guide/3-zarf-schema.md b/docs/4-user-guide/3-zarf-schema.md index f755c68d5c..4577812f25 100644 --- a/docs/4-user-guide/3-zarf-schema.md +++ b/docs/4-user-guide/3-zarf-schema.md @@ -163,7 +163,7 @@ Must be one of: | -------- | -------- | | **Type** | `string` | -**Examples:** +**Examples:** "arm64", "amd64" @@ -882,7 +882,7 @@ Must be one of: | -------- | -------- | | **Type** | `string` | -**Examples:** +**Examples:** "powershell", "cmd", "pwsh", "sh", "bash", "gsh" @@ -903,7 +903,7 @@ Must be one of: | -------- | -------- | | **Type** | `string` | -**Examples:** +**Examples:** "sh", "bash", "fish", "zsh", "pwsh" @@ -924,7 +924,7 @@ Must be one of: | -------- | -------- | | **Type** | `string` | -**Examples:** +**Examples:** "sh", "bash", "fish", "zsh", "pwsh" @@ -1243,7 +1243,7 @@ Must be one of: | -------- | -------- | | **Type** | `string` | -**Examples:** +**Examples:** "Pod", "Deployment)" @@ -1266,7 +1266,7 @@ Must be one of: | -------- | -------- | | **Type** | `string` | -**Examples:** +**Examples:** "podinfo", "app=podinfo" @@ -1303,7 +1303,7 @@ Must be one of: | -------- | -------- | | **Type** | `string` | -**Examples:** +**Examples:** "Ready", "Available" @@ -1371,7 +1371,7 @@ Must be one of: | -------- | -------- | | **Type** | `string` | -**Examples:** +**Examples:** "localhost:8080", "1.1.1.1" @@ -1392,7 +1392,7 @@ Must be one of: | -------- | --------- | | **Type** | `integer` | -**Examples:** +**Examples:** 200, 404 @@ -1789,7 +1789,7 @@ Must be one of: | -------- | -------- | | **Type** | `string` | -**Examples:** +**Examples:** "OCI registry: oci://ghcr.io/stefanprodan/charts/podinfo", "helm chart repo: https://stefanprodan.github.io/podinfo", "git repo: https://github.com/stefanprodan/podinfo" @@ -1873,7 +1873,7 @@ Must be one of: | -------- | -------- | | **Type** | `string` | -**Example:** +**Example:** "charts/your-chart" @@ -2218,7 +2218,7 @@ Must be one of: | -------- | -------- | | **Type** | `string` | -**Example:** +**Example:** "app=data-injection" diff --git a/src/pkg/packager/actions.go b/src/pkg/packager/actions.go index 2a620dae97..66887890b0 100644 --- a/src/pkg/packager/actions.go +++ b/src/pkg/packager/actions.go @@ -203,7 +203,7 @@ func actionCmdMutation(cmd string, shellPref types.ZarfComponentActionShell) (st cmd = strings.ReplaceAll(cmd, "./zarf ", binaryPath+" ") // Make commands 'more' compatible with Windows OS PowerShell - if runtime.GOOS == "windows" && exec.IsPowershell(shellPref.Windows) { + if runtime.GOOS == "windows" && (exec.IsPowershell(shellPref.Windows) || shellPref.Windows == "") { // Replace "touch" with "New-Item" on Windows as it's a common command, but not POSIX so not aliased by M$. // See https://mathieubuisson.github.io/powershell-linux-bash/ & // http://web.cs.ucla.edu/~miryung/teaching/EE461L-Spring2012/labs/posix.html for more details.