@cryptotaxi247 / kubo / commits / ae0508564

feat: enables searching pins by name (#10412)

Co-authored-by: Henrique Dias <mail@hacdias.com>

IGP committed May 14, 2024 at 13:05 UTC ae05085644b5f5c9f2bdae30bd332d2e28de3a7a
5 files changed +59 -8
core/commands/pin/pin.go
+5 -3
@@ -362,6 +362,7 @@ Example:
362 cmds.BoolOption(pinQuietOptionName, "q", "Write just hashes of objects."),
363 cmds.BoolOption(pinStreamOptionName, "s", "Enable streaming of pins as they are discovered."),
364 cmds.BoolOption(pinNamesOptionName, "n", "Enable displaying pin names (slower)."),
365 + cmds.StringOption(pinNameOptionName, "Display pins with names that contain the value provided (case-sensitive, exact match)."),
366 },
367 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
368 api, err := cmdenv.GetApi(env, req)
@@ -372,6 +373,7 @@ Example:
373 typeStr, _ := req.Options[pinTypeOptionName].(string)
374 stream, _ := req.Options[pinStreamOptionName].(bool)
375 displayNames, _ := req.Options[pinNamesOptionName].(bool)
376 + name, _ := req.Options[pinNameOptionName].(string)
377
378 switch typeStr {
379 case "all", "direct", "indirect", "recursive":
@@ -397,7 +399,7 @@ Example:
399 if len(req.Arguments) > 0 {
400 err = pinLsKeys(req, typeStr, api, emit)
401 } else {
400 - err = pinLsAll(req, typeStr, displayNames, api, emit)
402 + err = pinLsAll(req, typeStr, displayNames || name != "", name, api, emit)
403 }
404 if err != nil {
405 return err
@@ -537,7 +539,7 @@ func pinLsKeys(req *cmds.Request, typeStr string, api coreiface.CoreAPI, emit fu
539 return nil
540 }
541
540 -func pinLsAll(req *cmds.Request, typeStr string, detailed bool, api coreiface.CoreAPI, emit func(value PinLsOutputWrapper) error) error {
542 +func pinLsAll(req *cmds.Request, typeStr string, detailed bool, name string, api coreiface.CoreAPI, emit func(value PinLsOutputWrapper) error) error {
543 enc, err := cmdenv.GetCidEncoder(req)
544 if err != nil {
545 return err
@@ -555,7 +557,7 @@ func pinLsAll(req *cmds.Request, typeStr string, detailed bool, api coreiface.Co
557 panic("unhandled pin type")
558 }
559
558 - pins, err := api.Pin().Ls(req.Context, opt, options.Pin.Ls.Detailed(detailed))
560 + pins, err := api.Pin().Ls(req.Context, opt, options.Pin.Ls.Detailed(detailed), options.Pin.Ls.Name(name))
561 if err != nil {
562 return err
563 }
core/coreapi/pin.go
+6 -5
@@ -3,6 +3,7 @@ package coreapi
3 import (
4 "context"
5 "fmt"
6 + "strings"
7
8 bserv "github.com/ipfs/boxo/blockservice"
9 offline "github.com/ipfs/boxo/exchange/offline"
@@ -67,7 +68,7 @@ func (api *PinAPI) Ls(ctx context.Context, opts ...caopts.PinLsOption) (<-chan c
68 return nil, fmt.Errorf("invalid type '%s', must be one of {direct, indirect, recursive, all}", settings.Type)
69 }
70
70 - return api.pinLsAll(ctx, settings.Type, settings.Detailed), nil
71 + return api.pinLsAll(ctx, settings.Type, settings.Detailed, settings.Name), nil
72 }
73
74 func (api *PinAPI) IsPinned(ctx context.Context, p path.Path, opts ...caopts.PinIsPinnedOption) (string, bool, error) {
@@ -276,17 +277,17 @@ func (p *pinInfo) Err() error {
277 //
278 // The caller must keep reading results until the channel is closed to prevent
279 // leaking the goroutine that is fetching pins.
279 -func (api *PinAPI) pinLsAll(ctx context.Context, typeStr string, detailed bool) <-chan coreiface.Pin {
280 +func (api *PinAPI) pinLsAll(ctx context.Context, typeStr string, detailed bool, name string) <-chan coreiface.Pin {
281 out := make(chan coreiface.Pin, 1)
282
283 emittedSet := cid.NewSet()
284
284 - AddToResultKeys := func(c cid.Cid, name, typeStr string) error {
285 - if emittedSet.Visit(c) {
285 + AddToResultKeys := func(c cid.Cid, pinName, typeStr string) error {
286 + if emittedSet.Visit(c) && (name == "" || strings.Contains(pinName, name)) {
287 select {
288 case out <- &pinInfo{
289 pinType: typeStr,
289 - name: name,
290 + name: pinName,
291 path: path.FromCid(c),
292 }:
293 case <-ctx.Done():
core/coreiface/options/pin.go
+8
@@ -12,6 +12,7 @@ type PinAddSettings struct {
12 type PinLsSettings struct {
13 Type string
14 Detailed bool
15 + Name string
16 }
17
18 // PinIsPinnedSettings represent the settings for PinAPI.IsPinned
@@ -205,6 +206,13 @@ func (pinLsOpts) Detailed(detailed bool) PinLsOption {
206 }
207 }
208
209 +func (pinLsOpts) Name(name string) PinLsOption {
210 + return func(settings *PinLsSettings) error {
211 + settings.Name = name
212 + return nil
213 + }
214 +}
215 +
216 type pinIsPinnedOpts struct{}
217
218 // All is an option for Pin.IsPinned which will make it search in all type of pins.
docs/changelogs/v0.29.md
+5
@@ -6,6 +6,7 @@
6
7 - [Overview](#overview)
8 - [🔦 Highlights](#-highlights)
9 + - [Add search functionality for pin names](#add-search-functionality-for-pin-names)
10 - [📝 Changelog](#-changelog)
11 - [👨‍👩‍👧‍👦 Contributors](#-contributors)
12
@@ -13,6 +14,10 @@
14
15 ### 🔦 Highlights
16
17 +#### Add search functionality for pin names
18 +
19 +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 having a name which contains the exact word provided.
20 +
21 ### 📝 Changelog
22
23 ### 👨‍👩‍👧‍👦 Contributors
test/cli/pins_test.go
+35
@@ -242,6 +242,41 @@ func TestPins(t *testing.T) {
242 require.NotContains(t, lsOut, outADetailed)
243 })
244
245 + t.Run("test listing pins which contains specific name", func(t *testing.T) {
246 + t.Parallel()
247 +
248 + node := harness.NewT(t).NewNode().Init()
249 + cidAStr := node.IPFSAddStr(RandomStr(1000), "--pin=false")
250 + cidBStr := node.IPFSAddStr(RandomStr(1000), "--pin=false")
251 + cidCStr := node.IPFSAddStr(RandomStr(1000), "--pin=false")
252 +
253 + outA := cidAStr + " recursive testPin"
254 + outB := cidBStr + " recursive testPin"
255 + outC := cidCStr + " recursive randPin"
256 +
257 + _ = node.IPFS("pin", "add", "--name", "testPin", cidAStr)
258 + lsOut := pinLs(node, "-t=recursive", "--name=test")
259 + require.Contains(t, lsOut, outA)
260 + lsOut = pinLs(node, "-t=recursive", "--name=randomLabel")
261 + require.NotContains(t, lsOut, outA)
262 +
263 + _ = node.IPFS("pin", "add", "--name", "testPin", cidBStr)
264 + lsOut = pinLs(node, "-t=recursive", "--name=test")
265 + require.Contains(t, lsOut, outA)
266 + require.Contains(t, lsOut, outB)
267 +
268 + _ = node.IPFS("pin", "add", "--name", "randPin", cidCStr)
269 + lsOut = pinLs(node, "-t=recursive", "--name=rand")
270 + require.NotContains(t, lsOut, outA)
271 + require.NotContains(t, lsOut, outB)
272 + require.Contains(t, lsOut, outC)
273 +
274 + lsOut = pinLs(node, "-t=recursive", "--name=testPin")
275 + require.Contains(t, lsOut, outA)
276 + require.Contains(t, lsOut, outB)
277 + require.NotContains(t, lsOut, outC)
278 + })
279 +
280 t.Run("test overwriting pin with name", func(t *testing.T) {
281 t.Parallel()
282