From 90e5c7ffa8b7f636cf1bbecaf5c800b2b4331421 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Tue, 18 Nov 2014 23:02:22 -0800 Subject: [PATCH 01/19] pin: Added a Pinner#Set function to retrieve the set of pinned keys --- pin/pin.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pin/pin.go b/pin/pin.go index 60828b597..1d840c6bc 100644 --- a/pin/pin.go +++ b/pin/pin.go @@ -33,6 +33,7 @@ type Pinner interface { Unpin(util.Key, bool) error Flush() error GetManual() ManualPinner + Set() set.BlockSet } // ManualPinner is for manually editing the pin structure @@ -207,6 +208,11 @@ func LoadPinner(d ds.Datastore, dserv mdag.DAGService) (Pinner, error) { return p, nil } +// Set returns a blockset of directly pinned keys +func (p *pinner) Set() set.BlockSet { + return p.directPin +} + // Flush encodes and writes pinner keysets to the datastore func (p *pinner) Flush() error { p.lock.RLock() From afc7b6f48d7ddfd974b44d53e7bf988565d2c914 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Tue, 18 Nov 2014 23:02:33 -0800 Subject: [PATCH 02/19] core/commands: Added a 'pin ls' command --- core/commands/pin.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/core/commands/pin.go b/core/commands/pin.go index 33060de60..836495240 100644 --- a/core/commands/pin.go +++ b/core/commands/pin.go @@ -6,6 +6,7 @@ import ( cmds "github.com/jbenet/go-ipfs/commands" "github.com/jbenet/go-ipfs/core" "github.com/jbenet/go-ipfs/merkledag" + u "github.com/jbenet/go-ipfs/util" ) var pinCmd = &cmds.Command{ @@ -16,6 +17,7 @@ var pinCmd = &cmds.Command{ Subcommands: map[string]*cmds.Command{ "add": addPinCmd, "rm": rmPinCmd, + "ls": listPinCmd, }, } @@ -99,6 +101,26 @@ collected if needed. }, } +var listPinCmd = &cmds.Command{ + Helptext: cmds.HelpText{ + Tagline: "List objects pinned to local storage", + ShortDescription: ` +Returns a list of hashes of objects being pinned. Objects that are indirectly +or recursively pinned are not included in the list. +`, + }, + + Run: func(req cmds.Request) (interface{}, error) { + n, err := req.Context().GetNode() + if err != nil { + return nil, err + } + + return n.Pinning.Set().GetKeys(), nil + }, + Type: []u.Key{}, +} + func pin(n *core.IpfsNode, paths []string, recursive bool) ([]*merkledag.Node, error) { dagnodes := make([]*merkledag.Node, 0) From 961e4504f1a5287fb7ee20992392011717a1cff2 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Tue, 18 Nov 2014 23:03:31 -0800 Subject: [PATCH 03/19] core/commands: Fixed pin flag name (conflicted with global -r/--recursive flag) --- core/commands/pin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/commands/pin.go b/core/commands/pin.go index 836495240..d39a7ce66 100644 --- a/core/commands/pin.go +++ b/core/commands/pin.go @@ -34,7 +34,7 @@ on disk. cmds.StringArg("ipfs-path", true, true, "Path to object(s) to be pinned"), }, Options: []cmds.Option{ - cmds.BoolOption("recursive", "r", "Recursively pin the object linked to by the specified object(s)"), + cmds.BoolOption("R", "Recursively pin the object linked to by the specified object(s)"), }, Run: func(req cmds.Request) (interface{}, error) { n, err := req.Context().GetNode() From edb8eeaecf68fe081dad2c22fb34d7eefe55c4a7 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Tue, 18 Nov 2014 23:08:56 -0800 Subject: [PATCH 04/19] core/commands: Created a general key list output type and plaintext marshaler --- core/commands/refs.go | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/core/commands/refs.go b/core/commands/refs.go index a40b3f57e..ac70a6afa 100644 --- a/core/commands/refs.go +++ b/core/commands/refs.go @@ -2,6 +2,7 @@ package commands import ( "fmt" + "strings" mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash" cmds "github.com/jbenet/go-ipfs/commands" @@ -10,8 +11,16 @@ import ( u "github.com/jbenet/go-ipfs/util" ) -type RefsOutput struct { - Refs []string +// KeyList is a general type for outputting lists of keys +type KeyList struct { + Keys []string +} + +// KeyListTextMarshaler outputs a KeyList as plaintext, one key per line +func KeyListTextMarshaler(res cmds.Response) ([]byte, error) { + output := res.Output().(*KeyList) + s := strings.Join(output.Keys, "\n") + return []byte(s), nil } var refsCmd = &cmds.Command{ @@ -58,20 +67,13 @@ Note: list all refs recursively with -r. return getRefs(n, req.Arguments(), unique, recursive) }, - Type: &RefsOutput{}, + Type: &KeyList{}, Marshalers: cmds.MarshalerMap{ - cmds.Text: func(res cmds.Response) ([]byte, error) { - output := res.Output().(*RefsOutput) - s := "" - for _, ref := range output.Refs { - s += fmt.Sprintln(ref) - } - return []byte(s), nil - }, + cmds.Text: KeyListTextMarshaler, }, } -func getRefs(n *core.IpfsNode, paths []string, unique, recursive bool) (*RefsOutput, error) { +func getRefs(n *core.IpfsNode, paths []string, unique, recursive bool) (*KeyList, error) { var refsSeen map[u.Key]bool if unique { refsSeen = make(map[u.Key]bool) @@ -91,7 +93,7 @@ func getRefs(n *core.IpfsNode, paths []string, unique, recursive bool) (*RefsOut } } - return &RefsOutput{refs}, nil + return &KeyList{refs}, nil } func addRefs(n *core.IpfsNode, object *dag.Node, refs []string, refsSeen map[u.Key]bool, recursive bool) ([]string, error) { From 477c246c6c961a7c2aa9c76f9b77964e7b89a6ea Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Tue, 18 Nov 2014 23:09:53 -0800 Subject: [PATCH 05/19] core/commands: Fixed 'refs' option name collision --- core/commands/refs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/commands/refs.go b/core/commands/refs.go index ac70a6afa..bf55f6470 100644 --- a/core/commands/refs.go +++ b/core/commands/refs.go @@ -41,7 +41,7 @@ Note: list all refs recursively with -r. }, Options: []cmds.Option{ cmds.BoolOption("unique", "u", "Omit duplicate refs from output"), - cmds.BoolOption("recursive", "r", "Recursively list links of child nodes"), + cmds.BoolOption("rec", "R", "Recursively list links of child nodes"), }, Run: func(req cmds.Request) (interface{}, error) { n, err := req.Context().GetNode() From db53de806cfbde19e7a8895990f5ebea34e495df Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Tue, 18 Nov 2014 23:20:20 -0800 Subject: [PATCH 06/19] core/commands: Made 'refs' output u.Keys instead of strings --- core/commands/refs.go | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/core/commands/refs.go b/core/commands/refs.go index bf55f6470..61fd1da53 100644 --- a/core/commands/refs.go +++ b/core/commands/refs.go @@ -2,7 +2,6 @@ package commands import ( "fmt" - "strings" mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash" cmds "github.com/jbenet/go-ipfs/commands" @@ -13,13 +12,16 @@ import ( // KeyList is a general type for outputting lists of keys type KeyList struct { - Keys []string + Keys []u.Key } // KeyListTextMarshaler outputs a KeyList as plaintext, one key per line func KeyListTextMarshaler(res cmds.Response) ([]byte, error) { output := res.Output().(*KeyList) - s := strings.Join(output.Keys, "\n") + s := "" + for _, key := range output.Keys { + s += key.B58String() + "\n" + } return []byte(s), nil } @@ -79,7 +81,7 @@ func getRefs(n *core.IpfsNode, paths []string, unique, recursive bool) (*KeyList refsSeen = make(map[u.Key]bool) } - refs := make([]string, 0) + refs := make([]u.Key, 0) for _, path := range paths { object, err := n.Resolver.ResolvePath(path) @@ -96,7 +98,7 @@ func getRefs(n *core.IpfsNode, paths []string, unique, recursive bool) (*KeyList return &KeyList{refs}, nil } -func addRefs(n *core.IpfsNode, object *dag.Node, refs []string, refsSeen map[u.Key]bool, recursive bool) ([]string, error) { +func addRefs(n *core.IpfsNode, object *dag.Node, refs []u.Key, refsSeen map[u.Key]bool, recursive bool) ([]u.Key, error) { for _, link := range object.Links { var found bool found, refs = addRef(link.Hash, refs, refsSeen) @@ -117,15 +119,16 @@ func addRefs(n *core.IpfsNode, object *dag.Node, refs []string, refsSeen map[u.K return refs, nil } -func addRef(h mh.Multihash, refs []string, refsSeen map[u.Key]bool) (bool, []string) { +func addRef(h mh.Multihash, refs []u.Key, refsSeen map[u.Key]bool) (bool, []u.Key) { + key := u.Key(h) if refsSeen != nil { - _, found := refsSeen[u.Key(h)] + _, found := refsSeen[key] if found { return true, refs } - refsSeen[u.Key(h)] = true + refsSeen[key] = true } - refs = append(refs, h.B58String()) + refs = append(refs, key) return false, refs } From 49dc13e5ddb4b60e170f2171664346e48c43153b Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Tue, 18 Nov 2014 23:20:38 -0800 Subject: [PATCH 07/19] core/commands: Added plaintext marshaler for 'pin ls' --- core/commands/pin.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/core/commands/pin.go b/core/commands/pin.go index d39a7ce66..a226a887e 100644 --- a/core/commands/pin.go +++ b/core/commands/pin.go @@ -6,7 +6,6 @@ import ( cmds "github.com/jbenet/go-ipfs/commands" "github.com/jbenet/go-ipfs/core" "github.com/jbenet/go-ipfs/merkledag" - u "github.com/jbenet/go-ipfs/util" ) var pinCmd = &cmds.Command{ @@ -116,9 +115,14 @@ or recursively pinned are not included in the list. return nil, err } - return n.Pinning.Set().GetKeys(), nil + return &KeyList{ + Keys: n.Pinning.Set().GetKeys(), + }, nil + }, + Type: &KeyList{}, + Marshalers: cmds.MarshalerMap{ + cmds.Text: KeyListTextMarshaler, }, - Type: []u.Key{}, } func pin(n *core.IpfsNode, paths []string, recursive bool) ([]*merkledag.Node, error) { From 277ba26120cfa370e7773aa71766350b076b9901 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Wed, 19 Nov 2014 00:01:03 -0800 Subject: [PATCH 08/19] commands: Gave global options exported names --- commands/option.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/commands/option.go b/commands/option.go index d4bd75e42..3252862a6 100644 --- a/commands/option.go +++ b/commands/option.go @@ -141,9 +141,12 @@ const ( ) // options that are used by this package +var OptionEncodingType = StringOption(EncShort, EncLong, "The encoding type the output should be encoded with (json, xml, or text)") +var OptionRecursivePath = BoolOption(RecShort, RecLong, "Add directory paths recursively") + +// global options, added to every command var globalOptions = []Option{ - StringOption(EncShort, EncLong, "The encoding type the output should be encoded with (json, xml, or text)"), - BoolOption(RecShort, RecLong, "Add directory paths recursively"), + OptionEncodingType, } // the above array of Options, wrapped in a Command From bbf3a1f4d4d7813c2baa336aa22227f322a01623 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Wed, 19 Nov 2014 00:24:55 -0800 Subject: [PATCH 09/19] commands: Changed Option to an interface --- commands/cli/helptext.go | 4 ++-- commands/command.go | 4 ++-- commands/option.go | 36 +++++++++++++++++++++++++----------- commands/request.go | 23 ++++++++--------------- 4 files changed, 37 insertions(+), 30 deletions(-) diff --git a/commands/cli/helptext.go b/commands/cli/helptext.go index 9acc3c7d2..2563dc8e2 100644 --- a/commands/cli/helptext.go +++ b/commands/cli/helptext.go @@ -239,7 +239,7 @@ func optionText(cmd ...*cmds.Command) []string { lines = append(lines, "") } - names := sortByLength(opt.Names) + names := sortByLength(opt.Names()) if len(names) >= j+1 { lines[i] += fmt.Sprintf(optionFlag, names[j]) } @@ -268,7 +268,7 @@ func optionText(cmd ...*cmds.Command) []string { // add option descriptions to output for i, opt := range options { - lines[i] += " - " + opt.Description + lines[i] += " - " + opt.Description() } return lines diff --git a/commands/command.go b/commands/command.go index 1f15fdab4..6baddc2b5 100644 --- a/commands/command.go +++ b/commands/command.go @@ -167,7 +167,7 @@ func (c *Command) Get(path []string) (*Command, error) { // GetOptions gets the options in the given path of commands func (c *Command) GetOptions(path []string) (map[string]Option, error) { - options := make([]Option, len(c.Options)) + options := make([]Option, 0, len(c.Options)) cmds, err := c.Resolve(path) if err != nil { @@ -181,7 +181,7 @@ func (c *Command) GetOptions(path []string) (map[string]Option, error) { optionsMap := make(map[string]Option) for _, opt := range options { - for _, name := range opt.Names { + for _, name := range opt.Names() { if _, found := optionsMap[name]; found { return nil, fmt.Errorf("Option name '%s' used multiple times", name) } diff --git a/commands/option.go b/commands/option.go index 3252862a6..6aa5f8f00 100644 --- a/commands/option.go +++ b/commands/option.go @@ -17,14 +17,28 @@ const ( ) // Option is used to specify a field that will be provided by a consumer -type Option struct { - Names []string // a list of unique names to - Type reflect.Kind // value must be this type - Description string // a short string to describe this option +type Option interface { + Names() []string // a list of unique names matched with user-provided flags + Type() reflect.Kind // value must be this type + Description() string // a short string that describes this option +} - // MAYBE_TODO: add more features(?): - //Default interface{} // the default value (ignored if `Required` is true) - //Required bool // whether or not the option must be provided +type option struct { + names []string + kind reflect.Kind + description string +} + +func (o *option) Names() []string { + return o.names +} + +func (o *option) Type() reflect.Kind { + return o.kind +} + +func (o *option) Description() string { + return o.description } // constructor helper functions @@ -37,10 +51,10 @@ func NewOption(kind reflect.Kind, names ...string) Option { desc := names[len(names)-1] names = names[:len(names)-1] - return Option{ - Names: names, - Type: kind, - Description: desc, + return &option{ + names: names, + kind: kind, + description: desc, } } diff --git a/commands/request.go b/commands/request.go index 112e3dde0..7df966e7c 100644 --- a/commands/request.go +++ b/commands/request.go @@ -92,13 +92,6 @@ func (r *request) Path() []string { // Option returns the value of the option for given name. func (r *request) Option(name string) *OptionValue { - val, found := r.options[name] - if found { - return &OptionValue{val, found} - } - - // if a value isn't defined for that name, we will try to look it up by its aliases - // find the option with the specified name option, found := r.optionDefs[name] if !found { @@ -106,8 +99,8 @@ func (r *request) Option(name string) *OptionValue { } // try all the possible names, break if we find a value - for _, n := range option.Names { - val, found = r.options[n] + for _, n := range option.Names() { + val, found := r.options[n] if found { return &OptionValue{val, found} } @@ -135,7 +128,7 @@ func (r *request) SetOption(name string, val interface{}) { } // try all the possible names, if we already have a value then set over it - for _, n := range option.Names { + for _, n := range option.Names() { _, found := r.options[n] if found { r.options[n] = val @@ -222,9 +215,9 @@ func (r *request) ConvertOptions() error { } kind := reflect.TypeOf(v).Kind() - if kind != opt.Type { + if kind != opt.Type() { if kind == String { - convert := converters[opt.Type] + convert := converters[opt.Type()] str, ok := v.(string) if !ok { return u.ErrCast() @@ -236,19 +229,19 @@ func (r *request) ConvertOptions() error { value = "empty value" } return fmt.Errorf("Could not convert %s to type '%s' (for option '-%s')", - value, opt.Type.String(), k) + value, opt.Type().String(), k) } r.options[k] = val } else { return fmt.Errorf("Option '%s' should be type '%s', but got type '%s'", - k, opt.Type.String(), kind.String()) + k, opt.Type().String(), kind.String()) } } else { r.options[k] = v } - for _, name := range opt.Names { + for _, name := range opt.Names() { if _, ok := r.options[name]; name != k && ok { return fmt.Errorf("Duplicate command options were provided ('%s' and '%s')", k, name) From aa84f69231e9e62fea34499c1215bd3590a11071 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Wed, 19 Nov 2014 00:26:02 -0800 Subject: [PATCH 10/19] commands: Added a 'Definition()' method to OptionValue to get a reference to the option definiton --- commands/option.go | 6 ++++++ commands/request.go | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/commands/option.go b/commands/option.go index 6aa5f8f00..78f01a7aa 100644 --- a/commands/option.go +++ b/commands/option.go @@ -83,6 +83,7 @@ func StringOption(names ...string) Option { type OptionValue struct { value interface{} found bool + def Option } // Found returns true if the option value was provided by the user (not a default value) @@ -90,6 +91,11 @@ func (ov OptionValue) Found() bool { return ov.found } +// Definition returns the option definition for the provided value +func (ov OptionValue) Definition() Option { + return ov.def +} + // value accessor methods, gets the value as a certain type func (ov OptionValue) Bool() (value bool, found bool, err error) { if !ov.found { diff --git a/commands/request.go b/commands/request.go index 7df966e7c..7d8b7cd8e 100644 --- a/commands/request.go +++ b/commands/request.go @@ -102,12 +102,12 @@ func (r *request) Option(name string) *OptionValue { for _, n := range option.Names() { val, found := r.options[n] if found { - return &OptionValue{val, found} + return &OptionValue{val, found, option} } } // MAYBE_TODO: use default value instead of nil - return &OptionValue{nil, false} + return &OptionValue{nil, false, option} } // Options returns a copy of the option map From 761392d8de32d93410b5827c14dde5acbd3913bf Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Wed, 19 Nov 2014 00:26:53 -0800 Subject: [PATCH 11/19] commands/cli: Only allow recursive paths if -r option definition is OptionRecursivePath --- commands/cli/parse.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/commands/cli/parse.go b/commands/cli/parse.go index 1d05f5152..aceec578c 100644 --- a/commands/cli/parse.go +++ b/commands/cli/parse.go @@ -46,10 +46,17 @@ func Parse(input []string, stdin *os.File, root *cmds.Command) (cmds.Request, *c return nil, cmd, path, err } - recursive, _, err := req.Option(cmds.RecShort).Bool() - if err != nil { - return nil, nil, nil, u.ErrCast() + // if -r is provided, and it is associated with the package builtin + // recursive path option, allow recursive file paths + recursiveOpt := req.Option(cmds.RecShort) + recursive := false + if recursiveOpt != nil && recursiveOpt.Definition() == cmds.OptionRecursivePath { + recursive, _, err = recursiveOpt.Bool() + if err != nil { + return nil, nil, nil, u.ErrCast() + } } + stringArgs, fileArgs, err := parseArgs(stringVals, stdin, cmd.Arguments, recursive) if err != nil { return nil, cmd, path, err From 87853f2bded33ca10f80d86b9a710a9f00808c2a Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Wed, 19 Nov 2014 00:36:03 -0800 Subject: [PATCH 12/19] core/commands: Made 'add' use OptionRecursivePath --- core/commands/add.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/commands/add.go b/core/commands/add.go index 9306f81f2..f09787b9c 100644 --- a/core/commands/add.go +++ b/core/commands/add.go @@ -39,6 +39,9 @@ remains to be implemented. Arguments: []cmds.Argument{ cmds.FileArg("path", true, true, "The path to a file to be added to IPFS").EnableRecursive(), }, + Options: []cmds.Option{ + cmds.OptionRecursivePath, // a builtin option that allows recursive paths (-r, --recursive) + }, Run: func(req cmds.Request) (interface{}, error) { added := &AddOutput{} n, err := req.Context().GetNode() From 4c1a5f681625beeacf020a72b3e6597334547aba Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Wed, 19 Nov 2014 00:36:30 -0800 Subject: [PATCH 13/19] core/commands: Restored 'pin'/'refs' option names --- core/commands/pin.go | 2 +- core/commands/refs.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/commands/pin.go b/core/commands/pin.go index a226a887e..5340177b0 100644 --- a/core/commands/pin.go +++ b/core/commands/pin.go @@ -33,7 +33,7 @@ on disk. cmds.StringArg("ipfs-path", true, true, "Path to object(s) to be pinned"), }, Options: []cmds.Option{ - cmds.BoolOption("R", "Recursively pin the object linked to by the specified object(s)"), + cmds.BoolOption("recursive", "r", "Recursively pin the object linked to by the specified object(s)"), }, Run: func(req cmds.Request) (interface{}, error) { n, err := req.Context().GetNode() diff --git a/core/commands/refs.go b/core/commands/refs.go index 61fd1da53..c977a3df8 100644 --- a/core/commands/refs.go +++ b/core/commands/refs.go @@ -43,7 +43,7 @@ Note: list all refs recursively with -r. }, Options: []cmds.Option{ cmds.BoolOption("unique", "u", "Omit duplicate refs from output"), - cmds.BoolOption("rec", "R", "Recursively list links of child nodes"), + cmds.BoolOption("recursive", "r", "Recursively list links of child nodes"), }, Run: func(req cmds.Request) (interface{}, error) { n, err := req.Context().GetNode() From ae6f00d76660c48b3efabe4a1321fc7f740b9122 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Wed, 19 Nov 2014 00:36:42 -0800 Subject: [PATCH 14/19] commands: Fixed tests --- commands/cli/parse_test.go | 2 +- commands/command_test.go | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/commands/cli/parse_test.go b/commands/cli/parse_test.go index cddd54669..8fe5b3510 100644 --- a/commands/cli/parse_test.go +++ b/commands/cli/parse_test.go @@ -11,7 +11,7 @@ func TestOptionParsing(t *testing.T) { subCmd := &commands.Command{} cmd := &commands.Command{ Options: []commands.Option{ - commands.Option{Names: []string{"b"}, Type: commands.String}, + commands.StringOption("b", "some option"), }, Subcommands: map[string]*commands.Command{ "test": subCmd, diff --git a/commands/command_test.go b/commands/command_test.go index ab090fe2c..4fcc48bd8 100644 --- a/commands/command_test.go +++ b/commands/command_test.go @@ -9,8 +9,8 @@ func noop(req Request) (interface{}, error) { func TestOptionValidation(t *testing.T) { cmd := Command{ Options: []Option{ - Option{[]string{"b", "beep"}, Int, "enables beeper"}, - Option{[]string{"B", "boop"}, String, "password for booper"}, + IntOption("b", "beep", "enables beeper"), + StringOption("B", "boop", "password for booper"), }, Run: noop, } @@ -93,14 +93,14 @@ func TestOptionValidation(t *testing.T) { func TestRegistration(t *testing.T) { cmdA := &Command{ Options: []Option{ - Option{[]string{"beep"}, Int, "number of beeps"}, + IntOption("beep", "number of beeps"), }, Run: noop, } cmdB := &Command{ Options: []Option{ - Option{[]string{"beep"}, Int, "number of beeps"}, + IntOption("beep", "number of beeps"), }, Run: noop, Subcommands: map[string]*Command{ @@ -110,7 +110,7 @@ func TestRegistration(t *testing.T) { cmdC := &Command{ Options: []Option{ - Option{[]string{"encoding"}, String, "data encoding type"}, + StringOption("encoding", "data encoding type"), }, Run: noop, } From e6091be0c732d96bcebbb573f7978a6d6952ea17 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Wed, 19 Nov 2014 00:53:23 -0800 Subject: [PATCH 15/19] pin: Return copies of pinned keys, of each type (direct/indirect/recursive) --- pin/indirect.go | 4 ++++ pin/pin.go | 20 ++++++++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/pin/indirect.go b/pin/indirect.go index b15b720ee..9e67bc2c9 100644 --- a/pin/indirect.go +++ b/pin/indirect.go @@ -65,3 +65,7 @@ func (i *indirectPin) Decrement(k util.Key) { func (i *indirectPin) HasKey(k util.Key) bool { return i.blockset.HasKey(k) } + +func (i *indirectPin) Set() set.BlockSet { + return i.blockset +} diff --git a/pin/pin.go b/pin/pin.go index 1d840c6bc..371497da6 100644 --- a/pin/pin.go +++ b/pin/pin.go @@ -33,7 +33,9 @@ type Pinner interface { Unpin(util.Key, bool) error Flush() error GetManual() ManualPinner - Set() set.BlockSet + DirectKeys() []util.Key + IndirectKeys() []util.Key + RecursiveKeys() []util.Key } // ManualPinner is for manually editing the pin structure @@ -208,9 +210,19 @@ func LoadPinner(d ds.Datastore, dserv mdag.DAGService) (Pinner, error) { return p, nil } -// Set returns a blockset of directly pinned keys -func (p *pinner) Set() set.BlockSet { - return p.directPin +// DirectKeys returns a slice containing the directly pinned keys +func (p *pinner) DirectKeys() []util.Key { + return p.directPin.GetKeys() +} + +// IndirectKeys returns a slice containing the indirectly pinned keys +func (p *pinner) IndirectKeys() []util.Key { + return p.indirPin.Set().GetKeys() +} + +// RecursiveKeys returns a slice containing the recursively pinned keys +func (p *pinner) RecursiveKeys() []util.Key { + return p.recursePin.GetKeys() } // Flush encodes and writes pinner keysets to the datastore From 9de01007d02639301840f1de5ce2dfb074b21c5b Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Wed, 19 Nov 2014 00:53:57 -0800 Subject: [PATCH 16/19] core/commands: pin ls: Accept 'type' option to specify type of pinned keys to list --- core/commands/pin.go | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/core/commands/pin.go b/core/commands/pin.go index 5340177b0..656bc321d 100644 --- a/core/commands/pin.go +++ b/core/commands/pin.go @@ -6,6 +6,7 @@ import ( cmds "github.com/jbenet/go-ipfs/commands" "github.com/jbenet/go-ipfs/core" "github.com/jbenet/go-ipfs/merkledag" + u "github.com/jbenet/go-ipfs/util" ) var pinCmd = &cmds.Command{ @@ -109,15 +110,39 @@ or recursively pinned are not included in the list. `, }, + Options: []cmds.Option{ + cmds.StringOption("type", "t", "The type of pinned keys to list. Can be \"direct\", \"indirect\", \"recursive\", or \"all\""), + }, Run: func(req cmds.Request) (interface{}, error) { n, err := req.Context().GetNode() if err != nil { return nil, err } - return &KeyList{ - Keys: n.Pinning.Set().GetKeys(), - }, nil + typeStr, found, err := req.Option("type").String() + if err != nil { + return nil, err + } + if !found { + typeStr = "all" + } + + if typeStr != "all" && typeStr != "direct" && typeStr != "indirect" && typeStr != "recursive" { + return nil, cmds.ClientError("Invalid type '" + typeStr + "', must be \"direct\", \"indirect\", \"recursive\", or \"all\"") + } + + keys := make([]u.Key, 0) + if typeStr == "direct" || typeStr == "all" { + keys = append(keys, n.Pinning.DirectKeys()...) + } + if typeStr == "indirect" || typeStr == "all" { + keys = append(keys, n.Pinning.IndirectKeys()...) + } + if typeStr == "recursive" || typeStr == "all" { + keys = append(keys, n.Pinning.RecursiveKeys()...) + } + + return &KeyList{Keys: keys}, nil }, Type: &KeyList{}, Marshalers: cmds.MarshalerMap{ From 69ce2940a826625bfa328f5375cdcd8c1690048c Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Wed, 19 Nov 2014 00:54:59 -0800 Subject: [PATCH 17/19] commands/cli: Fixed helptext option type --- commands/cli/helptext.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/cli/helptext.go b/commands/cli/helptext.go index 2563dc8e2..32cbb7076 100644 --- a/commands/cli/helptext.go +++ b/commands/cli/helptext.go @@ -262,7 +262,7 @@ func optionText(cmd ...*cmds.Command) []string { // add option types to output for i, opt := range options { - lines[i] += " " + fmt.Sprintf("%v", opt.Type) + lines[i] += " " + fmt.Sprintf("%v", opt.Type()) } lines = align(lines) From 928f20b4bd5c2a8df7fa96b767accddfc9d79d5a Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Wed, 19 Nov 2014 01:44:51 -0800 Subject: [PATCH 18/19] core/commands: pin ls: Default type to 'direct' --- core/commands/pin.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/core/commands/pin.go b/core/commands/pin.go index 656bc321d..a085fe51c 100644 --- a/core/commands/pin.go +++ b/core/commands/pin.go @@ -107,11 +107,22 @@ var listPinCmd = &cmds.Command{ ShortDescription: ` Returns a list of hashes of objects being pinned. Objects that are indirectly or recursively pinned are not included in the list. +`, + LongDescription: ` +Returns a list of hashes of objects being pinned. Objects that are indirectly +or recursively pinned are not included in the list. + +Use --type= to specify the type of pinned keys to list. Valid values are: + * "direct" + * "indirect" + * "recursive" + * "all" +(Defaults to "direct") `, }, Options: []cmds.Option{ - cmds.StringOption("type", "t", "The type of pinned keys to list. Can be \"direct\", \"indirect\", \"recursive\", or \"all\""), + cmds.StringOption("type", "t", "The type of pinned keys to list. Can be \"direct\", \"indirect\", \"recursive\", or \"all\". Defaults to \"direct\""), }, Run: func(req cmds.Request) (interface{}, error) { n, err := req.Context().GetNode() @@ -124,7 +135,7 @@ or recursively pinned are not included in the list. return nil, err } if !found { - typeStr = "all" + typeStr = "direct" } if typeStr != "all" && typeStr != "direct" && typeStr != "indirect" && typeStr != "recursive" { From 5461d769579c02b637e507135980d93d590b6401 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Wed, 19 Nov 2014 03:23:21 -0800 Subject: [PATCH 19/19] core/commands: Better syntax for 'pin ls' option value handling --- core/commands/pin.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/commands/pin.go b/core/commands/pin.go index a085fe51c..341d7dd4a 100644 --- a/core/commands/pin.go +++ b/core/commands/pin.go @@ -138,8 +138,10 @@ Use --type= to specify the type of pinned keys to list. Valid values are: typeStr = "direct" } - if typeStr != "all" && typeStr != "direct" && typeStr != "indirect" && typeStr != "recursive" { - return nil, cmds.ClientError("Invalid type '" + typeStr + "', must be \"direct\", \"indirect\", \"recursive\", or \"all\"") + switch typeStr { + case "all", "direct", "indirect", "recursive": + default: + return nil, cmds.ClientError("Invalid type '" + typeStr + "', must be one of {direct, indirect, recursive, all}") } keys := make([]u.Key, 0)