@@ -259,8 +259,9 @@ collected if needed. (By default, recursively. Use -r=false for direct pins.)
259
259
}
260
260
261
261
const (
262
- pinTypeOptionName = "type"
263
- pinQuietOptionName = "quiet"
262
+ pinTypeOptionName = "type"
263
+ pinQuietOptionName = "quiet"
264
+ pinStreamOptionName = "stream"
264
265
)
265
266
266
267
var listPinCmd = & cmds.Command {
@@ -313,6 +314,7 @@ Example:
313
314
Options : []cmds.Option {
314
315
cmds .StringOption (pinTypeOptionName , "t" , "The type of pinned keys to list. Can be \" direct\" , \" indirect\" , \" recursive\" , or \" all\" ." ).WithDefault ("all" ),
315
316
cmds .BoolOption (pinQuietOptionName , "q" , "Write just hashes of objects." ),
317
+ cmds .BoolOption (pinStreamOptionName , "s" , "Enable streaming of pins as they are discovered." ),
316
318
},
317
319
Run : func (req * cmds.Request , res cmds.ResponseEmitter , env cmds.Environment ) error {
318
320
n , err := cmdenv .GetNode (env )
@@ -326,9 +328,7 @@ Example:
326
328
}
327
329
328
330
typeStr , _ := req .Options [pinTypeOptionName ].(string )
329
- if err != nil {
330
- return err
331
- }
331
+ stream , _ := req .Options [pinStreamOptionName ].(bool )
332
332
333
333
switch typeStr {
334
334
case "all" , "direct" , "indirect" , "recursive" :
@@ -337,34 +337,50 @@ Example:
337
337
return err
338
338
}
339
339
340
- enc , err := cmdenv .GetCidEncoder (req )
341
- if err != nil {
342
- return err
340
+ // For backward compatibility, we accumulate the pins in the same output type as before.
341
+ emit := res .Emit
342
+ lgcList := map [string ]PinLsType {}
343
+ if ! stream {
344
+ emit = func (v interface {}) error {
345
+ obj := v .(* PinLsOutputWrapper )
346
+ lgcList [obj .PinLsObject .Cid ] = PinLsType {Type : obj .PinLsObject .Type }
347
+ return nil
348
+ }
343
349
}
344
350
345
- var keys map [cid.Cid ]RefKeyObject
346
351
if len (req .Arguments ) > 0 {
347
- keys , err = pinLsKeys (req . Context , req . Arguments , typeStr , n , api )
352
+ err = pinLsKeys (req , typeStr , n , api , emit )
348
353
} else {
349
- keys , err = pinLsAll (req . Context , typeStr , n )
354
+ err = pinLsAll (req , typeStr , n , emit )
350
355
}
351
356
if err != nil {
352
357
return err
353
358
}
354
359
355
- refKeys := make (map [string ]RefKeyObject , len (keys ))
356
- for k , v := range keys {
357
- refKeys [enc .Encode (k )] = v
360
+ if ! stream {
361
+ return cmds .EmitOnce (res , & PinLsOutputWrapper {
362
+ PinLsList : PinLsList {Keys : lgcList },
363
+ })
358
364
}
359
365
360
- return cmds . EmitOnce ( res , & RefKeyList { Keys : refKeys })
366
+ return nil
361
367
},
362
- Type : RefKeyList {},
368
+ Type : & PinLsOutputWrapper {},
363
369
Encoders : cmds.EncoderMap {
364
- cmds .Text : cmds .MakeTypedEncoder (func (req * cmds.Request , w io.Writer , out * RefKeyList ) error {
370
+ cmds .Text : cmds .MakeTypedEncoder (func (req * cmds.Request , w io.Writer , out * PinLsOutputWrapper ) error {
365
371
quiet , _ := req .Options [pinQuietOptionName ].(bool )
372
+ stream , _ := req .Options [pinStreamOptionName ].(bool )
373
+
374
+ if stream {
375
+ if quiet {
376
+ fmt .Fprintf (w , "%s\n " , out .PinLsObject .Cid )
377
+ } else {
378
+ fmt .Fprintf (w , "%s %s\n " , out .PinLsObject .Cid , out .PinLsObject .Type )
379
+ }
380
+ return nil
381
+ }
366
382
367
- for k , v := range out .Keys {
383
+ for k , v := range out .PinLsList . Keys {
368
384
if quiet {
369
385
fmt .Fprintf (w , "%s\n " , k )
370
386
} else {
@@ -377,6 +393,144 @@ Example:
377
393
},
378
394
}
379
395
396
+ // PinLsOutputWrapper is the output type of the pin ls command.
397
+ // Pin ls needs to output two different type depending on if it's streamed or not.
398
+ // We use this to bypass the cmds lib refusing to have interface{}
399
+ type PinLsOutputWrapper struct {
400
+ PinLsList
401
+ PinLsObject
402
+ }
403
+
404
+ // PinLsList is a set of pins with their type
405
+ type PinLsList struct {
406
+ Keys map [string ]PinLsType `json:",omitempty"`
407
+ }
408
+
409
+ // PinLsType contains the type of a pin
410
+ type PinLsType struct {
411
+ Type string
412
+ }
413
+
414
+ // PinLsObject contains the description of a pin
415
+ type PinLsObject struct {
416
+ Cid string `json:",omitempty"`
417
+ Type string `json:",omitempty"`
418
+ }
419
+
420
+ func pinLsKeys (req * cmds.Request , typeStr string , n * core.IpfsNode , api coreiface.CoreAPI , emit func (value interface {}) error ) error {
421
+ mode , ok := pin .StringToMode (typeStr )
422
+ if ! ok {
423
+ return fmt .Errorf ("invalid pin mode '%s'" , typeStr )
424
+ }
425
+
426
+ enc , err := cmdenv .GetCidEncoder (req )
427
+ if err != nil {
428
+ return err
429
+ }
430
+
431
+ for _ , p := range req .Arguments {
432
+ c , err := api .ResolvePath (req .Context , path .New (p ))
433
+ if err != nil {
434
+ return err
435
+ }
436
+
437
+ pinType , pinned , err := n .Pinning .IsPinnedWithType (c .Cid (), mode )
438
+ if err != nil {
439
+ return err
440
+ }
441
+
442
+ if ! pinned {
443
+ return fmt .Errorf ("path '%s' is not pinned" , p )
444
+ }
445
+
446
+ switch pinType {
447
+ case "direct" , "indirect" , "recursive" , "internal" :
448
+ default :
449
+ pinType = "indirect through " + pinType
450
+ }
451
+
452
+ err = emit (& PinLsOutputWrapper {
453
+ PinLsObject : PinLsObject {
454
+ Type : pinType ,
455
+ Cid : enc .Encode (c .Cid ()),
456
+ },
457
+ })
458
+ if err != nil {
459
+ return err
460
+ }
461
+ }
462
+
463
+ return nil
464
+ }
465
+
466
+ func pinLsAll (req * cmds.Request , typeStr string , n * core.IpfsNode , emit func (value interface {}) error ) error {
467
+ enc , err := cmdenv .GetCidEncoder (req )
468
+ if err != nil {
469
+ return err
470
+ }
471
+
472
+ keys := cid .NewSet ()
473
+
474
+ AddToResultKeys := func (keyList []cid.Cid , typeStr string ) error {
475
+ for _ , c := range keyList {
476
+ if keys .Visit (c ) {
477
+ err := emit (& PinLsOutputWrapper {
478
+ PinLsObject : PinLsObject {
479
+ Type : typeStr ,
480
+ Cid : enc .Encode (c ),
481
+ },
482
+ })
483
+ if err != nil {
484
+ return err
485
+ }
486
+ }
487
+ }
488
+ return nil
489
+ }
490
+
491
+ if typeStr == "direct" || typeStr == "all" {
492
+ err := AddToResultKeys (n .Pinning .DirectKeys (), "direct" )
493
+ if err != nil {
494
+ return err
495
+ }
496
+ }
497
+ if typeStr == "recursive" || typeStr == "all" {
498
+ err := AddToResultKeys (n .Pinning .RecursiveKeys (), "recursive" )
499
+ if err != nil {
500
+ return err
501
+ }
502
+ }
503
+ if typeStr == "indirect" || typeStr == "all" {
504
+ for _ , k := range n .Pinning .RecursiveKeys () {
505
+ var visitErr error
506
+ err := dag .EnumerateChildren (req .Context , dag .GetLinksWithDAG (n .DAG ), k , func (c cid.Cid ) bool {
507
+ r := keys .Visit (c )
508
+ if r {
509
+ err := emit (& PinLsOutputWrapper {
510
+ PinLsObject : PinLsObject {
511
+ Type : "indirect" ,
512
+ Cid : enc .Encode (c ),
513
+ },
514
+ })
515
+ if err != nil {
516
+ visitErr = err
517
+ }
518
+ }
519
+ return r
520
+ })
521
+
522
+ if visitErr != nil {
523
+ return visitErr
524
+ }
525
+ if err != nil {
526
+ return err
527
+ }
528
+ }
529
+ }
530
+
531
+ return nil
532
+ }
533
+
380
534
const (
381
535
pinUnpinOptionName = "unpin"
382
536
)
@@ -491,83 +645,6 @@ var verifyPinCmd = &cmds.Command{
491
645
},
492
646
}
493
647
494
- type RefKeyObject struct {
495
- Type string
496
- }
497
-
498
- type RefKeyList struct {
499
- Keys map [string ]RefKeyObject
500
- }
501
-
502
- func pinLsKeys (ctx context.Context , args []string , typeStr string , n * core.IpfsNode , api coreiface.CoreAPI ) (map [cid.Cid ]RefKeyObject , error ) {
503
-
504
- mode , ok := pin .StringToMode (typeStr )
505
- if ! ok {
506
- return nil , fmt .Errorf ("invalid pin mode '%s'" , typeStr )
507
- }
508
-
509
- keys := make (map [cid.Cid ]RefKeyObject )
510
-
511
- for _ , p := range args {
512
- c , err := api .ResolvePath (ctx , path .New (p ))
513
- if err != nil {
514
- return nil , err
515
- }
516
-
517
- pinType , pinned , err := n .Pinning .IsPinnedWithType (c .Cid (), mode )
518
- if err != nil {
519
- return nil , err
520
- }
521
-
522
- if ! pinned {
523
- return nil , fmt .Errorf ("path '%s' is not pinned" , p )
524
- }
525
-
526
- switch pinType {
527
- case "direct" , "indirect" , "recursive" , "internal" :
528
- default :
529
- pinType = "indirect through " + pinType
530
- }
531
- keys [c .Cid ()] = RefKeyObject {
532
- Type : pinType ,
533
- }
534
- }
535
-
536
- return keys , nil
537
- }
538
-
539
- func pinLsAll (ctx context.Context , typeStr string , n * core.IpfsNode ) (map [cid.Cid ]RefKeyObject , error ) {
540
-
541
- keys := make (map [cid.Cid ]RefKeyObject )
542
-
543
- AddToResultKeys := func (keyList []cid.Cid , typeStr string ) {
544
- for _ , c := range keyList {
545
- keys [c ] = RefKeyObject {
546
- Type : typeStr ,
547
- }
548
- }
549
- }
550
-
551
- if typeStr == "direct" || typeStr == "all" {
552
- AddToResultKeys (n .Pinning .DirectKeys (), "direct" )
553
- }
554
- if typeStr == "indirect" || typeStr == "all" {
555
- set := cid .NewSet ()
556
- for _ , k := range n .Pinning .RecursiveKeys () {
557
- err := dag .EnumerateChildren (ctx , dag .GetLinksWithDAG (n .DAG ), k , set .Visit )
558
- if err != nil {
559
- return nil , err
560
- }
561
- }
562
- AddToResultKeys (set .Keys (), "indirect" )
563
- }
564
- if typeStr == "recursive" || typeStr == "all" {
565
- AddToResultKeys (n .Pinning .RecursiveKeys (), "recursive" )
566
- }
567
-
568
- return keys , nil
569
- }
570
-
571
648
// PinVerifyRes is the result returned for each pin checked in "pin verify"
572
649
type PinVerifyRes struct {
573
650
Cid string
0 commit comments