Skip to content

Commit

Permalink
feat: Add IOStreams inside command/io and add command/args package
Browse files Browse the repository at this point in the history
With IOStreams from k8s.io/cli-runtime creates a better methods of
providing data streams to cli while making it easy to create tests
inside those packages

command/args is a set of methods to read and extract data from cli
arguments making it easy to integrate into other clis and into task
scripts
  • Loading branch information
danielfbm committed Aug 22, 2022
1 parent 98126ec commit a121dec
Show file tree
Hide file tree
Showing 13 changed files with 546 additions and 10 deletions.
2 changes: 1 addition & 1 deletion apis/data/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 29 additions & 0 deletions command/args/args_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
Copyright 2022 The Katanomi Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package args_test

import (
"testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

func TestArgs(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Args Suite")
}
50 changes: 50 additions & 0 deletions command/args/array_values.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
Copyright 2022 The Katanomi Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package args

import (
"context"
"fmt"
"strings"
)

// GetArrayValues returns a list of values for a one flag in a set of given arguments
// args should be all the arguments to be interpreted. i.e --arg1 key1=value1 key2=value2 --arg2 key3=value3
// flag should be the flag name to select keys and values from, i.e arg1 or arg2 in the example above
func GetArrayValues(ctx context.Context, args []string, flag string) (values []string, ok bool) {
values = make([]string, 0, len(args))
offset := -1
for i, arg := range args {
if arg == fmt.Sprintf("--%s", flag) {
// this is the key
// save offset
offset = i + 1
ok = true
} else if ok && strings.HasPrefix(arg, "--") {
// found another flag and
// already passed all keys, quit the loop
values = args[offset:i]
break
} else if ok && i+1 == len(args) {
// this is the last flag so needs to get it all
values = args[offset : i+1]
} else {
// no-op
}
}
return
}
110 changes: 110 additions & 0 deletions command/args/array_values_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
Copyright 2022 The Katanomi Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package args_test

import (
"context"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"github.com/katanomi/pkg/command/args"
)

var _ = Describe("GetArrayValues", func() {
var (
ctx context.Context
cliArgs []string
flag string
result []string
ok bool
)
BeforeEach(func() {
ctx = context.Background()
cliArgs = []string{}
flag = ""
})
JustBeforeEach(func() {
result, ok = args.GetArrayValues(ctx, cliArgs, flag)
})
When("args are nil", func() {
BeforeEach(func() {
cliArgs = nil
})
It("should return empty array with false ok", func() {
Expect(result).To(Equal([]string{}))
Expect(ok).To(BeFalse())
})
})
When("args does not have the flag", func() {
BeforeEach(func() {
cliArgs = []string{"--flag1", "key=value", "--other-flag", "another-flag-key=123"}
flag = "non-existing-flag"
})
It("should return empty array with false ok", func() {
Expect(result).To(Equal([]string{}))
Expect(ok).To(BeFalse())
})
})
When("flag does not have items", func() {
BeforeEach(func() {
cliArgs = []string{"--flag1", "--other-flag", "another-flag-key=123"}
flag = "flag1"
})
It("should return empty slice with true ok", func() {
Expect(result).To(Equal([]string{}))
Expect(ok).To(BeTrue())
})
})
When("flag has key-value pairs", func() {
BeforeEach(func() {
cliArgs = []string{"--flag1", "this-is-key=this-is-value", "this-is-another-key=this-is-another-value", "--other-flag", "another-flag-key=123"}
flag = "flag1"
})
It("should return empty map with false ok", func() {
Expect(result).To(Equal([]string{
"this-is-key=this-is-value",
"this-is-another-key=this-is-another-value",
}))
Expect(ok).To(BeTrue())
})
})
When("only has one flag", func() {
BeforeEach(func() {
cliArgs = []string{"--flag1", "this-is-key=this-is-value", "this-is-another-key=this-is-another-value"}
flag = "flag1"
})
It("should return an slice with values with true ok", func() {
Expect(result).To(Equal([]string{
"this-is-key=this-is-value",
"this-is-another-key=this-is-another-value",
}))
Expect(ok).To(BeTrue())
})
})

When("flag with no values", func() {
BeforeEach(func() {
cliArgs = []string{"--flag1", "--another-flag"}
flag = "flag1"
})
It("should return empty slice with true ok", func() {
Expect(result).To(Equal([]string{}))
Expect(ok).To(BeTrue())
})
})
})
19 changes: 19 additions & 0 deletions command/args/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
Copyright 2022 The Katanomi Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package args stores useful methods to parse and extract
// data from extra arguments given to cli commands
package args
40 changes: 40 additions & 0 deletions command/args/key_value.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
Copyright 2022 The Katanomi Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package args

import (
"context"
// "fmt"
"strings"
)

// GetKeyValues returns the set of keys and values for one flag in a set of given arguments
// args should be all the arguments to be interpreted. i.e --arg1 key1=value1 key2=value2 --arg2 key3=value3
// flag should be the flag name to select keys and values from, i.e arg1 or arg2 in the example above
func GetKeyValues(ctx context.Context, args []string, flag string) (keyValues map[string]string, ok bool) {
keyValues = map[string]string{}
var values []string
if values, ok = GetArrayValues(ctx, args, flag); ok {
for _, arg := range values {
split := strings.SplitN(arg, "=", 2)
if len(split) == 2 {
keyValues[split[0]] = split[1]
}
}
}
return
}
99 changes: 99 additions & 0 deletions command/args/key_value_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
Copyright 2022 The Katanomi Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package args_test

import (
"context"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"github.com/katanomi/pkg/command/args"
)

var _ = Describe("GetKeyValues", func() {
var (
ctx context.Context
cliArgs []string
flag string
result map[string]string
ok bool
)
BeforeEach(func() {
ctx = context.Background()
cliArgs = []string{}
flag = ""
})
JustBeforeEach(func() {
result, ok = args.GetKeyValues(ctx, cliArgs, flag)
})
When("args are nil", func() {
BeforeEach(func() {
cliArgs = nil
})
It("should return empty map with false ok", func() {
Expect(result).To(Equal(map[string]string{}))
Expect(ok).To(BeFalse())
})
})
When("args does not have the flag", func() {
BeforeEach(func() {
cliArgs = []string{"--flag1", "key=value", "--other-flag", "another-flag-key=123"}
flag = "non-existing-flag"
})
It("should return empty map with false ok", func() {
Expect(result).To(Equal(map[string]string{}))
Expect(ok).To(BeFalse())
})
})
When("flag does not have items", func() {
BeforeEach(func() {
cliArgs = []string{"--flag1", "--other-flag", "another-flag-key=123"}
flag = "flag1"
})
It("should return empty map with false ok", func() {
Expect(result).To(Equal(map[string]string{}))
Expect(ok).To(BeTrue())
})
})
When("flag does not have key-value pairs", func() {
BeforeEach(func() {
cliArgs = []string{"--flag1", "this-is-a-value", "this-is-another-value", "--other-flag", "another-flag-key=123"}
flag = "flag1"
})
It("should return empty map with true ok", func() {
Expect(result).To(Equal(map[string]string{}))
Expect(ok).To(BeTrue())
})
})
When("flag has key-value pairs", func() {
BeforeEach(func() {
cliArgs = []string{
"--flag1", "this-is-key=this-is-value", "this-is-another-key=this-is-another-value", "key=with=multiple=equalsigns",
"--other-flag", "another-flag-key=123"}
flag = "flag1"
})
It("should return map with keys and values and true ok", func() {
Expect(result).To(Equal(map[string]string{
"this-is-key": "this-is-value",
"this-is-another-key": "this-is-another-value",
"key": "with=multiple=equalsigns",
}))
Expect(ok).To(BeTrue())
})
})
})
Loading

0 comments on commit a121dec

Please sign in to comment.