kubectl: allow users to use args with KUBECTL_EXTERNAL_DIFF

Currently, if users try to use external diff command with arguments
will fail because the entire command won't be available through $PATH.
This patch allow users to use external diff tools with args (or not)
via KUBECTL_EXTERNAL_DIFF env.

Reference: https://github.com/kubernetes/kubectl/issues/937

Signed-off-by: Douglas Schilling Landgraf <dougsland@redhat.com>
This commit is contained in:
Douglas Schilling Landgraf 2020-10-04 23:29:27 -04:00
parent 086b65a000
commit a6158c01b9
2 changed files with 39 additions and 14 deletions

View File

@ -22,6 +22,8 @@ import (
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strings"
"github.com/jonboulle/clockwork"
"github.com/spf13/cobra"
@ -55,7 +57,10 @@ var (
Output is always YAML.
KUBECTL_EXTERNAL_DIFF environment variable can be used to select your own
diff command. By default, the "diff" command available in your path will be
diff command. Users can use external commands with params too, example:
KUBECTL_EXTERNAL_DIFF="colordiff -N -u"
By default, the "diff" command available in your path will be
run with "-u" (unified diff) and "-N" (treat absent files as empty) options.
Exit status:
@ -168,7 +173,18 @@ type DiffProgram struct {
func (d *DiffProgram) getCommand(args ...string) (string, exec.Cmd) {
diff := ""
if envDiff := os.Getenv("KUBECTL_EXTERNAL_DIFF"); envDiff != "" {
diff = envDiff
diffCommand := strings.Split(envDiff, " ")
diff = diffCommand[0]
if len(diffCommand) > 1 {
// Regex accepts: Alphanumeric (case-insensitive) and dash
isValidChar := regexp.MustCompile(`^[a-zA-Z0-9-]+$`).MatchString
for i := 1; i < len(diffCommand); i++ {
if isValidChar(diffCommand[i]) {
args = append(args, diffCommand[i])
}
}
}
} else {
diff = "diff"
args = append([]string{"-u", "-N"}, args...)

View File

@ -52,18 +52,27 @@ func (f *FakeObject) Live() runtime.Object {
}
func TestDiffProgram(t *testing.T) {
os.Setenv("KUBECTL_EXTERNAL_DIFF", "echo")
streams, _, stdout, _ := genericclioptions.NewTestIOStreams()
diff := DiffProgram{
IOStreams: streams,
Exec: exec.New(),
}
err := diff.Run("one", "two")
if err != nil {
t.Fatal(err)
}
if output := stdout.String(); output != "one two\n" {
t.Fatalf(`stdout = %q, expected "one two\n"`, output)
externalDiffCommands := [3]string{"diff", "diff -ruN", "diff --report-identical-files"}
for i, c := range externalDiffCommands {
os.Setenv("KUBECTL_EXTERNAL_DIFF", c)
streams, _, stdout, _ := genericclioptions.NewTestIOStreams()
diff := DiffProgram{
IOStreams: streams,
Exec: exec.New(),
}
err := diff.Run("/dev/zero", "/dev/zero")
if err != nil {
t.Fatal(err)
}
// Testing diff --report-identical-files
if i == 2 {
output_msg := "Files /dev/zero and /dev/zero are identical\n"
if output := stdout.String(); output != output_msg {
t.Fatalf(`stdout = %q, expected = %s"`, output, output_msg)
}
}
}
}