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