pin: add a IsPinned method
This commit was moved from ipfs/interface-go-ipfs-core@c82db2ef2270a228185aaba6b08ecd7157a7ebee This commit was moved from ipfs/boxo@e84cc0569818ce3b28ff7ea27b5077fe17232163
Michael Muré committed
Nov 29, 2019 at 22:33 UTC
b52034068c6f306f3d111b3dfce9427535127e2f
3 files changed
+237
-46
core/coreiface/options/pin.go
+147
-37
@@ -1,13 +1,23 @@
1
package options
2
3
+import "fmt"
4
+
5
type PinAddSettings struct {
6
Recursive bool
7
}
8
9
+type TypeSettings struct {
10
+ Type string
11
+}
12
+
13
type PinLsSettings struct {
14
Type string
15
}
16
17
+type PinIsPinnedSettings struct {
18
+ WithType string
19
+}
20
+
21
// PinRmSettings represents the settings of pin rm command
22
type PinRmSettings struct {
23
Recursive bool
@@ -17,13 +27,19 @@ type PinUpdateSettings struct {
27
Unpin bool
28
}
29
30
+// PinAddOption pin add option func
31
type PinAddOption func(*PinAddSettings) error
32
33
+// PinLsOption pin ls option func
34
+type PinLsOption func(*PinLsSettings) error
35
+
36
+// PinIsPinnedOption pin isPinned option func
37
+type PinIsPinnedOption func(*PinIsPinnedSettings) error
38
+
39
// PinRmOption pin rm option func
40
type PinRmOption func(*PinRmSettings) error
41
25
-// PinLsOption pin ls option func
26
-type PinLsOption func(*PinLsSettings) error
42
+// PinUpdateOption pin update option func
43
type PinUpdateOption func(*PinUpdateSettings) error
44
45
func PinAddOptions(opts ...PinAddOption) (*PinAddSettings, error) {
@@ -41,14 +57,14 @@ func PinAddOptions(opts ...PinAddOption) (*PinAddSettings, error) {
57
return options, nil
58
}
59
44
-// PinRmOptions pin rm options
45
-func PinRmOptions(opts ...PinRmOption) (*PinRmSettings, error) {
46
- options := &PinRmSettings{
47
- Recursive: true,
60
+func PinLsOptions(opts ...PinLsOption) (*PinLsSettings, error) {
61
+ options := &PinLsSettings{
62
+ Type: "all",
63
}
64
65
for _, opt := range opts {
51
- if err := opt(options); err != nil {
66
+ err := opt(options)
67
+ if err != nil {
68
return nil, err
69
}
70
}
@@ -56,9 +72,9 @@ func PinRmOptions(opts ...PinRmOption) (*PinRmSettings, error) {
72
return options, nil
73
}
74
59
-func PinLsOptions(opts ...PinLsOption) (*PinLsSettings, error) {
60
- options := &PinLsSettings{
61
- Type: "all",
75
+func PinIsPinnedOptions(opts ...PinIsPinnedOption) (*PinIsPinnedSettings, error) {
76
+ options := &PinIsPinnedSettings{
77
+ WithType: "all",
78
}
79
80
for _, opt := range opts {
@@ -71,6 +87,21 @@ func PinLsOptions(opts ...PinLsOption) (*PinLsSettings, error) {
87
return options, nil
88
}
89
90
+// PinRmOptions pin rm options
91
+func PinRmOptions(opts ...PinRmOption) (*PinRmSettings, error) {
92
+ options := &PinRmSettings{
93
+ Recursive: true,
94
+ }
95
+
96
+ for _, opt := range opts {
97
+ if err := opt(options); err != nil {
98
+ return nil, err
99
+ }
100
+ }
101
+
102
+ return options, nil
103
+}
104
+
105
func PinUpdateOptions(opts ...PinUpdateOption) (*PinUpdateSettings, error) {
106
options := &PinUpdateSettings{
107
Unpin: true,
@@ -86,36 +117,131 @@ func PinUpdateOptions(opts ...PinUpdateOption) (*PinUpdateSettings, error) {
117
return options, nil
118
}
119
89
-type pinType struct{}
90
-
120
type pinOpts struct {
92
- Type pinType
121
+ Ls pinLsOpts
122
+ IsPinned pinIsPinnedOpts
123
}
124
125
var Pin pinOpts
126
127
+type pinLsOpts struct{}
128
+
129
// All is an option for Pin.Ls which will make it return all pins. It is
130
// the default
99
-func (pinType) All() PinLsOption {
100
- return Pin.pinType("all")
131
+func (pinLsOpts) All() PinLsOption {
132
+ return Pin.Ls.pinType("all")
133
}
134
135
// Recursive is an option for Pin.Ls which will make it only return recursive
136
// pins
105
-func (pinType) Recursive() PinLsOption {
106
- return Pin.pinType("recursive")
137
+func (pinLsOpts) Recursive() PinLsOption {
138
+ return Pin.Ls.pinType("recursive")
139
}
140
141
// Direct is an option for Pin.Ls which will make it only return direct (non
142
// recursive) pins
111
-func (pinType) Direct() PinLsOption {
112
- return Pin.pinType("direct")
143
+func (pinLsOpts) Direct() PinLsOption {
144
+ return Pin.Ls.pinType("direct")
145
}
146
147
// Indirect is an option for Pin.Ls which will make it only return indirect pins
148
// (objects referenced by other recursively pinned objects)
117
-func (pinType) Indirect() PinLsOption {
118
- return Pin.pinType("indirect")
149
+func (pinLsOpts) Indirect() PinLsOption {
150
+ return Pin.Ls.pinType("indirect")
151
+}
152
+
153
+// Type is an option for Pin.Ls which will make it only return pins of the given
154
+// type.
155
+//
156
+// Supported values:
157
+// * "direct" - directly pinned objects
158
+// * "recursive" - roots of recursive pins
159
+// * "indirect" - indirectly pinned objects (referenced by recursively pinned
160
+// objects)
161
+// * "all" - all pinned objects (default)
162
+func (pinLsOpts) Type(typeStr string) (PinLsOption, error) {
163
+ switch typeStr {
164
+ case "all", "direct", "indirect", "recursive":
165
+ return Pin.Ls.pinType(typeStr), nil
166
+ default:
167
+ return nil, fmt.Errorf("invalid type '%s', must be one of {direct, indirect, recursive, all}", typeStr)
168
+ }
169
+}
170
+
171
+// pinType is an option for Pin.Ls which allows to specify which pin types should
172
+// be returned
173
+//
174
+// Supported values:
175
+// * "direct" - directly pinned objects
176
+// * "recursive" - roots of recursive pins
177
+// * "indirect" - indirectly pinned objects (referenced by recursively pinned
178
+// objects)
179
+// * "all" - all pinned objects (default)
180
+func (pinLsOpts) pinType(t string) PinLsOption {
181
+ return func(settings *PinLsSettings) error {
182
+ settings.Type = t
183
+ return nil
184
+ }
185
+}
186
+
187
+type pinIsPinnedOpts struct{}
188
+
189
+// All is an option for Pin.IsPinned which will make it search in all type of pins.
190
+// It is the default
191
+func (pinIsPinnedOpts) All() PinIsPinnedOption {
192
+ return Pin.IsPinned.pinType("all")
193
+}
194
+
195
+// Recursive is an option for Pin.IsPinned which will make it only search in
196
+// recursive pins
197
+func (pinIsPinnedOpts) Recursive() PinIsPinnedOption {
198
+ return Pin.IsPinned.pinType("recursive")
199
+}
200
+
201
+// Direct is an option for Pin.IsPinned which will make it only search in direct
202
+// (non recursive) pins
203
+func (pinIsPinnedOpts) Direct() PinIsPinnedOption {
204
+ return Pin.IsPinned.pinType("direct")
205
+}
206
+
207
+// Indirect is an option for Pin.IsPinned which will make it only search indirect
208
+// pins (objects referenced by other recursively pinned objects)
209
+func (pinIsPinnedOpts) Indirect() PinIsPinnedOption {
210
+ return Pin.IsPinned.pinType("indirect")
211
+}
212
+
213
+// Type is an option for Pin.IsPinned which will make it only search pins of the given
214
+// type.
215
+//
216
+// Supported values:
217
+// * "direct" - directly pinned objects
218
+// * "recursive" - roots of recursive pins
219
+// * "indirect" - indirectly pinned objects (referenced by recursively pinned
220
+// objects)
221
+// * "all" - all pinned objects (default)
222
+func (pinIsPinnedOpts) Type(typeStr string) (PinIsPinnedOption, error) {
223
+ switch typeStr {
224
+ case "all", "direct", "indirect", "recursive":
225
+ return Pin.IsPinned.pinType(typeStr), nil
226
+ default:
227
+ return nil, fmt.Errorf("invalid type '%s', must be one of {direct, indirect, recursive, all}", typeStr)
228
+ }
229
+}
230
+
231
+// pinType is an option for Pin.IsPinned which allows to specify which pin type the given
232
+// pin is expected to be, speeding up the research.
233
+//
234
+// Supported values:
235
+// * "direct" - directly pinned objects
236
+// * "recursive" - roots of recursive pins
237
+// * "indirect" - indirectly pinned objects (referenced by recursively pinned
238
+// objects)
239
+// * "all" - all pinned objects (default)
240
+func (pinIsPinnedOpts) pinType(t string) PinIsPinnedOption {
241
+ return func(settings *PinIsPinnedSettings) error {
242
+ settings.WithType = t
243
+ return nil
244
+ }
245
}
246
247
// Recursive is an option for Pin.Add which specifies whether to pin an entire
@@ -137,22 +263,6 @@ func (pinOpts) RmRecursive(recursive bool) PinRmOption {
263
}
264
}
265
140
-// Type is an option for Pin.Ls which allows to specify which pin types should
141
-// be returned
142
-//
143
-// Supported values:
144
-// * "direct" - directly pinned objects
145
-// * "recursive" - roots of recursive pins
146
-// * "indirect" - indirectly pinned objects (referenced by recursively pinned
147
-// objects)
148
-// * "all" - all pinned objects (default)
149
-func (pinOpts) pinType(t string) PinLsOption {
150
- return func(settings *PinLsSettings) error {
151
- settings.Type = t
152
- return nil
153
- }
154
-}
155
-
266
// Unpin is an option for Pin.Update which specifies whether to remove the old pin.
267
// Default is true.
268
func (pinOpts) Unpin(unpin bool) PinUpdateOption {
core/coreiface/pin.go
+4
@@ -46,6 +46,10 @@ type PinAPI interface {
46
// Ls returns list of pinned objects on this node
47
Ls(context.Context, ...options.PinLsOption) (<-chan Pin, error)
48
49
+ // IsPinned returns whether or not the given cid is pinned
50
+ // and an explanation of why its pinned
51
+ IsPinned(context.Context, path.Path, ...options.PinIsPinnedOption) (string, bool, error)
52
+
53
// Rm removes pin for object specified by the path
54
Rm(context.Context, path.Path, ...options.PinRmOption) error
55
core/coreiface/tests/pin.go
+86
-9
@@ -28,6 +28,7 @@ func (tp *TestSuite) TestPin(t *testing.T) {
28
t.Run("TestPinRecursive", tp.TestPinRecursive)
29
t.Run("TestPinLsIndirect", tp.TestPinLsIndirect)
30
t.Run("TestPinLsPrecedence", tp.TestPinLsPrecedence)
31
+ t.Run("TestPinIsPinned", tp.TestPinIsPinned)
32
}
33
34
func (tp *TestSuite) TestPinAdd(t *testing.T) {
@@ -84,6 +85,8 @@ func (tp *TestSuite) TestPinSimple(t *testing.T) {
85
t.Error("unexpected pin type")
86
}
87
88
+ assertIsPinned(t, ctx, api, p, "recursive")
89
+
90
err = api.Pin().Rm(ctx, p)
91
if err != nil {
92
t.Fatal(err)
@@ -150,7 +153,7 @@ func (tp *TestSuite) TestPinRecursive(t *testing.T) {
153
t.Errorf("unexpected pin list len: %d", len(list))
154
}
155
153
- list, err = accPins(api.Pin().Ls(ctx, opt.Pin.Type.Direct()))
156
+ list, err = accPins(api.Pin().Ls(ctx, opt.Pin.Ls.Direct()))
157
if err != nil {
158
t.Fatal(err)
159
}
@@ -163,7 +166,7 @@ func (tp *TestSuite) TestPinRecursive(t *testing.T) {
166
t.Errorf("unexpected path, %s != %s", list[0].Path().String(), path.IpfsPath(nd3.Cid()).String())
167
}
168
166
- list, err = accPins(api.Pin().Ls(ctx, opt.Pin.Type.Recursive()))
169
+ list, err = accPins(api.Pin().Ls(ctx, opt.Pin.Ls.Recursive()))
170
if err != nil {
171
t.Fatal(err)
172
}
@@ -176,7 +179,7 @@ func (tp *TestSuite) TestPinRecursive(t *testing.T) {
179
t.Errorf("unexpected path, %s != %s", list[0].Path().String(), path.IpldPath(nd2.Cid()).String())
180
}
181
179
- list, err = accPins(api.Pin().Ls(ctx, opt.Pin.Type.Indirect()))
182
+ list, err = accPins(api.Pin().Ls(ctx, opt.Pin.Ls.Indirect()))
183
if err != nil {
184
t.Fatal(err)
185
}
@@ -360,6 +363,39 @@ func (tp *TestSuite) TestPinLsPrecedenceRecursiveDirect(t *testing.T) {
363
assertPinTypes(t, ctx, api, []cidContainer{grandparent, parent}, []cidContainer{}, []cidContainer{leaf})
364
}
365
366
+func (tp *TestSuite) TestPinIsPinned(t *testing.T) {
367
+ ctx, cancel := context.WithCancel(context.Background())
368
+ defer cancel()
369
+ api, err := tp.makeAPI(ctx)
370
+ if err != nil {
371
+ t.Fatal(err)
372
+ }
373
+
374
+ leaf, parent, grandparent := getThreeChainedNodes(t, ctx, api, "foofoo")
375
+
376
+ assertNotPinned(t, ctx, api, path.IpldPath(grandparent.Cid()))
377
+ assertNotPinned(t, ctx, api, path.IpldPath(parent.Cid()))
378
+ assertNotPinned(t, ctx, api, path.IpldPath(leaf.Cid()))
379
+
380
+ err = api.Pin().Add(ctx, path.IpldPath(parent.Cid()), opt.Pin.Recursive(true))
381
+ if err != nil {
382
+ t.Fatal(err)
383
+ }
384
+
385
+ assertNotPinned(t, ctx, api, path.IpldPath(grandparent.Cid()))
386
+ assertIsPinned(t, ctx, api, path.IpldPath(parent.Cid()), "recursive")
387
+ assertIsPinned(t, ctx, api, path.IpldPath(leaf.Cid()), "indirect")
388
+
389
+ err = api.Pin().Add(ctx, path.IpldPath(grandparent.Cid()), opt.Pin.Recursive(false))
390
+ if err != nil {
391
+ t.Fatal(err)
392
+ }
393
+
394
+ assertIsPinned(t, ctx, api, path.IpldPath(grandparent.Cid()), "direct")
395
+ assertIsPinned(t, ctx, api, path.IpldPath(parent.Cid()), "recursive")
396
+ assertIsPinned(t, ctx, api, path.IpldPath(leaf.Cid()), "indirect")
397
+}
398
+
399
type cidContainer interface {
400
Cid() cid.Cid
401
}
@@ -390,21 +426,21 @@ func getThreeChainedNodes(t *testing.T, ctx context.Context, api iface.CoreAPI,
426
func assertPinTypes(t *testing.T, ctx context.Context, api iface.CoreAPI, recusive, direct, indirect []cidContainer) {
427
assertPinLsAllConsistency(t, ctx, api)
428
393
- list, err := accPins(api.Pin().Ls(ctx, opt.Pin.Type.Recursive()))
429
+ list, err := accPins(api.Pin().Ls(ctx, opt.Pin.Ls.Recursive()))
430
if err != nil {
431
t.Fatal(err)
432
}
433
434
assertPinCids(t, list, recusive...)
435
400
- list, err = accPins(api.Pin().Ls(ctx, opt.Pin.Type.Direct()))
436
+ list, err = accPins(api.Pin().Ls(ctx, opt.Pin.Ls.Direct()))
437
if err != nil {
438
t.Fatal(err)
439
}
440
441
assertPinCids(t, list, direct...)
442
407
- list, err = accPins(api.Pin().Ls(ctx, opt.Pin.Type.Indirect()))
443
+ list, err = accPins(api.Pin().Ls(ctx, opt.Pin.Ls.Indirect()))
444
if err != nil {
445
t.Fatal(err)
446
}
@@ -466,9 +502,9 @@ func assertPinLsAllConsistency(t *testing.T, ctx context.Context, api iface.Core
502
503
all, recursive, direct, indirect := cid.NewSet(), cid.NewSet(), cid.NewSet(), cid.NewSet()
504
typeMap := map[string]*pinTypeProps{
469
- "recursive": {recursive, opt.Pin.Type.Recursive()},
470
- "direct": {direct, opt.Pin.Type.Direct()},
471
- "indirect": {indirect, opt.Pin.Type.Indirect()},
505
+ "recursive": {recursive, opt.Pin.Ls.Recursive()},
506
+ "direct": {direct, opt.Pin.Ls.Direct()},
507
+ "indirect": {indirect, opt.Pin.Ls.Indirect()},
508
}
509
510
for _, p := range allPins {
@@ -506,6 +542,47 @@ func assertPinLsAllConsistency(t *testing.T, ctx context.Context, api iface.Core
542
}
543
}
544
545
+func assertIsPinned(t *testing.T, ctx context.Context, api iface.CoreAPI, p path.Path, typeStr string) {
546
+ t.Helper()
547
+ withType, err := opt.Pin.IsPinned.Type(typeStr)
548
+ if err != nil {
549
+ panic("unhandled pin type")
550
+ }
551
+
552
+ whyPinned, pinned, err := api.Pin().IsPinned(ctx, p, withType)
553
+ if err != nil {
554
+ t.Fatal(err)
555
+ }
556
+
557
+ if !pinned {
558
+ t.Fatalf("%s expected to be pinned with type %s", p, typeStr)
559
+ }
560
+
561
+ switch typeStr {
562
+ case "recursive", "direct":
563
+ if typeStr != whyPinned {
564
+ t.Fatalf("reason for pinning expected to be %s for %s, got %s", typeStr, p, whyPinned)
565
+ }
566
+ case "indirect":
567
+ if whyPinned == "" {
568
+ t.Fatalf("expected to have a pin reason for %s", p)
569
+ }
570
+ }
571
+}
572
+
573
+func assertNotPinned(t *testing.T, ctx context.Context, api iface.CoreAPI, p path.Path) {
574
+ t.Helper()
575
+
576
+ _, pinned, err := api.Pin().IsPinned(ctx, p)
577
+ if err != nil {
578
+ t.Fatal(err)
579
+ }
580
+
581
+ if pinned {
582
+ t.Fatalf("%s expected to not be pinned", p)
583
+ }
584
+}
585
+
586
func accPins(pins <-chan iface.Pin, err error) ([]iface.Pin, error) {
587
if err != nil {
588
return nil, err