@cryptotaxi247 / kubo / commits / a8a6bbe92

feat: support optional pin names (#10261)

Henrique Dias committed Jan 4, 2024 at 14:25 UTC a8a6bbe929b0a821d854a20e3f5ed68f6cfe601c
22 files changed +200 -60
client/rpc/pin.go
+7 -1
@@ -26,6 +26,7 @@ type pinRefKeyList struct {
26 type pin struct {
27 path path.ImmutablePath
28 typ string
29 + name string
30 err error
31 }
32
@@ -37,6 +38,10 @@ func (p pin) Path() path.ImmutablePath {
38 return p.path
39 }
40
41 +func (p pin) Name() string {
42 + return p.name
43 +}
44 +
45 func (p pin) Type() string {
46 return p.typ
47 }
@@ -53,6 +58,7 @@ func (api *PinAPI) Add(ctx context.Context, p path.Path, opts ...caopts.PinAddOp
58
59 type pinLsObject struct {
60 Cid string
61 + Name string
62 Type string
63 }
64
@@ -102,7 +108,7 @@ func (api *PinAPI) Ls(ctx context.Context, opts ...caopts.PinLsOption) (<-chan i
108 }
109
110 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)}:
112 case <-ctx.Done():
113 return
114 }
cmd/ipfs/kubo/init.go
+1 -1
@@ -252,7 +252,7 @@ func initializeIpnsKeyspace(repoRoot string) error {
252
253 // pin recursively because this might already be pinned
254 // 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, "")
256 if err != nil {
257 return err
258 }
core/commands/dag/import.go
+1 -1
@@ -152,7 +152,7 @@ func dagImport(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment
152 ret.PinErrorMsg = err.Error()
153 } else if nd, err := blockDecoder.DecodeNode(req.Context, block); err != nil {
154 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 {
156 ret.PinErrorMsg = err.Error()
157 } else if err := node.Pinning.Flush(req.Context); err != nil {
158 ret.PinErrorMsg = err.Error()
core/commands/pin/pin.go
+52 -14
@@ -57,6 +57,28 @@ var addPinCmd = &cmds.Command{
57 Helptext: cmds.HelpText{
58 Tagline: "Pin objects to local storage.",
59 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 +`,
82 },
83
84 Arguments: []cmds.Argument{
@@ -64,6 +86,7 @@ var addPinCmd = &cmds.Command{
86 },
87 Options: []cmds.Option{
88 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)."),
90 cmds.BoolOption(pinProgressOptionName, "Show progress"),
91 },
92 Type: AddPinOutput{},
@@ -75,6 +98,7 @@ var addPinCmd = &cmds.Command{
98
99 // set recursive flag
100 recursive, _ := req.Options[pinRecursiveOptionName].(bool)
101 + name, _ := req.Options[pinNameOptionName].(string)
102 showProgress, _ := req.Options[pinProgressOptionName].(bool)
103
104 if err := req.ParseBodyArgs(); err != nil {
@@ -87,7 +111,7 @@ var addPinCmd = &cmds.Command{
111 }
112
113 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)
115 if err != nil {
116 return err
117 }
@@ -105,7 +129,7 @@ var addPinCmd = &cmds.Command{
129
130 ch := make(chan pinResult, 1)
131 go func() {
108 - added, err := pinAddMany(ctx, api, enc, req.Arguments, recursive)
132 + added, err := pinAddMany(ctx, api, enc, req.Arguments, recursive, name)
133 ch <- pinResult{pins: added, err: err}
134 }()
135
@@ -181,7 +205,7 @@ var addPinCmd = &cmds.Command{
205 },
206 }
207
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) {
209 added := make([]string, len(paths))
210 for i, b := range paths {
211 p, err := cmdutils.PathOrCidPath(b)
@@ -194,7 +218,7 @@ func pinAddMany(ctx context.Context, api coreiface.CoreAPI, enc cidenc.Encoder,
218 return nil, err
219 }
220
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 {
222 return nil, err
223 }
224 added[i] = enc.Encode(rp.RootCid())
@@ -281,6 +305,7 @@ const (
305 pinTypeOptionName = "type"
306 pinQuietOptionName = "quiet"
307 pinStreamOptionName = "stream"
308 + pinNamesOptionName = "names"
309 )
310
311 var listPinCmd = &cmds.Command{
@@ -294,6 +319,7 @@ respectively.
319 `,
320 LongDescription: `
321 Returns a list of objects that are pinned locally.
322 +
323 By default, all pinned objects are returned, but the '--type' flag or
324 arguments can restrict that to a specific pin type or to some specific objects
325 respectively.
@@ -302,10 +328,13 @@ Use --type=<type> to specify the type of pinned keys to list.
328 Valid values are:
329 * "direct": pin that specific object.
330 * "recursive": pin that specific object, and indirectly pin all its
305 - descendants
331 + descendants
332 * "indirect": pinned indirectly by an ancestor (like a refcount)
333 * "all"
334
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 +
338 With arguments, the command fails if any of the arguments is not a pinned
339 object. And if --type=<type> is additionally used, the command will also fail
340 if any of the arguments is not of the specified type.
@@ -334,6 +363,7 @@ Example:
363 cmds.StringOption(pinTypeOptionName, "t", "The type of pinned keys to list. Can be \"direct\", \"indirect\", \"recursive\", or \"all\".").WithDefault("all"),
364 cmds.BoolOption(pinQuietOptionName, "q", "Write just hashes of objects."),
365 cmds.BoolOption(pinStreamOptionName, "s", "Enable streaming of pins as they are discovered."),
366 + cmds.BoolOption(pinNamesOptionName, "n", "Enable displaying pin names (slower)."),
367 },
368 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
369 api, err := cmdenv.GetApi(env, req)
@@ -343,6 +373,7 @@ Example:
373
374 typeStr, _ := req.Options[pinTypeOptionName].(string)
375 stream, _ := req.Options[pinStreamOptionName].(bool)
376 + displayNames, _ := req.Options[pinNamesOptionName].(bool)
377
378 switch typeStr {
379 case "all", "direct", "indirect", "recursive":
@@ -356,7 +387,7 @@ Example:
387 lgcList := map[string]PinLsType{}
388 if !stream {
389 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}
391 return nil
392 }
393 } else {
@@ -368,7 +399,7 @@ Example:
399 if len(req.Arguments) > 0 {
400 err = pinLsKeys(req, typeStr, api, emit)
401 } else {
371 - err = pinLsAll(req, typeStr, api, emit)
402 + err = pinLsAll(req, typeStr, displayNames, api, emit)
403 }
404 if err != nil {
405 return err
@@ -402,8 +433,10 @@ Example:
433 if stream {
434 if quiet {
435 fmt.Fprintf(w, "%s\n", out.PinLsObject.Cid)
405 - } else {
436 + } else if out.PinLsObject.Name == "" {
437 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)
440 }
441 return nil
442 }
@@ -411,8 +444,10 @@ Example:
444 for k, v := range out.PinLsList.Keys {
445 if quiet {
446 fmt.Fprintf(w, "%s\n", k)
414 - } else {
447 + } else if v.Name == "" {
448 fmt.Fprintf(w, "%s %s\n", k, v.Type)
449 + } else {
450 + fmt.Fprintf(w, "%s %s %s\n", k, v.Type, v.Name)
451 }
452 }
453
@@ -437,11 +472,13 @@ type PinLsList struct {
472 // PinLsType contains the type of a pin
473 type PinLsType struct {
474 Type string
475 + Name string
476 }
477
478 // PinLsObject contains the description of a pin
479 type PinLsObject struct {
480 Cid string `json:",omitempty"`
481 + Name string `json:",omitempty"`
482 Type string `json:",omitempty"`
483 }
484
@@ -502,7 +539,7 @@ func pinLsKeys(req *cmds.Request, typeStr string, api coreiface.CoreAPI, emit fu
539 return nil
540 }
541
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 {
543 enc, err := cmdenv.GetCidEncoder(req)
544 if err != nil {
545 return err
@@ -520,7 +557,7 @@ func pinLsAll(req *cmds.Request, typeStr string, api coreiface.CoreAPI, emit fun
557 panic("unhandled pin type")
558 }
559
523 - pins, err := api.Pin().Ls(req.Context, opt)
560 + pins, err := api.Pin().Ls(req.Context, opt, options.Pin.Ls.Detailed(detailed))
561 if err != nil {
562 return err
563 }
@@ -532,6 +569,7 @@ func pinLsAll(req *cmds.Request, typeStr string, api coreiface.CoreAPI, emit fun
569 err = emit(PinLsOutputWrapper{
570 PinLsObject: PinLsObject{
571 Type: p.Type(),
572 + Name: p.Name(),
573 Cid: enc.Encode(p.Path().RootCid()),
574 },
575 })
@@ -748,15 +786,15 @@ func pinVerify(ctx context.Context, n *core.IpfsNode, opts pinVerifyOpts, enc ci
786 out := make(chan any)
787 go func() {
788 defer close(out)
751 - for p := range n.Pinning.RecursiveKeys(ctx) {
789 + for p := range n.Pinning.RecursiveKeys(ctx, false) {
790 if p.Err != nil {
791 out <- PinVerifyRes{Err: p.Err.Error()}
792 return
793 }
756 - pinStatus := checkPin(p.C)
794 + pinStatus := checkPin(p.Pin.Key)
795 if !pinStatus.Ok || opts.includeOk {
796 select {
759 - case out <- PinVerifyRes{Cid: enc.Encode(p.C), PinStatus: pinStatus}:
797 + case out <- PinVerifyRes{Cid: enc.Encode(p.Pin.Key), PinStatus: pinStatus}:
798 case <-ctx.Done():
799 return
800 }
core/coreapi/block.go
+1 -1
@@ -60,7 +60,7 @@ func (api *BlockAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.Bloc
60 }
61
62 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 {
64 return nil, err
65 }
66 if err := api.pinning.Flush(ctx); err != nil {
core/coreapi/dag.go
+2 -2
@@ -30,7 +30,7 @@ func (adder *pinningAdder) Add(ctx context.Context, nd ipld.Node) error {
30 return err
31 }
32
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 {
34 return err
35 }
36
@@ -51,7 +51,7 @@ func (adder *pinningAdder) AddMany(ctx context.Context, nds []ipld.Node) error {
51 for _, nd := range nds {
52 c := nd.Cid()
53 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 {
55 return err
56 }
57 }
core/coreapi/object.go
+1 -1
@@ -133,7 +133,7 @@ func (api *ObjectAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.Obj
133 }
134
135 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 {
137 return path.ImmutablePath{}, err
138 }
139
core/coreapi/pin.go
+23 -17
@@ -38,7 +38,7 @@ func (api *PinAPI) Add(ctx context.Context, p path.Path, opts ...caopts.PinAddOp
38
39 defer api.blockstore.PinLock(ctx).Unlock(ctx)
40
41 - err = api.pinning.Pin(ctx, dagNode, settings.Recursive)
41 + err = api.pinning.Pin(ctx, dagNode, settings.Recursive, settings.Name)
42 if err != nil {
43 return fmt.Errorf("pin: %s", err)
44 }
@@ -67,7 +67,7 @@ func (api *PinAPI) Ls(ctx context.Context, opts ...caopts.PinLsOption) (<-chan c
67 return nil, fmt.Errorf("invalid type '%s', must be one of {direct, indirect, recursive, all}", settings.Type)
68 }
69
70 - return api.pinLsAll(ctx, settings.Type), nil
70 + return api.pinLsAll(ctx, settings.Type, settings.Detailed), nil
71 }
72
73 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
231 out := make(chan coreiface.PinStatus)
232 go func() {
233 defer close(out)
234 - for p := range api.pinning.RecursiveKeys(ctx) {
234 + for p := range api.pinning.RecursiveKeys(ctx, false) {
235 var res *pinStatus
236 if p.Err != nil {
237 res = &pinStatus{err: p.Err}
238 } else {
239 - res = checkPin(p.C)
239 + res = checkPin(p.Pin.Key)
240 }
241 select {
242 case <-ctx.Done():
@@ -252,6 +252,7 @@ func (api *PinAPI) Verify(ctx context.Context) (<-chan coreiface.PinStatus, erro
252 type pinInfo struct {
253 pinType string
254 path path.ImmutablePath
255 + name string
256 err error
257 }
258
@@ -263,6 +264,10 @@ func (p *pinInfo) Type() string {
264 return p.pinType
265 }
266
267 +func (p *pinInfo) Name() string {
268 + return p.name
269 +}
270 +
271 func (p *pinInfo) Err() error {
272 return p.err
273 }
@@ -271,16 +276,17 @@ func (p *pinInfo) Err() error {
276 //
277 // The caller must keep reading results until the channel is closed to prevent
278 // 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 {
280 out := make(chan coreiface.Pin, 1)
281
282 emittedSet := cid.NewSet()
283
279 - AddToResultKeys := func(c cid.Cid, typeStr string) error {
284 + AddToResultKeys := func(c cid.Cid, name, typeStr string) error {
285 if emittedSet.Visit(c) {
286 select {
287 case out <- &pinInfo{
288 pinType: typeStr,
289 + name: name,
290 path: path.FromCid(c),
291 }:
292 case <-ctx.Done():
@@ -296,25 +302,25 @@ func (api *PinAPI) pinLsAll(ctx context.Context, typeStr string) <-chan coreifac
302 var rkeys []cid.Cid
303 var err error
304 if typeStr == "recursive" || typeStr == "all" {
299 - for streamedCid := range api.pinning.RecursiveKeys(ctx) {
305 + for streamedCid := range api.pinning.RecursiveKeys(ctx, detailed) {
306 if streamedCid.Err != nil {
307 out <- &pinInfo{err: streamedCid.Err}
308 return
309 }
304 - if err = AddToResultKeys(streamedCid.C, "recursive"); err != nil {
310 + if err = AddToResultKeys(streamedCid.Pin.Key, streamedCid.Pin.Name, "recursive"); err != nil {
311 out <- &pinInfo{err: err}
312 return
313 }
308 - rkeys = append(rkeys, streamedCid.C)
314 + rkeys = append(rkeys, streamedCid.Pin.Key)
315 }
316 }
317 if typeStr == "direct" || typeStr == "all" {
312 - for streamedCid := range api.pinning.DirectKeys(ctx) {
318 + for streamedCid := range api.pinning.DirectKeys(ctx, detailed) {
319 if streamedCid.Err != nil {
320 out <- &pinInfo{err: streamedCid.Err}
321 return
322 }
317 - if err = AddToResultKeys(streamedCid.C, "direct"); err != nil {
323 + if err = AddToResultKeys(streamedCid.Pin.Key, streamedCid.Pin.Name, "direct"); err != nil {
324 out <- &pinInfo{err: err}
325 return
326 }
@@ -324,21 +330,21 @@ func (api *PinAPI) pinLsAll(ctx context.Context, typeStr string) <-chan coreifac
330 // We need to first visit the direct pins that have priority
331 // without emitting them
332
327 - for streamedCid := range api.pinning.DirectKeys(ctx) {
333 + for streamedCid := range api.pinning.DirectKeys(ctx, detailed) {
334 if streamedCid.Err != nil {
335 out <- &pinInfo{err: streamedCid.Err}
336 return
337 }
332 - emittedSet.Add(streamedCid.C)
338 + emittedSet.Add(streamedCid.Pin.Key)
339 }
340
335 - for streamedCid := range api.pinning.RecursiveKeys(ctx) {
341 + for streamedCid := range api.pinning.RecursiveKeys(ctx, detailed) {
342 if streamedCid.Err != nil {
343 out <- &pinInfo{err: streamedCid.Err}
344 return
345 }
340 - emittedSet.Add(streamedCid.C)
341 - rkeys = append(rkeys, streamedCid.C)
346 + emittedSet.Add(streamedCid.Pin.Key)
347 + rkeys = append(rkeys, streamedCid.Pin.Key)
348 }
349 }
350 if typeStr == "indirect" || typeStr == "all" {
@@ -353,7 +359,7 @@ func (api *PinAPI) pinLsAll(ctx context.Context, typeStr string) <-chan coreifac
359 if emittedSet.Has(c) {
360 return true // skipped
361 }
356 - err := AddToResultKeys(c, "indirect")
362 + err := AddToResultKeys(c, "", "indirect")
363 if err != nil {
364 out <- &pinInfo{err: err}
365 return false
core/coreiface/options/pin.go
+20 -1
@@ -5,11 +5,13 @@ import "fmt"
5 // PinAddSettings represent the settings for PinAPI.Add
6 type PinAddSettings struct {
7 Recursive bool
8 + Name string
9 }
10
11 // PinLsSettings represent the settings for PinAPI.Ls
12 type PinLsSettings struct {
12 - Type string
13 + Type string
14 + Detailed bool
15 }
16
17 // PinIsPinnedSettings represent the settings for PinAPI.IsPinned
@@ -194,6 +196,15 @@ func (pinLsOpts) pinType(t string) PinLsOption {
196 }
197 }
198
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 +
208 type pinIsPinnedOpts struct{}
209
210 // 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 {
274 }
275 }
276
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 +
285 // RmRecursive is an option for Pin.Rm which specifies whether to recursively
286 // unpin the object linked to by the specified object(s). This does not remove
287 // indirect pins referenced by other recursive pins.
core/coreiface/pin.go
+3
@@ -13,6 +13,9 @@ type Pin interface {
13 // Path to the pinned object
14 Path() path.ImmutablePath
15
16 + // Name is the name of the pin.
17 + Name() string
18 +
19 // Type of the pin
20 Type() string
21
core/coreunix/add.go
+1 -1
@@ -186,7 +186,7 @@ func (adder *Adder) PinRoot(ctx context.Context, root ipld.Node) error {
186 adder.tempRoot = rnk
187 }
188
189 - err = adder.pinning.PinWithMode(ctx, rnk, pin.Recursive)
189 + err = adder.pinning.PinWithMode(ctx, rnk, pin.Recursive, "")
190 if err != nil {
191 return err
192 }
docs/changelogs/v0.26.md
+5
@@ -7,6 +7,7 @@
7 - [Overview](#overview)
8 - [🔦 Highlights](#-highlights)
9 - [Several deprecated commands have been removed](#several-deprecated-commands-have-been-removed)
10 + - [Support optional pin names](#support-optional-pin-names)
11 - [📝 Changelog](#-changelog)
12 - [👨‍👩‍👧‍👦 Contributors](#-contributors)
13
@@ -30,6 +31,10 @@ Several deprecated commands have been removed:
31 - `ipfs dns` deprecated in [April 2022, Kubo 0.13](https://github.com/ipfs/kubo/commit/76ae33a9f3f9abd166d1f6f23d6a8a0511510e3c), use `ipfs resolve /ipns/{name}` instead.
32 - `ipfs tar` deprecated [April 2022, Kubo 0.13](https://github.com/ipfs/kubo/pull/8849)
33
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 +
38 ### 📝 Changelog
39
40 - 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
@@ -7,7 +7,7 @@ go 1.20
7 replace github.com/ipfs/kubo => ./../../..
8
9 require (
10 - github.com/ipfs/boxo v0.16.0
10 + github.com/ipfs/boxo v0.16.1-0.20240104124825-38fb74f76b0d
11 github.com/ipfs/kubo v0.0.0-00010101000000-000000000000
12 github.com/libp2p/go-libp2p v0.32.2
13 github.com/multiformats/go-multiaddr v0.12.0
docs/examples/kubo-as-a-library/go.sum
+2 -2
@@ -303,8 +303,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c h1:7Uy
303 github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c/go.mod h1:6EekK/jo+TynwSE/ZOiOJd4eEvRXoavEC3vquKtv4yI=
304 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
305 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=
308 github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
309 github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
310 github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY=
fuse/ipns/common.go
+1 -1
@@ -18,7 +18,7 @@ func InitializeKeyspace(n *core.IpfsNode, key ci.PrivKey) error {
18
19 emptyDir := ft.EmptyDirNode()
20
21 - err := n.Pinning.Pin(ctx, emptyDir, false)
21 + err := n.Pinning.Pin(ctx, emptyDir, false, "")
22 if err != nil {
23 return err
24 }
gc/gc.go
+8 -8
@@ -154,7 +154,7 @@ func GC(ctx context.Context, bs bstore.GCBlockstore, dstor dstore.Datastore, pn
154 // Descendants recursively finds all the descendants of the given roots and
155 // adds them to the given cid.Set, using the provided dag.GetLinks function
156 // 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 {
158 verifyGetLinks := func(ctx context.Context, c cid.Cid) ([]*ipld.Link, error) {
159 err := verifcid.ValidateCid(verifcid.DefaultAllowlist, c)
160 if err != nil {
@@ -188,7 +188,7 @@ func Descendants(ctx context.Context, getLinks dag.GetLinks, set *cid.Set, roots
188 }
189
190 // 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 {
192 return set.Visit(toCidV1(k))
193 }, dag.Concurrent())
194 if err != nil {
@@ -226,7 +226,7 @@ func ColoredSet(ctx context.Context, pn pin.Pinner, ng ipld.NodeGetter, bestEffo
226 }
227 return links, nil
228 }
229 - rkeys := pn.RecursiveKeys(ctx)
229 + rkeys := pn.RecursiveKeys(ctx, false)
230 err := Descendants(ctx, getLinks, gcs, rkeys)
231 if err != nil {
232 errors = true
@@ -249,14 +249,14 @@ func ColoredSet(ctx context.Context, pn pin.Pinner, ng ipld.NodeGetter, bestEffo
249 }
250 return links, nil
251 }
252 - bestEffortRootsChan := make(chan pin.StreamedCid)
252 + bestEffortRootsChan := make(chan pin.StreamedPin)
253 go func() {
254 defer close(bestEffortRootsChan)
255 for _, root := range bestEffortRoots {
256 select {
257 case <-ctx.Done():
258 return
259 - case bestEffortRootsChan <- pin.StreamedCid{C: root}:
259 + case bestEffortRootsChan <- pin.StreamedPin{Pin: pin.Pinned{Key: root}}:
260 }
261 }
262 }()
@@ -270,15 +270,15 @@ func ColoredSet(ctx context.Context, pn pin.Pinner, ng ipld.NodeGetter, bestEffo
270 }
271 }
272
273 - dkeys := pn.DirectKeys(ctx)
273 + dkeys := pn.DirectKeys(ctx, false)
274 for k := range dkeys {
275 if k.Err != nil {
276 return nil, k.Err
277 }
278 - gcs.Add(toCidV1(k.C))
278 + gcs.Add(toCidV1(k.Pin.Key))
279 }
280
281 - ikeys := pn.InternalPins(ctx)
281 + ikeys := pn.InternalPins(ctx, false)
282 err = Descendants(ctx, getLinks, gcs, ikeys)
283 if err != nil {
284 errors = true
gc/gc_test.go
+2 -2
@@ -38,14 +38,14 @@ func TestGC(t *testing.T) {
38 // direct
39 root, _, err := daggen.MakeDagNode(dserv.Add, 0, 1)
40 require.NoError(t, err)
41 - err = pinner.PinWithMode(ctx, root, pin.Direct)
41 + err = pinner.PinWithMode(ctx, root, pin.Direct, "")
42 require.NoError(t, err)
43 expectedKept = append(expectedKept, root.Hash())
44
45 // recursive
46 root, allCids, err := daggen.MakeDagNode(dserv.Add, 5, 2)
47 require.NoError(t, err)
48 - err = pinner.PinWithMode(ctx, root, pin.Recursive)
48 + err = pinner.PinWithMode(ctx, root, pin.Recursive, "")
49 require.NoError(t, err)
50 expectedKept = append(expectedKept, toMHs(allCids)...)
51 }
go.mod
+1 -1
@@ -17,7 +17,7 @@ require (
17 github.com/hashicorp/go-multierror v1.1.1
18 github.com/ipfs-shipyard/nopfs v0.0.12-0.20231027223058-cde3b5ba964c
19 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
21 github.com/ipfs/go-block-format v0.2.0
22 github.com/ipfs/go-cid v0.4.1
23 github.com/ipfs/go-cidutil v0.1.0
go.sum
+2 -2
@@ -337,8 +337,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c h1:7Uy
337 github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c/go.mod h1:6EekK/jo+TynwSE/ZOiOJd4eEvRXoavEC3vquKtv4yI=
338 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
339 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=
342 github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
343 github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
344 github.com/ipfs/go-bitswap v0.11.0 h1:j1WVvhDX1yhG32NTC9xfxnqycqYIlhzEzLXG/cU1HyQ=
test/cli/pins_test.go
+63
@@ -209,4 +209,67 @@ func TestPins(t *testing.T) {
209 testPins(t, testPinsArgs{runDaemon: true, baseArg: "--cid-base=base32"})
210 testPins(t, testPinsArgs{runDaemon: true, lsArg: "--stream", baseArg: "--cid-base=base32"})
211 })
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 + })
275 }
test/dependencies/go.mod
+1 -1
@@ -103,7 +103,7 @@ require (
103 github.com/hexops/gotextdiff v1.0.3 // indirect
104 github.com/inconshreveable/mousetrap v1.1.0 // indirect
105 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
107 github.com/ipfs/go-block-format v0.2.0 // indirect
108 github.com/ipfs/go-cid v0.4.1 // indirect
109 github.com/ipfs/go-datastore v0.6.0 // indirect
test/dependencies/go.sum
+2 -2
@@ -342,8 +342,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
342 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
343 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
344 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=
347 github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs=
348 github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM=
349 github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s=