Skip to content

Commit a8a6bbe

Browse files
authoredJan 4, 2024
feat: support optional pin names (#10261)
1 parent 765cffe commit a8a6bbe

File tree

22 files changed

+200
-60
lines changed

22 files changed

+200
-60
lines changed
 

‎client/rpc/pin.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ type pinRefKeyList struct {
2626
type pin struct {
2727
path path.ImmutablePath
2828
typ string
29+
name string
2930
err error
3031
}
3132

@@ -37,6 +38,10 @@ func (p pin) Path() path.ImmutablePath {
3738
return p.path
3839
}
3940

41+
func (p pin) Name() string {
42+
return p.name
43+
}
44+
4045
func (p pin) Type() string {
4146
return p.typ
4247
}
@@ -53,6 +58,7 @@ func (api *PinAPI) Add(ctx context.Context, p path.Path, opts ...caopts.PinAddOp
5358

5459
type pinLsObject struct {
5560
Cid string
61+
Name string
5662
Type string
5763
}
5864

@@ -102,7 +108,7 @@ func (api *PinAPI) Ls(ctx context.Context, opts ...caopts.PinLsOption) (<-chan i
102108
}
103109

104110
select {
105-
case ch <- pin{typ: out.Type, path: path.FromCid(c)}:
111+
case ch <- pin{typ: out.Type, name: out.Name, path: path.FromCid(c)}:
106112
case <-ctx.Done():
107113
return
108114
}

‎cmd/ipfs/kubo/init.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ func initializeIpnsKeyspace(repoRoot string) error {
252252

253253
// pin recursively because this might already be pinned
254254
// and doing a direct pin would throw an error in that case
255-
err = nd.Pinning.Pin(ctx, emptyDir, true)
255+
err = nd.Pinning.Pin(ctx, emptyDir, true, "")
256256
if err != nil {
257257
return err
258258
}

‎core/commands/dag/import.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ func dagImport(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment
152152
ret.PinErrorMsg = err.Error()
153153
} else if nd, err := blockDecoder.DecodeNode(req.Context, block); err != nil {
154154
ret.PinErrorMsg = err.Error()
155-
} else if err := node.Pinning.Pin(req.Context, nd, true); err != nil {
155+
} else if err := node.Pinning.Pin(req.Context, nd, true, ""); err != nil {
156156
ret.PinErrorMsg = err.Error()
157157
} else if err := node.Pinning.Flush(req.Context); err != nil {
158158
ret.PinErrorMsg = err.Error()

‎core/commands/pin/pin.go

+52-14
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,36 @@ var addPinCmd = &cmds.Command{
5757
Helptext: cmds.HelpText{
5858
Tagline: "Pin objects to local storage.",
5959
ShortDescription: "Stores an IPFS object(s) from a given path locally to disk.",
60+
LongDescription: `
61+
Create a pin for the given object, protecting resolved CID from being garbage
62+
collected.
63+
64+
An optional name can be provided, and read back via 'ipfs pin ls --names'.
65+
66+
Be mindful of defaults:
67+
68+
Default pin type is 'recursive' (entire DAG).
69+
Pass -r=false to create a direct pin for a single block.
70+
Use 'pin ls -t recursive' to only list roots of recursively pinned DAGs
71+
(significantly faster when many big DAGs are pinned recursively)
72+
73+
Default pin name is empty. Pass '--name' to 'pin add' to set one
74+
and use 'pin ls --names' to see it.
75+
Pin add is idempotent: pinning CID which is already pinned won't change
76+
the name, value passed with '--name' with the original pin is preserved.
77+
To rename pin, use 'pin rm' and 'pin add --name'.
78+
79+
If daemon is running, any missing blocks will be retrieved from the network.
80+
It may take some time. Pass '--progress' to track the progress.
81+
`,
6082
},
6183

6284
Arguments: []cmds.Argument{
6385
cmds.StringArg("ipfs-path", true, true, "Path to object(s) to be pinned.").EnableStdin(),
6486
},
6587
Options: []cmds.Option{
6688
cmds.BoolOption(pinRecursiveOptionName, "r", "Recursively pin the object linked to by the specified object(s).").WithDefault(true),
89+
cmds.StringOption(pinNameOptionName, "n", "An optional name for created pin(s)."),
6790
cmds.BoolOption(pinProgressOptionName, "Show progress"),
6891
},
6992
Type: AddPinOutput{},
@@ -75,6 +98,7 @@ var addPinCmd = &cmds.Command{
7598

7699
// set recursive flag
77100
recursive, _ := req.Options[pinRecursiveOptionName].(bool)
101+
name, _ := req.Options[pinNameOptionName].(string)
78102
showProgress, _ := req.Options[pinProgressOptionName].(bool)
79103

80104
if err := req.ParseBodyArgs(); err != nil {
@@ -87,7 +111,7 @@ var addPinCmd = &cmds.Command{
87111
}
88112

89113
if !showProgress {
90-
added, err := pinAddMany(req.Context, api, enc, req.Arguments, recursive)
114+
added, err := pinAddMany(req.Context, api, enc, req.Arguments, recursive, name)
91115
if err != nil {
92116
return err
93117
}
@@ -105,7 +129,7 @@ var addPinCmd = &cmds.Command{
105129

106130
ch := make(chan pinResult, 1)
107131
go func() {
108-
added, err := pinAddMany(ctx, api, enc, req.Arguments, recursive)
132+
added, err := pinAddMany(ctx, api, enc, req.Arguments, recursive, name)
109133
ch <- pinResult{pins: added, err: err}
110134
}()
111135

@@ -181,7 +205,7 @@ var addPinCmd = &cmds.Command{
181205
},
182206
}
183207

184-
func pinAddMany(ctx context.Context, api coreiface.CoreAPI, enc cidenc.Encoder, paths []string, recursive bool) ([]string, error) {
208+
func pinAddMany(ctx context.Context, api coreiface.CoreAPI, enc cidenc.Encoder, paths []string, recursive bool, name string) ([]string, error) {
185209
added := make([]string, len(paths))
186210
for i, b := range paths {
187211
p, err := cmdutils.PathOrCidPath(b)
@@ -194,7 +218,7 @@ func pinAddMany(ctx context.Context, api coreiface.CoreAPI, enc cidenc.Encoder,
194218
return nil, err
195219
}
196220

197-
if err := api.Pin().Add(ctx, rp, options.Pin.Recursive(recursive)); err != nil {
221+
if err := api.Pin().Add(ctx, rp, options.Pin.Recursive(recursive), options.Pin.Name(name)); err != nil {
198222
return nil, err
199223
}
200224
added[i] = enc.Encode(rp.RootCid())
@@ -281,6 +305,7 @@ const (
281305
pinTypeOptionName = "type"
282306
pinQuietOptionName = "quiet"
283307
pinStreamOptionName = "stream"
308+
pinNamesOptionName = "names"
284309
)
285310

286311
var listPinCmd = &cmds.Command{
@@ -294,6 +319,7 @@ respectively.
294319
`,
295320
LongDescription: `
296321
Returns a list of objects that are pinned locally.
322+
297323
By default, all pinned objects are returned, but the '--type' flag or
298324
arguments can restrict that to a specific pin type or to some specific objects
299325
respectively.
@@ -302,10 +328,13 @@ Use --type=<type> to specify the type of pinned keys to list.
302328
Valid values are:
303329
* "direct": pin that specific object.
304330
* "recursive": pin that specific object, and indirectly pin all its
305-
descendants
331+
descendants
306332
* "indirect": pinned indirectly by an ancestor (like a refcount)
307333
* "all"
308334
335+
By default, pin names are not included (returned as empty).
336+
Pass '--names' flag to return pin names (set with '--name' from 'pin add').
337+
309338
With arguments, the command fails if any of the arguments is not a pinned
310339
object. And if --type=<type> is additionally used, the command will also fail
311340
if any of the arguments is not of the specified type.
@@ -334,6 +363,7 @@ Example:
334363
cmds.StringOption(pinTypeOptionName, "t", "The type of pinned keys to list. Can be \"direct\", \"indirect\", \"recursive\", or \"all\".").WithDefault("all"),
335364
cmds.BoolOption(pinQuietOptionName, "q", "Write just hashes of objects."),
336365
cmds.BoolOption(pinStreamOptionName, "s", "Enable streaming of pins as they are discovered."),
366+
cmds.BoolOption(pinNamesOptionName, "n", "Enable displaying pin names (slower)."),
337367
},
338368
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
339369
api, err := cmdenv.GetApi(env, req)
@@ -343,6 +373,7 @@ Example:
343373

344374
typeStr, _ := req.Options[pinTypeOptionName].(string)
345375
stream, _ := req.Options[pinStreamOptionName].(bool)
376+
displayNames, _ := req.Options[pinNamesOptionName].(bool)
346377

347378
switch typeStr {
348379
case "all", "direct", "indirect", "recursive":
@@ -356,7 +387,7 @@ Example:
356387
lgcList := map[string]PinLsType{}
357388
if !stream {
358389
emit = func(v PinLsOutputWrapper) error {
359-
lgcList[v.PinLsObject.Cid] = PinLsType{Type: v.PinLsObject.Type}
390+
lgcList[v.PinLsObject.Cid] = PinLsType{Type: v.PinLsObject.Type, Name: v.PinLsObject.Name}
360391
return nil
361392
}
362393
} else {
@@ -368,7 +399,7 @@ Example:
368399
if len(req.Arguments) > 0 {
369400
err = pinLsKeys(req, typeStr, api, emit)
370401
} else {
371-
err = pinLsAll(req, typeStr, api, emit)
402+
err = pinLsAll(req, typeStr, displayNames, api, emit)
372403
}
373404
if err != nil {
374405
return err
@@ -402,17 +433,21 @@ Example:
402433
if stream {
403434
if quiet {
404435
fmt.Fprintf(w, "%s\n", out.PinLsObject.Cid)
405-
} else {
436+
} else if out.PinLsObject.Name == "" {
406437
fmt.Fprintf(w, "%s %s\n", out.PinLsObject.Cid, out.PinLsObject.Type)
438+
} else {
439+
fmt.Fprintf(w, "%s %s %s\n", out.PinLsObject.Cid, out.PinLsObject.Type, out.PinLsObject.Name)
407440
}
408441
return nil
409442
}
410443

411444
for k, v := range out.PinLsList.Keys {
412445
if quiet {
413446
fmt.Fprintf(w, "%s\n", k)
414-
} else {
447+
} else if v.Name == "" {
415448
fmt.Fprintf(w, "%s %s\n", k, v.Type)
449+
} else {
450+
fmt.Fprintf(w, "%s %s %s\n", k, v.Type, v.Name)
416451
}
417452
}
418453

@@ -437,11 +472,13 @@ type PinLsList struct {
437472
// PinLsType contains the type of a pin
438473
type PinLsType struct {
439474
Type string
475+
Name string
440476
}
441477

442478
// PinLsObject contains the description of a pin
443479
type PinLsObject struct {
444480
Cid string `json:",omitempty"`
481+
Name string `json:",omitempty"`
445482
Type string `json:",omitempty"`
446483
}
447484

@@ -502,7 +539,7 @@ func pinLsKeys(req *cmds.Request, typeStr string, api coreiface.CoreAPI, emit fu
502539
return nil
503540
}
504541

505-
func pinLsAll(req *cmds.Request, typeStr string, api coreiface.CoreAPI, emit func(value PinLsOutputWrapper) error) error {
542+
func pinLsAll(req *cmds.Request, typeStr string, detailed bool, api coreiface.CoreAPI, emit func(value PinLsOutputWrapper) error) error {
506543
enc, err := cmdenv.GetCidEncoder(req)
507544
if err != nil {
508545
return err
@@ -520,7 +557,7 @@ func pinLsAll(req *cmds.Request, typeStr string, api coreiface.CoreAPI, emit fun
520557
panic("unhandled pin type")
521558
}
522559

523-
pins, err := api.Pin().Ls(req.Context, opt)
560+
pins, err := api.Pin().Ls(req.Context, opt, options.Pin.Ls.Detailed(detailed))
524561
if err != nil {
525562
return err
526563
}
@@ -532,6 +569,7 @@ func pinLsAll(req *cmds.Request, typeStr string, api coreiface.CoreAPI, emit fun
532569
err = emit(PinLsOutputWrapper{
533570
PinLsObject: PinLsObject{
534571
Type: p.Type(),
572+
Name: p.Name(),
535573
Cid: enc.Encode(p.Path().RootCid()),
536574
},
537575
})
@@ -748,15 +786,15 @@ func pinVerify(ctx context.Context, n *core.IpfsNode, opts pinVerifyOpts, enc ci
748786
out := make(chan any)
749787
go func() {
750788
defer close(out)
751-
for p := range n.Pinning.RecursiveKeys(ctx) {
789+
for p := range n.Pinning.RecursiveKeys(ctx, false) {
752790
if p.Err != nil {
753791
out <- PinVerifyRes{Err: p.Err.Error()}
754792
return
755793
}
756-
pinStatus := checkPin(p.C)
794+
pinStatus := checkPin(p.Pin.Key)
757795
if !pinStatus.Ok || opts.includeOk {
758796
select {
759-
case out <- PinVerifyRes{Cid: enc.Encode(p.C), PinStatus: pinStatus}:
797+
case out <- PinVerifyRes{Cid: enc.Encode(p.Pin.Key), PinStatus: pinStatus}:
760798
case <-ctx.Done():
761799
return
762800
}

‎core/coreapi/block.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ func (api *BlockAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.Bloc
6060
}
6161

6262
if settings.Pin {
63-
if err = api.pinning.PinWithMode(ctx, b.Cid(), pin.Recursive); err != nil {
63+
if err = api.pinning.PinWithMode(ctx, b.Cid(), pin.Recursive, ""); err != nil {
6464
return nil, err
6565
}
6666
if err := api.pinning.Flush(ctx); err != nil {

‎core/coreapi/dag.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func (adder *pinningAdder) Add(ctx context.Context, nd ipld.Node) error {
3030
return err
3131
}
3232

33-
if err := adder.pinning.PinWithMode(ctx, nd.Cid(), pin.Recursive); err != nil {
33+
if err := adder.pinning.PinWithMode(ctx, nd.Cid(), pin.Recursive, ""); err != nil {
3434
return err
3535
}
3636

@@ -51,7 +51,7 @@ func (adder *pinningAdder) AddMany(ctx context.Context, nds []ipld.Node) error {
5151
for _, nd := range nds {
5252
c := nd.Cid()
5353
if cids.Visit(c) {
54-
if err := adder.pinning.PinWithMode(ctx, c, pin.Recursive); err != nil {
54+
if err := adder.pinning.PinWithMode(ctx, c, pin.Recursive, ""); err != nil {
5555
return err
5656
}
5757
}

‎core/coreapi/object.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ func (api *ObjectAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.Obj
133133
}
134134

135135
if options.Pin {
136-
if err := api.pinning.PinWithMode(ctx, dagnode.Cid(), pin.Recursive); err != nil {
136+
if err := api.pinning.PinWithMode(ctx, dagnode.Cid(), pin.Recursive, ""); err != nil {
137137
return path.ImmutablePath{}, err
138138
}
139139

‎core/coreapi/pin.go

+23-17
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func (api *PinAPI) Add(ctx context.Context, p path.Path, opts ...caopts.PinAddOp
3838

3939
defer api.blockstore.PinLock(ctx).Unlock(ctx)
4040

41-
err = api.pinning.Pin(ctx, dagNode, settings.Recursive)
41+
err = api.pinning.Pin(ctx, dagNode, settings.Recursive, settings.Name)
4242
if err != nil {
4343
return fmt.Errorf("pin: %s", err)
4444
}
@@ -67,7 +67,7 @@ func (api *PinAPI) Ls(ctx context.Context, opts ...caopts.PinLsOption) (<-chan c
6767
return nil, fmt.Errorf("invalid type '%s', must be one of {direct, indirect, recursive, all}", settings.Type)
6868
}
6969

70-
return api.pinLsAll(ctx, settings.Type), nil
70+
return api.pinLsAll(ctx, settings.Type, settings.Detailed), nil
7171
}
7272

7373
func (api *PinAPI) IsPinned(ctx context.Context, p path.Path, opts ...caopts.PinIsPinnedOption) (string, bool, error) {
@@ -231,12 +231,12 @@ func (api *PinAPI) Verify(ctx context.Context) (<-chan coreiface.PinStatus, erro
231231
out := make(chan coreiface.PinStatus)
232232
go func() {
233233
defer close(out)
234-
for p := range api.pinning.RecursiveKeys(ctx) {
234+
for p := range api.pinning.RecursiveKeys(ctx, false) {
235235
var res *pinStatus
236236
if p.Err != nil {
237237
res = &pinStatus{err: p.Err}
238238
} else {
239-
res = checkPin(p.C)
239+
res = checkPin(p.Pin.Key)
240240
}
241241
select {
242242
case <-ctx.Done():
@@ -252,6 +252,7 @@ func (api *PinAPI) Verify(ctx context.Context) (<-chan coreiface.PinStatus, erro
252252
type pinInfo struct {
253253
pinType string
254254
path path.ImmutablePath
255+
name string
255256
err error
256257
}
257258

@@ -263,6 +264,10 @@ func (p *pinInfo) Type() string {
263264
return p.pinType
264265
}
265266

267+
func (p *pinInfo) Name() string {
268+
return p.name
269+
}
270+
266271
func (p *pinInfo) Err() error {
267272
return p.err
268273
}
@@ -271,16 +276,17 @@ func (p *pinInfo) Err() error {
271276
//
272277
// The caller must keep reading results until the channel is closed to prevent
273278
// leaking the goroutine that is fetching pins.
274-
func (api *PinAPI) pinLsAll(ctx context.Context, typeStr string) <-chan coreiface.Pin {
279+
func (api *PinAPI) pinLsAll(ctx context.Context, typeStr string, detailed bool) <-chan coreiface.Pin {
275280
out := make(chan coreiface.Pin, 1)
276281

277282
emittedSet := cid.NewSet()
278283

279-
AddToResultKeys := func(c cid.Cid, typeStr string) error {
284+
AddToResultKeys := func(c cid.Cid, name, typeStr string) error {
280285
if emittedSet.Visit(c) {
281286
select {
282287
case out <- &pinInfo{
283288
pinType: typeStr,
289+
name: name,
284290
path: path.FromCid(c),
285291
}:
286292
case <-ctx.Done():
@@ -296,25 +302,25 @@ func (api *PinAPI) pinLsAll(ctx context.Context, typeStr string) <-chan coreifac
296302
var rkeys []cid.Cid
297303
var err error
298304
if typeStr == "recursive" || typeStr == "all" {
299-
for streamedCid := range api.pinning.RecursiveKeys(ctx) {
305+
for streamedCid := range api.pinning.RecursiveKeys(ctx, detailed) {
300306
if streamedCid.Err != nil {
301307
out <- &pinInfo{err: streamedCid.Err}
302308
return
303309
}
304-
if err = AddToResultKeys(streamedCid.C, "recursive"); err != nil {
310+
if err = AddToResultKeys(streamedCid.Pin.Key, streamedCid.Pin.Name, "recursive"); err != nil {
305311
out <- &pinInfo{err: err}
306312
return
307313
}
308-
rkeys = append(rkeys, streamedCid.C)
314+
rkeys = append(rkeys, streamedCid.Pin.Key)
309315
}
310316
}
311317
if typeStr == "direct" || typeStr == "all" {
312-
for streamedCid := range api.pinning.DirectKeys(ctx) {
318+
for streamedCid := range api.pinning.DirectKeys(ctx, detailed) {
313319
if streamedCid.Err != nil {
314320
out <- &pinInfo{err: streamedCid.Err}
315321
return
316322
}
317-
if err = AddToResultKeys(streamedCid.C, "direct"); err != nil {
323+
if err = AddToResultKeys(streamedCid.Pin.Key, streamedCid.Pin.Name, "direct"); err != nil {
318324
out <- &pinInfo{err: err}
319325
return
320326
}
@@ -324,21 +330,21 @@ func (api *PinAPI) pinLsAll(ctx context.Context, typeStr string) <-chan coreifac
324330
// We need to first visit the direct pins that have priority
325331
// without emitting them
326332

327-
for streamedCid := range api.pinning.DirectKeys(ctx) {
333+
for streamedCid := range api.pinning.DirectKeys(ctx, detailed) {
328334
if streamedCid.Err != nil {
329335
out <- &pinInfo{err: streamedCid.Err}
330336
return
331337
}
332-
emittedSet.Add(streamedCid.C)
338+
emittedSet.Add(streamedCid.Pin.Key)
333339
}
334340

335-
for streamedCid := range api.pinning.RecursiveKeys(ctx) {
341+
for streamedCid := range api.pinning.RecursiveKeys(ctx, detailed) {
336342
if streamedCid.Err != nil {
337343
out <- &pinInfo{err: streamedCid.Err}
338344
return
339345
}
340-
emittedSet.Add(streamedCid.C)
341-
rkeys = append(rkeys, streamedCid.C)
346+
emittedSet.Add(streamedCid.Pin.Key)
347+
rkeys = append(rkeys, streamedCid.Pin.Key)
342348
}
343349
}
344350
if typeStr == "indirect" || typeStr == "all" {
@@ -353,7 +359,7 @@ func (api *PinAPI) pinLsAll(ctx context.Context, typeStr string) <-chan coreifac
353359
if emittedSet.Has(c) {
354360
return true // skipped
355361
}
356-
err := AddToResultKeys(c, "indirect")
362+
err := AddToResultKeys(c, "", "indirect")
357363
if err != nil {
358364
out <- &pinInfo{err: err}
359365
return false

‎core/coreiface/options/pin.go

+20-1
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ import "fmt"
55
// PinAddSettings represent the settings for PinAPI.Add
66
type PinAddSettings struct {
77
Recursive bool
8+
Name string
89
}
910

1011
// PinLsSettings represent the settings for PinAPI.Ls
1112
type PinLsSettings struct {
12-
Type string
13+
Type string
14+
Detailed bool
1315
}
1416

1517
// PinIsPinnedSettings represent the settings for PinAPI.IsPinned
@@ -194,6 +196,15 @@ func (pinLsOpts) pinType(t string) PinLsOption {
194196
}
195197
}
196198

199+
// Detailed is an option for [Pin.Ls] which sets whether or not to return
200+
// detailed information, such as pin names and modes.
201+
func (pinLsOpts) Detailed(detailed bool) PinLsOption {
202+
return func(settings *PinLsSettings) error {
203+
settings.Detailed = detailed
204+
return nil
205+
}
206+
}
207+
197208
type pinIsPinnedOpts struct{}
198209

199210
// All is an option for Pin.IsPinned which will make it search in all type of pins.
@@ -263,6 +274,14 @@ func (pinOpts) Recursive(recursive bool) PinAddOption {
263274
}
264275
}
265276

277+
// Name is an option for Pin.Add which specifies an optional name to add to the pin.
278+
func (pinOpts) Name(name string) PinAddOption {
279+
return func(settings *PinAddSettings) error {
280+
settings.Name = name
281+
return nil
282+
}
283+
}
284+
266285
// RmRecursive is an option for Pin.Rm which specifies whether to recursively
267286
// unpin the object linked to by the specified object(s). This does not remove
268287
// indirect pins referenced by other recursive pins.

‎core/coreiface/pin.go

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ type Pin interface {
1313
// Path to the pinned object
1414
Path() path.ImmutablePath
1515

16+
// Name is the name of the pin.
17+
Name() string
18+
1619
// Type of the pin
1720
Type() string
1821

‎core/coreunix/add.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ func (adder *Adder) PinRoot(ctx context.Context, root ipld.Node) error {
186186
adder.tempRoot = rnk
187187
}
188188

189-
err = adder.pinning.PinWithMode(ctx, rnk, pin.Recursive)
189+
err = adder.pinning.PinWithMode(ctx, rnk, pin.Recursive, "")
190190
if err != nil {
191191
return err
192192
}

‎docs/changelogs/v0.26.md

+5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- [Overview](#overview)
88
- [🔦 Highlights](#-highlights)
99
- [Several deprecated commands have been removed](#several-deprecated-commands-have-been-removed)
10+
- [Support optional pin names](#support-optional-pin-names)
1011
- [📝 Changelog](#-changelog)
1112
- [👨‍👩‍👧‍👦 Contributors](#-contributors)
1213

@@ -30,6 +31,10 @@ Several deprecated commands have been removed:
3031
- `ipfs dns` deprecated in [April 2022, Kubo 0.13](https://github.com/ipfs/kubo/commit/76ae33a9f3f9abd166d1f6f23d6a8a0511510e3c), use `ipfs resolve /ipns/{name}` instead.
3132
- `ipfs tar` deprecated [April 2022, Kubo 0.13](https://github.com/ipfs/kubo/pull/8849)
3233

34+
#### Support optional pin names
35+
36+
You can now add a name to a pin when pinning a CID. To do so, use `ipfs pin add --name "Some Name" bafy...`. You can list your pins, including their names, with `ipfs pin ls --names`.
37+
3338
### 📝 Changelog
3439

3540
- Export a `kubo.Start` function so users can programmatically start Kubo from within a go program.

‎docs/examples/kubo-as-a-library/go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ go 1.20
77
replace github.com/ipfs/kubo => ./../../..
88

99
require (
10-
github.com/ipfs/boxo v0.16.0
10+
github.com/ipfs/boxo v0.16.1-0.20240104124825-38fb74f76b0d
1111
github.com/ipfs/kubo v0.0.0-00010101000000-000000000000
1212
github.com/libp2p/go-libp2p v0.32.2
1313
github.com/multiformats/go-multiaddr v0.12.0

‎docs/examples/kubo-as-a-library/go.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -303,8 +303,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c h1:7Uy
303303
github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c/go.mod h1:6EekK/jo+TynwSE/ZOiOJd4eEvRXoavEC3vquKtv4yI=
304304
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
305305
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
306-
github.com/ipfs/boxo v0.16.0 h1:A9dUmef5a+mEFki6kbyG7el5gl65CiUBzrDeZxzTWKY=
307-
github.com/ipfs/boxo v0.16.0/go.mod h1:jAgpNQn7T7BnibUeReXcKU9Ha1xmYNyOlwVEl193ow0=
306+
github.com/ipfs/boxo v0.16.1-0.20240104124825-38fb74f76b0d h1:7tDzalCLHYr4tzrjNrfqZvIki2MEBSrpLBdc0bssDZk=
307+
github.com/ipfs/boxo v0.16.1-0.20240104124825-38fb74f76b0d/go.mod h1:jAgpNQn7T7BnibUeReXcKU9Ha1xmYNyOlwVEl193ow0=
308308
github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
309309
github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
310310
github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY=

‎fuse/ipns/common.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ func InitializeKeyspace(n *core.IpfsNode, key ci.PrivKey) error {
1818

1919
emptyDir := ft.EmptyDirNode()
2020

21-
err := n.Pinning.Pin(ctx, emptyDir, false)
21+
err := n.Pinning.Pin(ctx, emptyDir, false, "")
2222
if err != nil {
2323
return err
2424
}

‎gc/gc.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ func GC(ctx context.Context, bs bstore.GCBlockstore, dstor dstore.Datastore, pn
154154
// Descendants recursively finds all the descendants of the given roots and
155155
// adds them to the given cid.Set, using the provided dag.GetLinks function
156156
// to walk the tree.
157-
func Descendants(ctx context.Context, getLinks dag.GetLinks, set *cid.Set, roots <-chan pin.StreamedCid) error {
157+
func Descendants(ctx context.Context, getLinks dag.GetLinks, set *cid.Set, roots <-chan pin.StreamedPin) error {
158158
verifyGetLinks := func(ctx context.Context, c cid.Cid) ([]*ipld.Link, error) {
159159
err := verifcid.ValidateCid(verifcid.DefaultAllowlist, c)
160160
if err != nil {
@@ -188,7 +188,7 @@ func Descendants(ctx context.Context, getLinks dag.GetLinks, set *cid.Set, roots
188188
}
189189

190190
// Walk recursively walks the dag and adds the keys to the given set
191-
err := dag.Walk(ctx, verifyGetLinks, wrapper.C, func(k cid.Cid) bool {
191+
err := dag.Walk(ctx, verifyGetLinks, wrapper.Pin.Key, func(k cid.Cid) bool {
192192
return set.Visit(toCidV1(k))
193193
}, dag.Concurrent())
194194
if err != nil {
@@ -226,7 +226,7 @@ func ColoredSet(ctx context.Context, pn pin.Pinner, ng ipld.NodeGetter, bestEffo
226226
}
227227
return links, nil
228228
}
229-
rkeys := pn.RecursiveKeys(ctx)
229+
rkeys := pn.RecursiveKeys(ctx, false)
230230
err := Descendants(ctx, getLinks, gcs, rkeys)
231231
if err != nil {
232232
errors = true
@@ -249,14 +249,14 @@ func ColoredSet(ctx context.Context, pn pin.Pinner, ng ipld.NodeGetter, bestEffo
249249
}
250250
return links, nil
251251
}
252-
bestEffortRootsChan := make(chan pin.StreamedCid)
252+
bestEffortRootsChan := make(chan pin.StreamedPin)
253253
go func() {
254254
defer close(bestEffortRootsChan)
255255
for _, root := range bestEffortRoots {
256256
select {
257257
case <-ctx.Done():
258258
return
259-
case bestEffortRootsChan <- pin.StreamedCid{C: root}:
259+
case bestEffortRootsChan <- pin.StreamedPin{Pin: pin.Pinned{Key: root}}:
260260
}
261261
}
262262
}()
@@ -270,15 +270,15 @@ func ColoredSet(ctx context.Context, pn pin.Pinner, ng ipld.NodeGetter, bestEffo
270270
}
271271
}
272272

273-
dkeys := pn.DirectKeys(ctx)
273+
dkeys := pn.DirectKeys(ctx, false)
274274
for k := range dkeys {
275275
if k.Err != nil {
276276
return nil, k.Err
277277
}
278-
gcs.Add(toCidV1(k.C))
278+
gcs.Add(toCidV1(k.Pin.Key))
279279
}
280280

281-
ikeys := pn.InternalPins(ctx)
281+
ikeys := pn.InternalPins(ctx, false)
282282
err = Descendants(ctx, getLinks, gcs, ikeys)
283283
if err != nil {
284284
errors = true

‎gc/gc_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ func TestGC(t *testing.T) {
3838
// direct
3939
root, _, err := daggen.MakeDagNode(dserv.Add, 0, 1)
4040
require.NoError(t, err)
41-
err = pinner.PinWithMode(ctx, root, pin.Direct)
41+
err = pinner.PinWithMode(ctx, root, pin.Direct, "")
4242
require.NoError(t, err)
4343
expectedKept = append(expectedKept, root.Hash())
4444

4545
// recursive
4646
root, allCids, err := daggen.MakeDagNode(dserv.Add, 5, 2)
4747
require.NoError(t, err)
48-
err = pinner.PinWithMode(ctx, root, pin.Recursive)
48+
err = pinner.PinWithMode(ctx, root, pin.Recursive, "")
4949
require.NoError(t, err)
5050
expectedKept = append(expectedKept, toMHs(allCids)...)
5151
}

‎go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ require (
1717
github.com/hashicorp/go-multierror v1.1.1
1818
github.com/ipfs-shipyard/nopfs v0.0.12-0.20231027223058-cde3b5ba964c
1919
github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c
20-
github.com/ipfs/boxo v0.16.0
20+
github.com/ipfs/boxo v0.16.1-0.20240104124825-38fb74f76b0d
2121
github.com/ipfs/go-block-format v0.2.0
2222
github.com/ipfs/go-cid v0.4.1
2323
github.com/ipfs/go-cidutil v0.1.0

‎go.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -337,8 +337,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c h1:7Uy
337337
github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c/go.mod h1:6EekK/jo+TynwSE/ZOiOJd4eEvRXoavEC3vquKtv4yI=
338338
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
339339
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
340-
github.com/ipfs/boxo v0.16.0 h1:A9dUmef5a+mEFki6kbyG7el5gl65CiUBzrDeZxzTWKY=
341-
github.com/ipfs/boxo v0.16.0/go.mod h1:jAgpNQn7T7BnibUeReXcKU9Ha1xmYNyOlwVEl193ow0=
340+
github.com/ipfs/boxo v0.16.1-0.20240104124825-38fb74f76b0d h1:7tDzalCLHYr4tzrjNrfqZvIki2MEBSrpLBdc0bssDZk=
341+
github.com/ipfs/boxo v0.16.1-0.20240104124825-38fb74f76b0d/go.mod h1:jAgpNQn7T7BnibUeReXcKU9Ha1xmYNyOlwVEl193ow0=
342342
github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
343343
github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
344344
github.com/ipfs/go-bitswap v0.11.0 h1:j1WVvhDX1yhG32NTC9xfxnqycqYIlhzEzLXG/cU1HyQ=

‎test/cli/pins_test.go

+63
Original file line numberDiff line numberDiff line change
@@ -209,4 +209,67 @@ func TestPins(t *testing.T) {
209209
testPins(t, testPinsArgs{runDaemon: true, baseArg: "--cid-base=base32"})
210210
testPins(t, testPinsArgs{runDaemon: true, lsArg: "--stream", baseArg: "--cid-base=base32"})
211211
})
212+
213+
t.Run("test pinning with names cli text output", func(t *testing.T) {
214+
t.Parallel()
215+
216+
node := harness.NewT(t).NewNode().Init()
217+
cidAStr := node.IPFSAddStr(RandomStr(1000), "--pin=false")
218+
cidBStr := node.IPFSAddStr(RandomStr(1000), "--pin=false")
219+
220+
_ = node.IPFS("pin", "add", "--name", "testPin", cidAStr)
221+
222+
outARegular := cidAStr + " recursive"
223+
outADetailed := outARegular + " testPin"
224+
outBRegular := cidBStr + " recursive"
225+
outBDetailed := outBRegular + " testPin"
226+
227+
pinLs := func(args ...string) []string {
228+
return strings.Split(node.IPFS(StrCat("pin", "ls", args)...).Stdout.Trimmed(), "\n")
229+
}
230+
231+
lsOut := pinLs("-t=recursive")
232+
require.Contains(t, lsOut, outARegular)
233+
require.NotContains(t, lsOut, outADetailed)
234+
235+
lsOut = pinLs("-t=recursive", "--names")
236+
require.Contains(t, lsOut, outADetailed)
237+
require.NotContains(t, lsOut, outARegular)
238+
239+
_ = node.IPFS("pin", "update", cidAStr, cidBStr)
240+
lsOut = pinLs("-t=recursive", "--names")
241+
require.Contains(t, lsOut, outBDetailed)
242+
require.NotContains(t, lsOut, outADetailed)
243+
})
244+
245+
// JSON that is also the wire format of /api/v0
246+
t.Run("test pinning with names json output", func(t *testing.T) {
247+
t.Parallel()
248+
249+
node := harness.NewT(t).NewNode().Init()
250+
cidAStr := node.IPFSAddStr(RandomStr(1000), "--pin=false")
251+
cidBStr := node.IPFSAddStr(RandomStr(1000), "--pin=false")
252+
253+
_ = node.IPFS("pin", "add", "--name", "testPinJson", cidAStr)
254+
255+
outARegular := `"` + cidAStr + `":{"Type":"recursive"`
256+
outADetailed := outARegular + `,"Name":"testPinJson"`
257+
outBRegular := `"` + cidBStr + `":{"Type":"recursive"`
258+
outBDetailed := outBRegular + `,"Name":"testPinJson"`
259+
260+
pinLs := func(args ...string) string {
261+
return node.IPFS(StrCat("pin", "ls", "--enc=json", args)...).Stdout.Trimmed()
262+
}
263+
264+
lsOut := pinLs("-t=recursive")
265+
require.Contains(t, lsOut, outARegular)
266+
require.NotContains(t, lsOut, outADetailed)
267+
268+
lsOut = pinLs("-t=recursive", "--names")
269+
require.Contains(t, lsOut, outADetailed)
270+
271+
_ = node.IPFS("pin", "update", cidAStr, cidBStr)
272+
lsOut = pinLs("-t=recursive", "--names")
273+
require.Contains(t, lsOut, outBDetailed)
274+
})
212275
}

‎test/dependencies/go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ require (
103103
github.com/hexops/gotextdiff v1.0.3 // indirect
104104
github.com/inconshreveable/mousetrap v1.1.0 // indirect
105105
github.com/ipfs/bbloom v0.0.4 // indirect
106-
github.com/ipfs/boxo v0.16.0 // indirect
106+
github.com/ipfs/boxo v0.16.1-0.20240104124825-38fb74f76b0d // indirect
107107
github.com/ipfs/go-block-format v0.2.0 // indirect
108108
github.com/ipfs/go-cid v0.4.1 // indirect
109109
github.com/ipfs/go-datastore v0.6.0 // indirect

‎test/dependencies/go.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -342,8 +342,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
342342
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
343343
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
344344
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
345-
github.com/ipfs/boxo v0.16.0 h1:A9dUmef5a+mEFki6kbyG7el5gl65CiUBzrDeZxzTWKY=
346-
github.com/ipfs/boxo v0.16.0/go.mod h1:jAgpNQn7T7BnibUeReXcKU9Ha1xmYNyOlwVEl193ow0=
345+
github.com/ipfs/boxo v0.16.1-0.20240104124825-38fb74f76b0d h1:7tDzalCLHYr4tzrjNrfqZvIki2MEBSrpLBdc0bssDZk=
346+
github.com/ipfs/boxo v0.16.1-0.20240104124825-38fb74f76b0d/go.mod h1:jAgpNQn7T7BnibUeReXcKU9Ha1xmYNyOlwVEl193ow0=
347347
github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs=
348348
github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM=
349349
github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s=

0 commit comments

Comments
 (0)
Please sign in to comment.