mirror of
https://github.com/ipfs/kubo.git
synced 2025-07-03 04:37:30 +08:00
@ -239,7 +239,7 @@ func optionText(cmd ...*cmds.Command) []string {
|
|||||||
lines = append(lines, "")
|
lines = append(lines, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
names := sortByLength(opt.Names)
|
names := sortByLength(opt.Names())
|
||||||
if len(names) >= j+1 {
|
if len(names) >= j+1 {
|
||||||
lines[i] += fmt.Sprintf(optionFlag, names[j])
|
lines[i] += fmt.Sprintf(optionFlag, names[j])
|
||||||
}
|
}
|
||||||
@ -262,13 +262,13 @@ func optionText(cmd ...*cmds.Command) []string {
|
|||||||
|
|
||||||
// add option types to output
|
// add option types to output
|
||||||
for i, opt := range options {
|
for i, opt := range options {
|
||||||
lines[i] += " " + fmt.Sprintf("%v", opt.Type)
|
lines[i] += " " + fmt.Sprintf("%v", opt.Type())
|
||||||
}
|
}
|
||||||
lines = align(lines)
|
lines = align(lines)
|
||||||
|
|
||||||
// add option descriptions to output
|
// add option descriptions to output
|
||||||
for i, opt := range options {
|
for i, opt := range options {
|
||||||
lines[i] += " - " + opt.Description
|
lines[i] += " - " + opt.Description()
|
||||||
}
|
}
|
||||||
|
|
||||||
return lines
|
return lines
|
||||||
|
@ -46,10 +46,17 @@ func Parse(input []string, stdin *os.File, root *cmds.Command) (cmds.Request, *c
|
|||||||
return nil, cmd, path, err
|
return nil, cmd, path, err
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive, _, err := req.Option(cmds.RecShort).Bool()
|
// if -r is provided, and it is associated with the package builtin
|
||||||
if err != nil {
|
// recursive path option, allow recursive file paths
|
||||||
return nil, nil, nil, u.ErrCast()
|
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)
|
stringArgs, fileArgs, err := parseArgs(stringVals, stdin, cmd.Arguments, recursive)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, cmd, path, err
|
return nil, cmd, path, err
|
||||||
|
@ -11,7 +11,7 @@ func TestOptionParsing(t *testing.T) {
|
|||||||
subCmd := &commands.Command{}
|
subCmd := &commands.Command{}
|
||||||
cmd := &commands.Command{
|
cmd := &commands.Command{
|
||||||
Options: []commands.Option{
|
Options: []commands.Option{
|
||||||
commands.Option{Names: []string{"b"}, Type: commands.String},
|
commands.StringOption("b", "some option"),
|
||||||
},
|
},
|
||||||
Subcommands: map[string]*commands.Command{
|
Subcommands: map[string]*commands.Command{
|
||||||
"test": subCmd,
|
"test": subCmd,
|
||||||
|
@ -167,7 +167,7 @@ func (c *Command) Get(path []string) (*Command, error) {
|
|||||||
|
|
||||||
// GetOptions gets the options in the given path of commands
|
// GetOptions gets the options in the given path of commands
|
||||||
func (c *Command) GetOptions(path []string) (map[string]Option, error) {
|
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)
|
cmds, err := c.Resolve(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -181,7 +181,7 @@ func (c *Command) GetOptions(path []string) (map[string]Option, error) {
|
|||||||
|
|
||||||
optionsMap := make(map[string]Option)
|
optionsMap := make(map[string]Option)
|
||||||
for _, opt := range options {
|
for _, opt := range options {
|
||||||
for _, name := range opt.Names {
|
for _, name := range opt.Names() {
|
||||||
if _, found := optionsMap[name]; found {
|
if _, found := optionsMap[name]; found {
|
||||||
return nil, fmt.Errorf("Option name '%s' used multiple times", name)
|
return nil, fmt.Errorf("Option name '%s' used multiple times", name)
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,8 @@ func noop(req Request) (interface{}, error) {
|
|||||||
func TestOptionValidation(t *testing.T) {
|
func TestOptionValidation(t *testing.T) {
|
||||||
cmd := Command{
|
cmd := Command{
|
||||||
Options: []Option{
|
Options: []Option{
|
||||||
Option{[]string{"b", "beep"}, Int, "enables beeper"},
|
IntOption("b", "beep", "enables beeper"),
|
||||||
Option{[]string{"B", "boop"}, String, "password for booper"},
|
StringOption("B", "boop", "password for booper"),
|
||||||
},
|
},
|
||||||
Run: noop,
|
Run: noop,
|
||||||
}
|
}
|
||||||
@ -93,14 +93,14 @@ func TestOptionValidation(t *testing.T) {
|
|||||||
func TestRegistration(t *testing.T) {
|
func TestRegistration(t *testing.T) {
|
||||||
cmdA := &Command{
|
cmdA := &Command{
|
||||||
Options: []Option{
|
Options: []Option{
|
||||||
Option{[]string{"beep"}, Int, "number of beeps"},
|
IntOption("beep", "number of beeps"),
|
||||||
},
|
},
|
||||||
Run: noop,
|
Run: noop,
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdB := &Command{
|
cmdB := &Command{
|
||||||
Options: []Option{
|
Options: []Option{
|
||||||
Option{[]string{"beep"}, Int, "number of beeps"},
|
IntOption("beep", "number of beeps"),
|
||||||
},
|
},
|
||||||
Run: noop,
|
Run: noop,
|
||||||
Subcommands: map[string]*Command{
|
Subcommands: map[string]*Command{
|
||||||
@ -110,7 +110,7 @@ func TestRegistration(t *testing.T) {
|
|||||||
|
|
||||||
cmdC := &Command{
|
cmdC := &Command{
|
||||||
Options: []Option{
|
Options: []Option{
|
||||||
Option{[]string{"encoding"}, String, "data encoding type"},
|
StringOption("encoding", "data encoding type"),
|
||||||
},
|
},
|
||||||
Run: noop,
|
Run: noop,
|
||||||
}
|
}
|
||||||
|
@ -17,14 +17,28 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Option is used to specify a field that will be provided by a consumer
|
// Option is used to specify a field that will be provided by a consumer
|
||||||
type Option struct {
|
type Option interface {
|
||||||
Names []string // a list of unique names to
|
Names() []string // a list of unique names matched with user-provided flags
|
||||||
Type reflect.Kind // value must be this type
|
Type() reflect.Kind // value must be this type
|
||||||
Description string // a short string to describe this option
|
Description() string // a short string that describes this option
|
||||||
|
}
|
||||||
|
|
||||||
// MAYBE_TODO: add more features(?):
|
type option struct {
|
||||||
//Default interface{} // the default value (ignored if `Required` is true)
|
names []string
|
||||||
//Required bool // whether or not the option must be provided
|
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
|
// constructor helper functions
|
||||||
@ -37,10 +51,10 @@ func NewOption(kind reflect.Kind, names ...string) Option {
|
|||||||
desc := names[len(names)-1]
|
desc := names[len(names)-1]
|
||||||
names = names[:len(names)-1]
|
names = names[:len(names)-1]
|
||||||
|
|
||||||
return Option{
|
return &option{
|
||||||
Names: names,
|
names: names,
|
||||||
Type: kind,
|
kind: kind,
|
||||||
Description: desc,
|
description: desc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,6 +83,7 @@ func StringOption(names ...string) Option {
|
|||||||
type OptionValue struct {
|
type OptionValue struct {
|
||||||
value interface{}
|
value interface{}
|
||||||
found bool
|
found bool
|
||||||
|
def Option
|
||||||
}
|
}
|
||||||
|
|
||||||
// Found returns true if the option value was provided by the user (not a default value)
|
// Found returns true if the option value was provided by the user (not a default value)
|
||||||
@ -76,6 +91,11 @@ func (ov OptionValue) Found() bool {
|
|||||||
return ov.found
|
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
|
// value accessor methods, gets the value as a certain type
|
||||||
func (ov OptionValue) Bool() (value bool, found bool, err error) {
|
func (ov OptionValue) Bool() (value bool, found bool, err error) {
|
||||||
if !ov.found {
|
if !ov.found {
|
||||||
@ -141,9 +161,12 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// options that are used by this package
|
// 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{
|
var globalOptions = []Option{
|
||||||
StringOption(EncShort, EncLong, "The encoding type the output should be encoded with (json, xml, or text)"),
|
OptionEncodingType,
|
||||||
BoolOption(RecShort, RecLong, "Add directory paths recursively"),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// the above array of Options, wrapped in a Command
|
// the above array of Options, wrapped in a Command
|
||||||
|
@ -92,13 +92,6 @@ func (r *request) Path() []string {
|
|||||||
|
|
||||||
// Option returns the value of the option for given name.
|
// Option returns the value of the option for given name.
|
||||||
func (r *request) Option(name string) *OptionValue {
|
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
|
// find the option with the specified name
|
||||||
option, found := r.optionDefs[name]
|
option, found := r.optionDefs[name]
|
||||||
if !found {
|
if !found {
|
||||||
@ -106,15 +99,15 @@ func (r *request) Option(name string) *OptionValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// try all the possible names, break if we find a value
|
// try all the possible names, break if we find a value
|
||||||
for _, n := range option.Names {
|
for _, n := range option.Names() {
|
||||||
val, found = r.options[n]
|
val, found := r.options[n]
|
||||||
if found {
|
if found {
|
||||||
return &OptionValue{val, found}
|
return &OptionValue{val, found, option}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MAYBE_TODO: use default value instead of nil
|
// 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
|
// Options returns a copy of the option map
|
||||||
@ -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
|
// 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]
|
_, found := r.options[n]
|
||||||
if found {
|
if found {
|
||||||
r.options[n] = val
|
r.options[n] = val
|
||||||
@ -222,9 +215,9 @@ func (r *request) ConvertOptions() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
kind := reflect.TypeOf(v).Kind()
|
kind := reflect.TypeOf(v).Kind()
|
||||||
if kind != opt.Type {
|
if kind != opt.Type() {
|
||||||
if kind == String {
|
if kind == String {
|
||||||
convert := converters[opt.Type]
|
convert := converters[opt.Type()]
|
||||||
str, ok := v.(string)
|
str, ok := v.(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return u.ErrCast()
|
return u.ErrCast()
|
||||||
@ -236,19 +229,19 @@ func (r *request) ConvertOptions() error {
|
|||||||
value = "empty value"
|
value = "empty value"
|
||||||
}
|
}
|
||||||
return fmt.Errorf("Could not convert %s to type '%s' (for option '-%s')",
|
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
|
r.options[k] = val
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("Option '%s' should be type '%s', but got type '%s'",
|
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 {
|
} else {
|
||||||
r.options[k] = v
|
r.options[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, name := range opt.Names {
|
for _, name := range opt.Names() {
|
||||||
if _, ok := r.options[name]; name != k && ok {
|
if _, ok := r.options[name]; name != k && ok {
|
||||||
return fmt.Errorf("Duplicate command options were provided ('%s' and '%s')",
|
return fmt.Errorf("Duplicate command options were provided ('%s' and '%s')",
|
||||||
k, name)
|
k, name)
|
||||||
|
@ -39,6 +39,9 @@ remains to be implemented.
|
|||||||
Arguments: []cmds.Argument{
|
Arguments: []cmds.Argument{
|
||||||
cmds.FileArg("path", true, true, "The path to a file to be added to IPFS").EnableRecursive(),
|
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) {
|
Run: func(req cmds.Request) (interface{}, error) {
|
||||||
added := &AddOutput{}
|
added := &AddOutput{}
|
||||||
n, err := req.Context().GetNode()
|
n, err := req.Context().GetNode()
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
cmds "github.com/jbenet/go-ipfs/commands"
|
cmds "github.com/jbenet/go-ipfs/commands"
|
||||||
"github.com/jbenet/go-ipfs/core"
|
"github.com/jbenet/go-ipfs/core"
|
||||||
"github.com/jbenet/go-ipfs/merkledag"
|
"github.com/jbenet/go-ipfs/merkledag"
|
||||||
|
u "github.com/jbenet/go-ipfs/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
var pinCmd = &cmds.Command{
|
var pinCmd = &cmds.Command{
|
||||||
@ -16,6 +17,7 @@ var pinCmd = &cmds.Command{
|
|||||||
Subcommands: map[string]*cmds.Command{
|
Subcommands: map[string]*cmds.Command{
|
||||||
"add": addPinCmd,
|
"add": addPinCmd,
|
||||||
"rm": rmPinCmd,
|
"rm": rmPinCmd,
|
||||||
|
"ls": listPinCmd,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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.
|
||||||
|
`,
|
||||||
|
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}")
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
func pin(n *core.IpfsNode, paths []string, recursive bool) ([]*merkledag.Node, error) {
|
||||||
|
|
||||||
dagnodes := make([]*merkledag.Node, 0)
|
dagnodes := make([]*merkledag.Node, 0)
|
||||||
|
@ -10,8 +10,19 @@ import (
|
|||||||
u "github.com/jbenet/go-ipfs/util"
|
u "github.com/jbenet/go-ipfs/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RefsOutput struct {
|
// KeyList is a general type for outputting lists of keys
|
||||||
Refs []string
|
type KeyList struct {
|
||||||
|
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 := ""
|
||||||
|
for _, key := range output.Keys {
|
||||||
|
s += key.B58String() + "\n"
|
||||||
|
}
|
||||||
|
return []byte(s), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var refsCmd = &cmds.Command{
|
var refsCmd = &cmds.Command{
|
||||||
@ -58,26 +69,19 @@ Note: list all refs recursively with -r.
|
|||||||
|
|
||||||
return getRefs(n, req.Arguments(), unique, recursive)
|
return getRefs(n, req.Arguments(), unique, recursive)
|
||||||
},
|
},
|
||||||
Type: &RefsOutput{},
|
Type: &KeyList{},
|
||||||
Marshalers: cmds.MarshalerMap{
|
Marshalers: cmds.MarshalerMap{
|
||||||
cmds.Text: func(res cmds.Response) ([]byte, error) {
|
cmds.Text: KeyListTextMarshaler,
|
||||||
output := res.Output().(*RefsOutput)
|
|
||||||
s := ""
|
|
||||||
for _, ref := range output.Refs {
|
|
||||||
s += fmt.Sprintln(ref)
|
|
||||||
}
|
|
||||||
return []byte(s), nil
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
var refsSeen map[u.Key]bool
|
||||||
if unique {
|
if unique {
|
||||||
refsSeen = make(map[u.Key]bool)
|
refsSeen = make(map[u.Key]bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
refs := make([]string, 0)
|
refs := make([]u.Key, 0)
|
||||||
|
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
object, err := n.Resolver.ResolvePath(path)
|
object, err := n.Resolver.ResolvePath(path)
|
||||||
@ -91,10 +95,10 @@ 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) {
|
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 {
|
for _, link := range object.Links {
|
||||||
var found bool
|
var found bool
|
||||||
found, refs = addRef(link.Hash, refs, refsSeen)
|
found, refs = addRef(link.Hash, refs, refsSeen)
|
||||||
@ -115,15 +119,16 @@ func addRefs(n *core.IpfsNode, object *dag.Node, refs []string, refsSeen map[u.K
|
|||||||
return refs, nil
|
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 {
|
if refsSeen != nil {
|
||||||
_, found := refsSeen[u.Key(h)]
|
_, found := refsSeen[key]
|
||||||
if found {
|
if found {
|
||||||
return true, refs
|
return true, refs
|
||||||
}
|
}
|
||||||
refsSeen[u.Key(h)] = true
|
refsSeen[key] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
refs = append(refs, h.B58String())
|
refs = append(refs, key)
|
||||||
return false, refs
|
return false, refs
|
||||||
}
|
}
|
||||||
|
@ -65,3 +65,7 @@ func (i *indirectPin) Decrement(k util.Key) {
|
|||||||
func (i *indirectPin) HasKey(k util.Key) bool {
|
func (i *indirectPin) HasKey(k util.Key) bool {
|
||||||
return i.blockset.HasKey(k)
|
return i.blockset.HasKey(k)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *indirectPin) Set() set.BlockSet {
|
||||||
|
return i.blockset
|
||||||
|
}
|
||||||
|
18
pin/pin.go
18
pin/pin.go
@ -33,6 +33,9 @@ type Pinner interface {
|
|||||||
Unpin(util.Key, bool) error
|
Unpin(util.Key, bool) error
|
||||||
Flush() error
|
Flush() error
|
||||||
GetManual() ManualPinner
|
GetManual() ManualPinner
|
||||||
|
DirectKeys() []util.Key
|
||||||
|
IndirectKeys() []util.Key
|
||||||
|
RecursiveKeys() []util.Key
|
||||||
}
|
}
|
||||||
|
|
||||||
// ManualPinner is for manually editing the pin structure
|
// ManualPinner is for manually editing the pin structure
|
||||||
@ -207,6 +210,21 @@ func LoadPinner(d ds.Datastore, dserv mdag.DAGService) (Pinner, error) {
|
|||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
// Flush encodes and writes pinner keysets to the datastore
|
||||||
func (p *pinner) Flush() error {
|
func (p *pinner) Flush() error {
|
||||||
p.lock.RLock()
|
p.lock.RLock()
|
||||||
|
Reference in New Issue
Block a user