diff --git a/command.go b/command.go index d1472c61..104c0e71 100644 --- a/command.go +++ b/command.go @@ -210,6 +210,54 @@ func (c *Command) Resolve(pth []string) ([]*Command, error) { return cmds, nil } +// FilterSubcommands returns a subset of the subcommands in this root with only the ones +// passed as argument with the format: array of strings containing slash-delimited +// subcommands as: +// * "cmd/subcmd/subsubcmd" +// * "block/get" +// * "dag/put" +// If a command path as "0/1/2" is specified only midway like "0/1" it is interpreted +// as allowing all of its subcommands, like "0/1/*". +func (c *Command) FilterSubcommands(subCommands []string) (map[string]*Command, error) { + filteredRoot := make(map[string]*Command) + + for _, s := range subCommands { + cmdName := strings.Split(s, "/") + cmdPath, err := c.Resolve(cmdName) + if err != nil { + return nil, err + } + // Discard the root command, we return the map of its subcommands + // (just because go-ipfs consumes it that way). + cmdPath = cmdPath[1:] + + filtered := filteredRoot + for i, node := range cmdPath { + name := cmdName[i] + if i == len(cmdPath)-1 { + // Last specified path, allow any subcommand so just copy the + // entire thing. + filtered[name] = node + } else { + // More qualifiers to come in the path, only copy the entry + // (if needed) with no subcommands. + if _, ok := filtered[name]; !ok { + filtered[name] = node.copyWithoutSubCommands() + } + } + filtered = filtered[name].Subcommands + } + } + + return filteredRoot, nil +} + +func (c *Command) copyWithoutSubCommands() *Command { + copied := *c + copied.Subcommands = make(map[string]*Command) + return &copied +} + // Get resolves and returns the Command addressed by path func (c *Command) Get(path []string) (*Command, error) { cmds, err := c.Resolve(path) diff --git a/command_test.go b/command_test.go index 89f60748..d7688c28 100644 --- a/command_test.go +++ b/command_test.go @@ -5,8 +5,12 @@ import ( "errors" "fmt" "io" + "sort" + "strconv" "testing" "time" + + "github.com/stretchr/testify/require" ) // NOTE: helpers nopCloser, testEmitter, noop and writeCloser are defined in helpers_test.go @@ -127,6 +131,79 @@ func TestResolving(t *testing.T) { } } +func fullCmdTree(numberOfSubs int, depth int) *Command { + cmd := &Command{} + cmd.Subcommands = make(map[string]*Command) + for i := 0; i < numberOfSubs; i++ { + var sub *Command + if depth == 0 { + sub = &Command{} + } else { + sub = fullCmdTree(numberOfSubs, depth-1) + } + cmd.Subcommands[strconv.FormatInt(int64(i), 10)] = sub + } + return cmd +} + +func listAllCmds(cmd *Command, prefix string) []string { + if cmd.Subcommands == nil || len(cmd.Subcommands) == 0 { + if prefix == "" { + return []string{} + } + return []string{prefix} + } + + subStr := make([]string, 0) + for k, s := range cmd.Subcommands { + newPrefix := k + if prefix != "" { + newPrefix = prefix + "/" + newPrefix + } + subStr = append(subStr, listAllCmds(s, newPrefix)...) + } + sort.Strings(subStr) + return subStr +} + +func TestFilterSubCommands(t *testing.T) { + cmd := fullCmdTree(2, 2) + all := []string{ + "0/0/0", + "0/0/1", + "0/1/0", + "0/1/1", + "1/0/0", + "1/0/1", + "1/1/0", + "1/1/1"} + require.Equal(t, all, listAllCmds(cmd, "")) + + checkFilter := func(filter []string, expected []string) { + filtered, err := cmd.FilterSubcommands(filter) + require.NoError(t, err) + require.Equal(t, expected, listAllCmds(&Command{Subcommands: filtered}, "")) + } + + checkFilter(nil, []string{}) + checkFilter(all, all) + checkFilter([]string{"0/0/0"}, []string{"0/0/0"}) + checkFilter([]string{"0/0"}, []string{ // implicit subcommands + "0/0/0", + "0/0/1"}) + checkFilter([]string{"0"}, []string{ // even more implicit subcommands + "0/0/0", + "0/0/1", + "0/1/0", + "0/1/1"}) + checkFilter([]string{"1", "1/1"}, []string{ // redundant second filter + "1/0/0", + "1/0/1", + "1/1/0", + "1/1/1"}) + checkFilter([]string{"0/0/0", "1/1/1"}, []string{"0/0/0", "1/1/1"}) // independent +} + func TestWalking(t *testing.T) { cmdA := &Command{ Subcommands: map[string]*Command{ diff --git a/go.mod b/go.mod index 075bc419..7b1ec2aa 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/ipfs/go-ipfs-files v0.0.8 github.com/ipfs/go-log v1.0.4 github.com/rs/cors v1.7.0 + github.com/stretchr/testify v1.7.1 github.com/texttheater/golang-levenshtein v0.0.0-20180516184445-d188e65d659e golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d ) diff --git a/go.sum b/go.sum index 9d2390bd..0ac63f88 100644 --- a/go.sum +++ b/go.sum @@ -18,8 +18,10 @@ github.com/ipfs/go-log/v2 v2.0.5 h1:fL4YI+1g5V/b1Yxr1qAiXTMg1H8z9vx/VmJxBuQMHvU= github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -32,8 +34,9 @@ github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/texttheater/golang-levenshtein v0.0.0-20180516184445-d188e65d659e h1:T5PdfK/M1xyrHwynxMIVMWLS7f/qHwfslZphxtGnw7s= github.com/texttheater/golang-levenshtein v0.0.0-20180516184445-d188e65d659e/go.mod h1:XDKHRm5ThF8YJjx001LtgelzsoaEcvnA7lVWz9EeX3g= go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= @@ -68,9 +71,11 @@ golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64 golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/version.json b/version.json index 8047016a..ada6e882 100644 --- a/version.json +++ b/version.json @@ -1,3 +1,3 @@ { - "version": "v0.8.1" + "version": "v0.8.2" }