From 3a9bbd7c7646e7ee80325097c1195105b0105712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Sun, 22 Nov 2020 22:03:00 +0100 Subject: [PATCH] Support arguments in post render MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jan-Otto Kröpke --- pkg/postrender/exec.go | 12 +++++++-- pkg/postrender/exec_test.go | 50 +++++++++++++++++++++++++++++++------ 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/pkg/postrender/exec.go b/pkg/postrender/exec.go index c3a45a215..b38e7a1c8 100644 --- a/pkg/postrender/exec.go +++ b/pkg/postrender/exec.go @@ -21,8 +21,8 @@ import ( "io" "os/exec" "path/filepath" - "strings" + "github.com/mattn/go-shellwords" "github.com/pkg/errors" ) @@ -36,7 +36,15 @@ type execRender struct { // contain any separators, it will search in $PATH, otherwise it will resolve // any relative paths to a fully qualified path func NewExec(command string) (PostRenderer, error) { - commandList := strings.Split(command, " ") + parser := shellwords.NewParser() + parser.ParseEnv = false + parser.ParseBacktick = false + + commandList, err := parser.Parse(command) + if err != nil { + return nil, err + } + binaryPath, args := commandList[0], commandList[1:] fullPath, err := getFullPath(binaryPath) diff --git a/pkg/postrender/exec_test.go b/pkg/postrender/exec_test.go index 8275cb0e2..071d574c4 100644 --- a/pkg/postrender/exec_test.go +++ b/pkg/postrender/exec_test.go @@ -22,6 +22,7 @@ import ( "os" "path/filepath" "runtime" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -37,7 +38,7 @@ sed s/FOOTEST/${1:-BARTEST}/g <&0 func TestGetFullPath(t *testing.T) { is := assert.New(t) t.Run("full path resolves correctly", func(t *testing.T) { - testpath, cleanup := setupTestingScript(t) + testpath, cleanup := setupTestingScript(t, "post-render-test.sh") defer cleanup() fullPath, err := getFullPath(testpath) @@ -46,7 +47,7 @@ func TestGetFullPath(t *testing.T) { }) t.Run("relative path resolves correctly", func(t *testing.T) { - testpath, cleanup := setupTestingScript(t) + testpath, cleanup := setupTestingScript(t, "post-render-test.sh") defer cleanup() currentDir, err := os.Getwd() @@ -59,7 +60,7 @@ func TestGetFullPath(t *testing.T) { }) t.Run("binary in PATH resolves correctly", func(t *testing.T) { - testpath, cleanup := setupTestingScript(t) + testpath, cleanup := setupTestingScript(t, "post-render-test.sh") defer cleanup() realPath := os.Getenv("PATH") @@ -113,7 +114,7 @@ func TestExecRun(t *testing.T) { t.Skip("skipping on windows") } is := assert.New(t) - testpath, cleanup := setupTestingScript(t) + testpath, cleanup := setupTestingScript(t, "post-render-test.sh") defer cleanup() renderer, err := NewExec(testpath) @@ -130,7 +131,7 @@ func TestExecRunWithArgs(t *testing.T) { t.Skip("skipping on windows") } is := assert.New(t) - testpath, cleanup := setupTestingScript(t) + testpath, cleanup := setupTestingScript(t, "post-render-test.sh") defer cleanup() renderer, err := NewExec(testpath + " ARGUMENT") @@ -141,12 +142,47 @@ func TestExecRunWithArgs(t *testing.T) { is.Contains(output.String(), "ARGUMENT") } -func setupTestingScript(t *testing.T) (filepath string, cleanup func()) { +func TestExecRunWithArgsAndSpaceInCommandUsingBackslash(t *testing.T) { + if runtime.GOOS == "windows" { + // the actual Run test uses a basic sed example, so skip this test on windows + t.Skip("skipping on windows") + } + is := assert.New(t) + testpath, cleanup := setupTestingScript(t, "post render test.sh") + testpathEscaped := strings.ReplaceAll(testpath, " ", "\\ ") + defer cleanup() + + renderer, err := NewExec(testpathEscaped + " ARGUMENT") + require.NoError(t, err) + + output, err := renderer.Run(bytes.NewBufferString("FOOTEST")) + is.NoError(err) + is.Contains(output.String(), "ARGUMENT") +} + +func TestExecRunWithArgsAndSpaceInCommandUsingQuotes(t *testing.T) { + if runtime.GOOS == "windows" { + // the actual Run test uses a basic sed example, so skip this test on windows + t.Skip("skipping on windows") + } + is := assert.New(t) + testpath, cleanup := setupTestingScript(t, "post render test.sh") + defer cleanup() + + renderer, err := NewExec("'" + testpath + "' ARGUMENT") + require.NoError(t, err) + + output, err := renderer.Run(bytes.NewBufferString("FOOTEST")) + is.NoError(err) + is.Contains(output.String(), "ARGUMENT") +} + +func setupTestingScript(t *testing.T, fileName string) (filepath string, cleanup func()) { t.Helper() tempdir := ensure.TempDir(t) - f, err := ioutil.TempFile(tempdir, "post-render-test.sh") + f, err := ioutil.TempFile(tempdir, fileName) if err != nil { t.Fatalf("unable to create tempfile for testing: %s", err) }