-
Notifications
You must be signed in to change notification settings - Fork 108
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support modifier flags such as '-c' being placed after the profile na…
…me (#45) * initial * working * added int flag implementation * added test for new flag functions * added back normalize function * add back copy function * update descriptions Co-authored-by: meyerjrr <[email protected]>
- Loading branch information
1 parent
66a8cec
commit 3ee7eac
Showing
8 changed files
with
253 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package cfflags | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"testing" | ||
|
||
"github.com/bmizerany/assert" | ||
"github.com/urfave/cli/v2" | ||
) | ||
|
||
var testingFlags = []cli.Flag{ | ||
&cli.BoolFlag{Name: "testbool", Aliases: []string{"c"}, Usage: "Open a web console to the role"}, | ||
&cli.StringFlag{Name: "teststringservice", Aliases: []string{"s"}, Usage: "Specify a service to open the console into"}, | ||
&cli.StringFlag{Name: "teststringregion", Aliases: []string{"r"}, Usage: "Specify a service to open the console into"}, | ||
} | ||
|
||
func TestFlagsPassToCFFlags(t *testing.T) { | ||
|
||
app := cli.App{ | ||
Name: "test", | ||
|
||
Flags: testingFlags, | ||
|
||
Action: func(c *cli.Context) error { | ||
|
||
assumeFlags, err := New("assumeFlags", testingFlags, c) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
booloutcome := assumeFlags.Bool("testbool") | ||
|
||
serviceoutcome := assumeFlags.String("teststringservice") | ||
regionoutcome := assumeFlags.String("teststringregion") | ||
|
||
assert.Equal(t, booloutcome, true) | ||
assert.Equal(t, serviceoutcome, "iam") | ||
assert.Equal(t, regionoutcome, "region-name") | ||
return nil | ||
}, | ||
EnableBashCompletion: true, | ||
} | ||
|
||
os.Args = []string{"", "test-role", "-c", "-s", "iam", "-r", "region-name"} | ||
|
||
err := app.Run(os.Args) | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "%s\n", err) | ||
os.Exit(1) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
package cfflags | ||
|
||
import ( | ||
"errors" | ||
"flag" | ||
"io/ioutil" | ||
"os" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/urfave/cli/v2" | ||
) | ||
|
||
type Flags struct { | ||
*flag.FlagSet | ||
urFavFlags []cli.Flag | ||
} | ||
|
||
// The purpose of this package is to allow the assume cli command to accept flags on either side of the "role" arg | ||
// for example, `assume -c my-role -region=us-east-1` by default, urfav-cli, the cli framework that we are using does not | ||
// support this usage pattern. | ||
// | ||
// We have extracted some methods from the original urfav-cli library to mimic the original behaviour but processing all the flags. | ||
// to use this in a command, | ||
// This package interacts with os.Args directly | ||
// | ||
// allFlags := cfflags.New("name",GlobalFlagsList, c) | ||
// allFlags.String("region") | ||
func New(name string, flags []cli.Flag, c *cli.Context) (*Flags, error) { | ||
set := flag.NewFlagSet(name, flag.ContinueOnError) | ||
for _, f := range flags { | ||
if err := f.Apply(set); err != nil { | ||
return nil, err | ||
} | ||
} | ||
set.SetOutput(ioutil.Discard) | ||
ca := []string{} | ||
ca = append(ca, c.Args().Slice()...) | ||
// context.Args() for this command will ONLY contain the role and any flags provided after the role | ||
// this slice of os.Args will only contain flags and not the role if it was provided | ||
ag := []string{} | ||
ag = append(ag, os.Args[1:len(os.Args)-len(ca)]...) | ||
ag = append(ag, ca[1:]...) | ||
err := normalizeFlags(flags, set) | ||
if err != nil { | ||
return nil, err | ||
} | ||
err = set.Parse(ag) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &Flags{FlagSet: set, urFavFlags: flags}, nil | ||
} | ||
func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) { | ||
switch ff.Value.(type) { | ||
case cli.Serializer: | ||
_ = set.Set(name, ff.Value.(cli.Serializer).Serialize()) | ||
default: | ||
_ = set.Set(name, ff.Value.String()) | ||
} | ||
} | ||
|
||
func normalizeFlags(flags []cli.Flag, set *flag.FlagSet) error { | ||
visited := make(map[string]bool) | ||
set.Visit(func(f *flag.Flag) { | ||
visited[f.Name] = true | ||
}) | ||
for _, f := range flags { | ||
parts := f.Names() | ||
if len(parts) == 1 { | ||
continue | ||
} | ||
var ff *flag.Flag | ||
for _, name := range parts { | ||
name = strings.Trim(name, " ") | ||
if visited[name] { | ||
if ff != nil { | ||
return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name) | ||
} | ||
ff = set.Lookup(name) | ||
} | ||
} | ||
if ff == nil { | ||
continue | ||
} | ||
for _, name := range parts { | ||
name = strings.Trim(name, " ") | ||
if !visited[name] { | ||
copyFlag(name, ff, set) | ||
} | ||
} | ||
} | ||
return nil | ||
} | ||
func (set *Flags) searchFS(name string) []string { | ||
for _, f := range set.urFavFlags { | ||
for _, n := range f.Names() { | ||
if n == name { | ||
return f.Names() | ||
} | ||
} | ||
} | ||
return nil | ||
} | ||
func (set *Flags) String(name string) string { | ||
names := set.searchFS(name) | ||
for _, n := range names { | ||
f := set.Lookup(n) | ||
if f != nil { | ||
parsed := f.Value.String() | ||
if parsed != "" { | ||
return parsed | ||
} | ||
} | ||
} | ||
return "" | ||
} | ||
|
||
func (set *Flags) Bool(name string) bool { | ||
names := set.searchFS(name) | ||
for _, n := range names { | ||
f := set.Lookup(n) | ||
if f != nil { | ||
parsed, _ := strconv.ParseBool(f.Value.String()) | ||
if parsed { | ||
return parsed | ||
} | ||
} | ||
} | ||
return false | ||
} | ||
|
||
func (set *Flags) Int(name string) int { | ||
names := set.searchFS(name) | ||
for _, n := range names { | ||
f := set.Lookup(n) | ||
if f != nil { | ||
parsed, err := strconv.ParseInt(f.Value.String(), 0, 64) | ||
if err != nil { | ||
return int(parsed) | ||
} | ||
} | ||
} | ||
return 0 | ||
} | ||
|
||
func (set *Flags) Int64(name string) int64 { | ||
names := set.searchFS(name) | ||
for _, n := range names { | ||
f := set.Lookup(n) | ||
if f != nil { | ||
parsed, err := strconv.ParseInt(f.Value.String(), 0, 64) | ||
if err != nil { | ||
return parsed | ||
} | ||
} | ||
} | ||
return 0 | ||
} |