@cryptotaxi247 / kubo / commits / b52034068

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