Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added 'pin ls' Command #364

Merged
merged 19 commits into from
Nov 19, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
90e5c7f
pin: Added a Pinner#Set function to retrieve the set of pinned keys
mappum Nov 19, 2014
afc7b6f
core/commands: Added a 'pin ls' command
mappum Nov 19, 2014
961e450
core/commands: Fixed pin flag name (conflicted with global -r/--recur…
mappum Nov 19, 2014
edb8eea
core/commands: Created a general key list output type and plaintext m…
mappum Nov 19, 2014
477c246
core/commands: Fixed 'refs' option name collision
mappum Nov 19, 2014
db53de8
core/commands: Made 'refs' output u.Keys instead of strings
mappum Nov 19, 2014
49dc13e
core/commands: Added plaintext marshaler for 'pin ls'
mappum Nov 19, 2014
277ba26
commands: Gave global options exported names
mappum Nov 19, 2014
bbf3a1f
commands: Changed Option to an interface
mappum Nov 19, 2014
aa84f69
commands: Added a 'Definition()' method to OptionValue to get a refer…
mappum Nov 19, 2014
761392d
commands/cli: Only allow recursive paths if -r option definition is O…
mappum Nov 19, 2014
87853f2
core/commands: Made 'add' use OptionRecursivePath
mappum Nov 19, 2014
4c1a5f6
core/commands: Restored 'pin'/'refs' option names
mappum Nov 19, 2014
ae6f00d
commands: Fixed tests
mappum Nov 19, 2014
e6091be
pin: Return copies of pinned keys, of each type (direct/indirect/recu…
mappum Nov 19, 2014
9de0100
core/commands: pin ls: Accept 'type' option to specify type of pinned…
mappum Nov 19, 2014
69ce294
commands/cli: Fixed helptext option type
mappum Nov 19, 2014
928f20b
core/commands: pin ls: Default type to 'direct'
mappum Nov 19, 2014
5461d76
core/commands: Better syntax for 'pin ls' option value handling
mappum Nov 19, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions commands/cli/helptext.go
Original file line number Diff line number Diff line change
Expand Up @@ -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])
}
Expand All @@ -262,13 +262,13 @@ 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)

// add option descriptions to output
for i, opt := range options {
lines[i] += " - " + opt.Description
lines[i] += " - " + opt.Description()
}

return lines
Expand Down
13 changes: 10 additions & 3 deletions commands/cli/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion commands/cli/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions commands/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)
}
Expand Down
10 changes: 5 additions & 5 deletions commands/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down Expand Up @@ -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{
Expand All @@ -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,
}
Expand Down
49 changes: 36 additions & 13 deletions commands/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

type option struct {
names []string
kind reflect.Kind
description string
}

func (o *option) Names() []string {
return o.names
}

// 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
func (o *option) Type() reflect.Kind {
return o.kind
}

func (o *option) Description() string {
return o.description
}

// constructor helper functions
Expand All @@ -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,
}
}

Expand Down Expand Up @@ -69,13 +83,19 @@ 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)
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 {
Expand Down Expand Up @@ -141,9 +161,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
Expand Down
27 changes: 10 additions & 17 deletions commands/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,29 +92,22 @@ 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 {
return nil
}

// 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}
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
Expand All @@ -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
Expand Down Expand Up @@ -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()
Expand All @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions core/commands/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
64 changes: 64 additions & 0 deletions core/commands/pin.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand All @@ -16,6 +17,7 @@ var pinCmd = &cmds.Command{
Subcommands: map[string]*cmds.Command{
"add": addPinCmd,
"rm": rmPinCmd,
"ls": listPinCmd,
},
}

Expand Down Expand Up @@ -99,6 +101,68 @@ 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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this planning to change later on?

Maybe:

ipfs pin ls [-r, --recursive] [-i, --indirect]
# or
ipfs pin ls [-t, --type [ recursive | indirect | direct | all ] ]

`,
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=<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\". Defaults to \"direct\""),
},
Run: func(req cmds.Request) (interface{}, error) {
n, err := req.Context().GetNode()
if err != nil {
return nil, err
}

typeStr, found, err := req.Option("type").String()
if err != nil {
return nil, err
}
if !found {
typeStr = "direct"
}

switch typeStr {
case "all", "direct", "indirect", "recursive":
default:
return nil, cmds.ClientError("Invalid type '" + typeStr + "', must be one of {direct, indirect, recursive, all}")
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
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{
cmds.Text: KeyListTextMarshaler,
},
}

func pin(n *core.IpfsNode, paths []string, recursive bool) ([]*merkledag.Node, error) {

dagnodes := make([]*merkledag.Node, 0)
Expand Down
Loading