diff --git a/core/commands/pin/pin.go b/core/commands/pin/pin.go index ca3c932bff0..3569b9afe13 100644 --- a/core/commands/pin/pin.go +++ b/core/commands/pin/pin.go @@ -362,6 +362,7 @@ Example: cmds.BoolOption(pinQuietOptionName, "q", "Write just hashes of objects."), cmds.BoolOption(pinStreamOptionName, "s", "Enable streaming of pins as they are discovered."), cmds.BoolOption(pinNamesOptionName, "n", "Enable displaying pin names (slower)."), + cmds.StringOption(pinNameOptionName, "Display only pins with the given name."), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { api, err := cmdenv.GetApi(env, req) @@ -372,6 +373,7 @@ Example: typeStr, _ := req.Options[pinTypeOptionName].(string) stream, _ := req.Options[pinStreamOptionName].(bool) displayNames, _ := req.Options[pinNamesOptionName].(bool) + name, _ := req.Options[pinNameOptionName].(string) switch typeStr { case "all", "direct", "indirect", "recursive": @@ -397,7 +399,7 @@ Example: if len(req.Arguments) > 0 { err = pinLsKeys(req, typeStr, api, emit) } else { - err = pinLsAll(req, typeStr, displayNames, api, emit) + err = pinLsAll(req, typeStr, displayNames || name != "", name, api, emit) } if err != nil { return err @@ -537,7 +539,7 @@ func pinLsKeys(req *cmds.Request, typeStr string, api coreiface.CoreAPI, emit fu return nil } -func pinLsAll(req *cmds.Request, typeStr string, detailed bool, api coreiface.CoreAPI, emit func(value PinLsOutputWrapper) error) error { +func pinLsAll(req *cmds.Request, typeStr string, detailed bool, name string, api coreiface.CoreAPI, emit func(value PinLsOutputWrapper) error) error { enc, err := cmdenv.GetCidEncoder(req) if err != nil { return err @@ -555,7 +557,7 @@ func pinLsAll(req *cmds.Request, typeStr string, detailed bool, api coreiface.Co panic("unhandled pin type") } - pins, err := api.Pin().Ls(req.Context, opt, options.Pin.Ls.Detailed(detailed)) + pins, err := api.Pin().Ls(req.Context, opt, options.Pin.Ls.Detailed(detailed), options.Pin.Ls.Name(name)) if err != nil { return err } diff --git a/core/coreapi/pin.go b/core/coreapi/pin.go index 8db582a4ffa..7b7556fa3b1 100644 --- a/core/coreapi/pin.go +++ b/core/coreapi/pin.go @@ -67,7 +67,7 @@ func (api *PinAPI) Ls(ctx context.Context, opts ...caopts.PinLsOption) (<-chan c return nil, fmt.Errorf("invalid type '%s', must be one of {direct, indirect, recursive, all}", settings.Type) } - return api.pinLsAll(ctx, settings.Type, settings.Detailed), nil + return api.pinLsAll(ctx, settings.Type, settings.Detailed, settings.Name), nil } func (api *PinAPI) IsPinned(ctx context.Context, p path.Path, opts ...caopts.PinIsPinnedOption) (string, bool, error) { @@ -276,17 +276,17 @@ func (p *pinInfo) Err() error { // // The caller must keep reading results until the channel is closed to prevent // leaking the goroutine that is fetching pins. -func (api *PinAPI) pinLsAll(ctx context.Context, typeStr string, detailed bool) <-chan coreiface.Pin { +func (api *PinAPI) pinLsAll(ctx context.Context, typeStr string, detailed bool, name string) <-chan coreiface.Pin { out := make(chan coreiface.Pin, 1) emittedSet := cid.NewSet() - AddToResultKeys := func(c cid.Cid, name, typeStr string) error { - if emittedSet.Visit(c) { + AddToResultKeys := func(c cid.Cid, pinName, typeStr string) error { + if emittedSet.Visit(c) && (name == "" || name == pinName) { select { case out <- &pinInfo{ pinType: typeStr, - name: name, + name: pinName, path: path.FromCid(c), }: case <-ctx.Done(): diff --git a/core/coreiface/options/pin.go b/core/coreiface/options/pin.go index 0efd853ef22..5b4cc9de7ec 100644 --- a/core/coreiface/options/pin.go +++ b/core/coreiface/options/pin.go @@ -12,6 +12,7 @@ type PinAddSettings struct { type PinLsSettings struct { Type string Detailed bool + Name string } // PinIsPinnedSettings represent the settings for PinAPI.IsPinned @@ -205,6 +206,13 @@ func (pinLsOpts) Detailed(detailed bool) PinLsOption { } } +func (pinLsOpts) Name(name string) PinLsOption { + return func(settings *PinLsSettings) error { + settings.Name = name + return nil + } +} + type pinIsPinnedOpts struct{} // All is an option for Pin.IsPinned which will make it search in all type of pins. diff --git a/docs/changelogs/v0.29.md b/docs/changelogs/v0.29.md index e51d34b5e48..1c1f9d62b6a 100644 --- a/docs/changelogs/v0.29.md +++ b/docs/changelogs/v0.29.md @@ -6,6 +6,7 @@ - [Overview](#overview) - [๐Ÿ”ฆ Highlights](#-highlights) + - [Add search functionality for pin names](#add-search-functionality-for-pin-names) - [๐Ÿ“ Changelog](#-changelog) - [๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ Contributors](#-contributors) @@ -13,6 +14,9 @@ ### ๐Ÿ”ฆ Highlights +#### Add search functionality for pin names +It is now possible to search for pins by name. To do so, use `ipfs pin ls --name "SomeName"`. The search is case-sensitive and will return all pins with the exact name provided. + ### ๐Ÿ“ Changelog ### ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ Contributors diff --git a/test/cli/pins_test.go b/test/cli/pins_test.go index 415da8d3b6a..d0836e3ed67 100644 --- a/test/cli/pins_test.go +++ b/test/cli/pins_test.go @@ -242,6 +242,43 @@ func TestPins(t *testing.T) { require.NotContains(t, lsOut, outADetailed) }) + t.Run("test listing pins with specific name", func(t *testing.T) { + print("test pinning with names cli text output") + t.Parallel() + + node := harness.NewT(t).NewNode().Init() + cidAStr := node.IPFSAddStr(RandomStr(1000), "--pin=false") + cidBStr := node.IPFSAddStr(RandomStr(1000), "--pin=false") + cidCStr := node.IPFSAddStr(RandomStr(1000), "--pin=false") + + outA := cidAStr + " recursive testPin" + outB := cidBStr + " recursive testPin" + outC := cidCStr + " recursive randPin" + + _ = node.IPFS("pin", "add", "--name", "testPin", cidAStr) + lsOut := pinLs(node, "-t=recursive", "--name=testPin") + require.Contains(t, lsOut, outA) + lsOut = pinLs(node, "-t=recursive", "--name=randomLabel") + require.NotContains(t, lsOut, outA) + + _ = node.IPFS("pin", "add", "--name", "testPin", cidBStr) + lsOut = pinLs(node, "-t=recursive", "--name=testPin") + require.Contains(t, lsOut, outA) + require.Contains(t, lsOut, outB) + + _ = node.IPFS("pin", "add", "--name", "randPin", cidCStr) + lsOut = pinLs(node, "-t=recursive", "--name=randPin") + require.NotContains(t, lsOut, outA) + require.NotContains(t, lsOut, outB) + require.Contains(t, lsOut, outC) + + lsOut = pinLs(node, "-t=recursive", "--name=testPin") + require.Contains(t, lsOut, outA) + require.Contains(t, lsOut, outB) + require.NotContains(t, lsOut, outC) + + }) + t.Run("test overwriting pin with name", func(t *testing.T) { t.Parallel()