pin: add a IsPinned method

parent 292d906e
package options package options
import "fmt"
type PinAddSettings struct { type PinAddSettings struct {
Recursive bool Recursive bool
} }
type TypeSettings struct {
Type string
}
type PinLsSettings struct { type PinLsSettings struct {
Type string Type string
} }
type PinIsPinnedSettings struct {
WithType string
}
// PinRmSettings represents the settings of pin rm command // PinRmSettings represents the settings of pin rm command
type PinRmSettings struct { type PinRmSettings struct {
Recursive bool Recursive bool
...@@ -17,13 +27,19 @@ type PinUpdateSettings struct { ...@@ -17,13 +27,19 @@ type PinUpdateSettings struct {
Unpin bool Unpin bool
} }
// PinAddOption pin add option func
type PinAddOption func(*PinAddSettings) error type PinAddOption func(*PinAddSettings) error
// PinLsOption pin ls option func
type PinLsOption func(*PinLsSettings) error
// PinIsPinnedOption pin isPinned option func
type PinIsPinnedOption func(*PinIsPinnedSettings) error
// PinRmOption pin rm option func // PinRmOption pin rm option func
type PinRmOption func(*PinRmSettings) error type PinRmOption func(*PinRmSettings) error
// PinLsOption pin ls option func // PinUpdateOption pin update option func
type PinLsOption func(*PinLsSettings) error
type PinUpdateOption func(*PinUpdateSettings) error type PinUpdateOption func(*PinUpdateSettings) error
func PinAddOptions(opts ...PinAddOption) (*PinAddSettings, error) { func PinAddOptions(opts ...PinAddOption) (*PinAddSettings, error) {
...@@ -41,14 +57,14 @@ func PinAddOptions(opts ...PinAddOption) (*PinAddSettings, error) { ...@@ -41,14 +57,14 @@ func PinAddOptions(opts ...PinAddOption) (*PinAddSettings, error) {
return options, nil return options, nil
} }
// PinRmOptions pin rm options func PinLsOptions(opts ...PinLsOption) (*PinLsSettings, error) {
func PinRmOptions(opts ...PinRmOption) (*PinRmSettings, error) { options := &PinLsSettings{
options := &PinRmSettings{ Type: "all",
Recursive: true,
} }
for _, opt := range opts { for _, opt := range opts {
if err := opt(options); err != nil { err := opt(options)
if err != nil {
return nil, err return nil, err
} }
} }
...@@ -56,9 +72,9 @@ func PinRmOptions(opts ...PinRmOption) (*PinRmSettings, error) { ...@@ -56,9 +72,9 @@ func PinRmOptions(opts ...PinRmOption) (*PinRmSettings, error) {
return options, nil return options, nil
} }
func PinLsOptions(opts ...PinLsOption) (*PinLsSettings, error) { func PinIsPinnedOptions(opts ...PinIsPinnedOption) (*PinIsPinnedSettings, error) {
options := &PinLsSettings{ options := &PinIsPinnedSettings{
Type: "all", WithType: "all",
} }
for _, opt := range opts { for _, opt := range opts {
...@@ -71,6 +87,21 @@ func PinLsOptions(opts ...PinLsOption) (*PinLsSettings, error) { ...@@ -71,6 +87,21 @@ func PinLsOptions(opts ...PinLsOption) (*PinLsSettings, error) {
return options, nil return options, nil
} }
// PinRmOptions pin rm options
func PinRmOptions(opts ...PinRmOption) (*PinRmSettings, error) {
options := &PinRmSettings{
Recursive: true,
}
for _, opt := range opts {
if err := opt(options); err != nil {
return nil, err
}
}
return options, nil
}
func PinUpdateOptions(opts ...PinUpdateOption) (*PinUpdateSettings, error) { func PinUpdateOptions(opts ...PinUpdateOption) (*PinUpdateSettings, error) {
options := &PinUpdateSettings{ options := &PinUpdateSettings{
Unpin: true, Unpin: true,
...@@ -86,36 +117,131 @@ func PinUpdateOptions(opts ...PinUpdateOption) (*PinUpdateSettings, error) { ...@@ -86,36 +117,131 @@ func PinUpdateOptions(opts ...PinUpdateOption) (*PinUpdateSettings, error) {
return options, nil return options, nil
} }
type pinType struct{}
type pinOpts struct { type pinOpts struct {
Type pinType Ls pinLsOpts
IsPinned pinIsPinnedOpts
} }
var Pin pinOpts var Pin pinOpts
type pinLsOpts struct{}
// All is an option for Pin.Ls which will make it return all pins. It is // All is an option for Pin.Ls which will make it return all pins. It is
// the default // the default
func (pinType) All() PinLsOption { func (pinLsOpts) All() PinLsOption {
return Pin.pinType("all") return Pin.Ls.pinType("all")
} }
// Recursive is an option for Pin.Ls which will make it only return recursive // Recursive is an option for Pin.Ls which will make it only return recursive
// pins // pins
func (pinType) Recursive() PinLsOption { func (pinLsOpts) Recursive() PinLsOption {
return Pin.pinType("recursive") return Pin.Ls.pinType("recursive")
} }
// Direct is an option for Pin.Ls which will make it only return direct (non // Direct is an option for Pin.Ls which will make it only return direct (non
// recursive) pins // recursive) pins
func (pinType) Direct() PinLsOption { func (pinLsOpts) Direct() PinLsOption {
return Pin.pinType("direct") return Pin.Ls.pinType("direct")
} }
// Indirect is an option for Pin.Ls which will make it only return indirect pins // Indirect is an option for Pin.Ls which will make it only return indirect pins
// (objects referenced by other recursively pinned objects) // (objects referenced by other recursively pinned objects)
func (pinType) Indirect() PinLsOption { func (pinLsOpts) Indirect() PinLsOption {
return Pin.pinType("indirect") return Pin.Ls.pinType("indirect")
}
// Type is an option for Pin.Ls which will make it only return pins of the given
// type.
//
// Supported values:
// * "direct" - directly pinned objects
// * "recursive" - roots of recursive pins
// * "indirect" - indirectly pinned objects (referenced by recursively pinned
// objects)
// * "all" - all pinned objects (default)
func (pinLsOpts) Type(typeStr string) (PinLsOption, error) {
switch typeStr {
case "all", "direct", "indirect", "recursive":
return Pin.Ls.pinType(typeStr), nil
default:
return nil, fmt.Errorf("invalid type '%s', must be one of {direct, indirect, recursive, all}", typeStr)
}
}
// pinType is an option for Pin.Ls which allows to specify which pin types should
// be returned
//
// Supported values:
// * "direct" - directly pinned objects
// * "recursive" - roots of recursive pins
// * "indirect" - indirectly pinned objects (referenced by recursively pinned
// objects)
// * "all" - all pinned objects (default)
func (pinLsOpts) pinType(t string) PinLsOption {
return func(settings *PinLsSettings) error {
settings.Type = t
return nil
}
}
type pinIsPinnedOpts struct{}
// All is an option for Pin.IsPinned which will make it search in all type of pins.
// It is the default
func (pinIsPinnedOpts) All() PinIsPinnedOption {
return Pin.IsPinned.pinType("all")
}
// Recursive is an option for Pin.IsPinned which will make it only search in
// recursive pins
func (pinIsPinnedOpts) Recursive() PinIsPinnedOption {
return Pin.IsPinned.pinType("recursive")
}
// Direct is an option for Pin.IsPinned which will make it only search in direct
// (non recursive) pins
func (pinIsPinnedOpts) Direct() PinIsPinnedOption {
return Pin.IsPinned.pinType("direct")
}
// Indirect is an option for Pin.IsPinned which will make it only search indirect
// pins (objects referenced by other recursively pinned objects)
func (pinIsPinnedOpts) Indirect() PinIsPinnedOption {
return Pin.IsPinned.pinType("indirect")
}
// Type is an option for Pin.IsPinned which will make it only search pins of the given
// type.
//
// Supported values:
// * "direct" - directly pinned objects
// * "recursive" - roots of recursive pins
// * "indirect" - indirectly pinned objects (referenced by recursively pinned
// objects)
// * "all" - all pinned objects (default)
func (pinIsPinnedOpts) Type(typeStr string) (PinIsPinnedOption, error) {
switch typeStr {
case "all", "direct", "indirect", "recursive":
return Pin.IsPinned.pinType(typeStr), nil
default:
return nil, fmt.Errorf("invalid type '%s', must be one of {direct, indirect, recursive, all}", typeStr)
}
}
// pinType is an option for Pin.IsPinned which allows to specify which pin type the given
// pin is expected to be, speeding up the research.
//
// Supported values:
// * "direct" - directly pinned objects
// * "recursive" - roots of recursive pins
// * "indirect" - indirectly pinned objects (referenced by recursively pinned
// objects)
// * "all" - all pinned objects (default)
func (pinIsPinnedOpts) pinType(t string) PinIsPinnedOption {
return func(settings *PinIsPinnedSettings) error {
settings.WithType = t
return nil
}
} }
// Recursive is an option for Pin.Add which specifies whether to pin an entire // Recursive is an option for Pin.Add which specifies whether to pin an entire
...@@ -137,22 +263,6 @@ func (pinOpts) RmRecursive(recursive bool) PinRmOption { ...@@ -137,22 +263,6 @@ func (pinOpts) RmRecursive(recursive bool) PinRmOption {
} }
} }
// Type is an option for Pin.Ls which allows to specify which pin types should
// be returned
//
// Supported values:
// * "direct" - directly pinned objects
// * "recursive" - roots of recursive pins
// * "indirect" - indirectly pinned objects (referenced by recursively pinned
// objects)
// * "all" - all pinned objects (default)
func (pinOpts) pinType(t string) PinLsOption {
return func(settings *PinLsSettings) error {
settings.Type = t
return nil
}
}
// Unpin is an option for Pin.Update which specifies whether to remove the old pin. // Unpin is an option for Pin.Update which specifies whether to remove the old pin.
// Default is true. // Default is true.
func (pinOpts) Unpin(unpin bool) PinUpdateOption { func (pinOpts) Unpin(unpin bool) PinUpdateOption {
......
...@@ -46,6 +46,10 @@ type PinAPI interface { ...@@ -46,6 +46,10 @@ type PinAPI interface {
// Ls returns list of pinned objects on this node // Ls returns list of pinned objects on this node
Ls(context.Context, ...options.PinLsOption) (<-chan Pin, error) Ls(context.Context, ...options.PinLsOption) (<-chan Pin, error)
// IsPinned returns whether or not the given cid is pinned
// and an explanation of why its pinned
IsPinned(context.Context, path.Path, ...options.PinIsPinnedOption) (string, bool, error)
// Rm removes pin for object specified by the path // Rm removes pin for object specified by the path
Rm(context.Context, path.Path, ...options.PinRmOption) error Rm(context.Context, path.Path, ...options.PinRmOption) error
......
...@@ -28,6 +28,7 @@ func (tp *TestSuite) TestPin(t *testing.T) { ...@@ -28,6 +28,7 @@ func (tp *TestSuite) TestPin(t *testing.T) {
t.Run("TestPinRecursive", tp.TestPinRecursive) t.Run("TestPinRecursive", tp.TestPinRecursive)
t.Run("TestPinLsIndirect", tp.TestPinLsIndirect) t.Run("TestPinLsIndirect", tp.TestPinLsIndirect)
t.Run("TestPinLsPrecedence", tp.TestPinLsPrecedence) t.Run("TestPinLsPrecedence", tp.TestPinLsPrecedence)
t.Run("TestPinIsPinned", tp.TestPinIsPinned)
} }
func (tp *TestSuite) TestPinAdd(t *testing.T) { func (tp *TestSuite) TestPinAdd(t *testing.T) {
...@@ -84,6 +85,8 @@ func (tp *TestSuite) TestPinSimple(t *testing.T) { ...@@ -84,6 +85,8 @@ func (tp *TestSuite) TestPinSimple(t *testing.T) {
t.Error("unexpected pin type") t.Error("unexpected pin type")
} }
assertIsPinned(t, ctx, api, p, "recursive")
err = api.Pin().Rm(ctx, p) err = api.Pin().Rm(ctx, p)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
...@@ -150,7 +153,7 @@ func (tp *TestSuite) TestPinRecursive(t *testing.T) { ...@@ -150,7 +153,7 @@ func (tp *TestSuite) TestPinRecursive(t *testing.T) {
t.Errorf("unexpected pin list len: %d", len(list)) t.Errorf("unexpected pin list len: %d", len(list))
} }
list, err = accPins(api.Pin().Ls(ctx, opt.Pin.Type.Direct())) list, err = accPins(api.Pin().Ls(ctx, opt.Pin.Ls.Direct()))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -163,7 +166,7 @@ func (tp *TestSuite) TestPinRecursive(t *testing.T) { ...@@ -163,7 +166,7 @@ func (tp *TestSuite) TestPinRecursive(t *testing.T) {
t.Errorf("unexpected path, %s != %s", list[0].Path().String(), path.IpfsPath(nd3.Cid()).String()) t.Errorf("unexpected path, %s != %s", list[0].Path().String(), path.IpfsPath(nd3.Cid()).String())
} }
list, err = accPins(api.Pin().Ls(ctx, opt.Pin.Type.Recursive())) list, err = accPins(api.Pin().Ls(ctx, opt.Pin.Ls.Recursive()))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -176,7 +179,7 @@ func (tp *TestSuite) TestPinRecursive(t *testing.T) { ...@@ -176,7 +179,7 @@ func (tp *TestSuite) TestPinRecursive(t *testing.T) {
t.Errorf("unexpected path, %s != %s", list[0].Path().String(), path.IpldPath(nd2.Cid()).String()) t.Errorf("unexpected path, %s != %s", list[0].Path().String(), path.IpldPath(nd2.Cid()).String())
} }
list, err = accPins(api.Pin().Ls(ctx, opt.Pin.Type.Indirect())) list, err = accPins(api.Pin().Ls(ctx, opt.Pin.Ls.Indirect()))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -360,6 +363,39 @@ func (tp *TestSuite) TestPinLsPrecedenceRecursiveDirect(t *testing.T) { ...@@ -360,6 +363,39 @@ func (tp *TestSuite) TestPinLsPrecedenceRecursiveDirect(t *testing.T) {
assertPinTypes(t, ctx, api, []cidContainer{grandparent, parent}, []cidContainer{}, []cidContainer{leaf}) assertPinTypes(t, ctx, api, []cidContainer{grandparent, parent}, []cidContainer{}, []cidContainer{leaf})
} }
func (tp *TestSuite) TestPinIsPinned(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
api, err := tp.makeAPI(ctx)
if err != nil {
t.Fatal(err)
}
leaf, parent, grandparent := getThreeChainedNodes(t, ctx, api, "foofoo")
assertNotPinned(t, ctx, api, path.IpldPath(grandparent.Cid()))
assertNotPinned(t, ctx, api, path.IpldPath(parent.Cid()))
assertNotPinned(t, ctx, api, path.IpldPath(leaf.Cid()))
err = api.Pin().Add(ctx, path.IpldPath(parent.Cid()), opt.Pin.Recursive(true))
if err != nil {
t.Fatal(err)
}
assertNotPinned(t, ctx, api, path.IpldPath(grandparent.Cid()))
assertIsPinned(t, ctx, api, path.IpldPath(parent.Cid()), "recursive")
assertIsPinned(t, ctx, api, path.IpldPath(leaf.Cid()), "indirect")
err = api.Pin().Add(ctx, path.IpldPath(grandparent.Cid()), opt.Pin.Recursive(false))
if err != nil {
t.Fatal(err)
}
assertIsPinned(t, ctx, api, path.IpldPath(grandparent.Cid()), "direct")
assertIsPinned(t, ctx, api, path.IpldPath(parent.Cid()), "recursive")
assertIsPinned(t, ctx, api, path.IpldPath(leaf.Cid()), "indirect")
}
type cidContainer interface { type cidContainer interface {
Cid() cid.Cid Cid() cid.Cid
} }
...@@ -390,21 +426,21 @@ func getThreeChainedNodes(t *testing.T, ctx context.Context, api iface.CoreAPI, ...@@ -390,21 +426,21 @@ func getThreeChainedNodes(t *testing.T, ctx context.Context, api iface.CoreAPI,
func assertPinTypes(t *testing.T, ctx context.Context, api iface.CoreAPI, recusive, direct, indirect []cidContainer) { func assertPinTypes(t *testing.T, ctx context.Context, api iface.CoreAPI, recusive, direct, indirect []cidContainer) {
assertPinLsAllConsistency(t, ctx, api) assertPinLsAllConsistency(t, ctx, api)
list, err := accPins(api.Pin().Ls(ctx, opt.Pin.Type.Recursive())) list, err := accPins(api.Pin().Ls(ctx, opt.Pin.Ls.Recursive()))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
assertPinCids(t, list, recusive...) assertPinCids(t, list, recusive...)
list, err = accPins(api.Pin().Ls(ctx, opt.Pin.Type.Direct())) list, err = accPins(api.Pin().Ls(ctx, opt.Pin.Ls.Direct()))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
assertPinCids(t, list, direct...) assertPinCids(t, list, direct...)
list, err = accPins(api.Pin().Ls(ctx, opt.Pin.Type.Indirect())) list, err = accPins(api.Pin().Ls(ctx, opt.Pin.Ls.Indirect()))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -466,9 +502,9 @@ func assertPinLsAllConsistency(t *testing.T, ctx context.Context, api iface.Core ...@@ -466,9 +502,9 @@ func assertPinLsAllConsistency(t *testing.T, ctx context.Context, api iface.Core
all, recursive, direct, indirect := cid.NewSet(), cid.NewSet(), cid.NewSet(), cid.NewSet() all, recursive, direct, indirect := cid.NewSet(), cid.NewSet(), cid.NewSet(), cid.NewSet()
typeMap := map[string]*pinTypeProps{ typeMap := map[string]*pinTypeProps{
"recursive": {recursive, opt.Pin.Type.Recursive()}, "recursive": {recursive, opt.Pin.Ls.Recursive()},
"direct": {direct, opt.Pin.Type.Direct()}, "direct": {direct, opt.Pin.Ls.Direct()},
"indirect": {indirect, opt.Pin.Type.Indirect()}, "indirect": {indirect, opt.Pin.Ls.Indirect()},
} }
for _, p := range allPins { for _, p := range allPins {
...@@ -506,6 +542,47 @@ func assertPinLsAllConsistency(t *testing.T, ctx context.Context, api iface.Core ...@@ -506,6 +542,47 @@ func assertPinLsAllConsistency(t *testing.T, ctx context.Context, api iface.Core
} }
} }
func assertIsPinned(t *testing.T, ctx context.Context, api iface.CoreAPI, p path.Path, typeStr string) {
t.Helper()
withType, err := opt.Pin.IsPinned.Type(typeStr)
if err != nil {
panic("unhandled pin type")
}
whyPinned, pinned, err := api.Pin().IsPinned(ctx, p, withType)
if err != nil {
t.Fatal(err)
}
if !pinned {
t.Fatalf("%s expected to be pinned with type %s", p, typeStr)
}
switch typeStr {
case "recursive", "direct":
if typeStr != whyPinned {
t.Fatalf("reason for pinning expected to be %s for %s, got %s", typeStr, p, whyPinned)
}
case "indirect":
if whyPinned == "" {
t.Fatalf("expected to have a pin reason for %s", p)
}
}
}
func assertNotPinned(t *testing.T, ctx context.Context, api iface.CoreAPI, p path.Path) {
t.Helper()
_, pinned, err := api.Pin().IsPinned(ctx, p)
if err != nil {
t.Fatal(err)
}
if pinned {
t.Fatalf("%s expected to not be pinned", p)
}
}
func accPins(pins <-chan iface.Pin, err error) ([]iface.Pin, error) { func accPins(pins <-chan iface.Pin, err error) ([]iface.Pin, error) {
if err != nil { if err != nil {
return nil, err return nil, err
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment