pin: add a IsPinned method

parent 292d906e
package options
import "fmt"
type PinAddSettings struct {
Recursive bool
}
type TypeSettings struct {
Type string
}
type PinLsSettings struct {
Type string
}
type PinIsPinnedSettings struct {
WithType string
}
// PinRmSettings represents the settings of pin rm command
type PinRmSettings struct {
Recursive bool
......@@ -17,13 +27,19 @@ type PinUpdateSettings struct {
Unpin bool
}
// PinAddOption pin add option func
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
type PinRmOption func(*PinRmSettings) error
// PinLsOption pin ls option func
type PinLsOption func(*PinLsSettings) error
// PinUpdateOption pin update option func
type PinUpdateOption func(*PinUpdateSettings) error
func PinAddOptions(opts ...PinAddOption) (*PinAddSettings, error) {
......@@ -41,14 +57,14 @@ func PinAddOptions(opts ...PinAddOption) (*PinAddSettings, error) {
return options, nil
}
// PinRmOptions pin rm options
func PinRmOptions(opts ...PinRmOption) (*PinRmSettings, error) {
options := &PinRmSettings{
Recursive: true,
func PinLsOptions(opts ...PinLsOption) (*PinLsSettings, error) {
options := &PinLsSettings{
Type: "all",
}
for _, opt := range opts {
if err := opt(options); err != nil {
err := opt(options)
if err != nil {
return nil, err
}
}
......@@ -56,9 +72,9 @@ func PinRmOptions(opts ...PinRmOption) (*PinRmSettings, error) {
return options, nil
}
func PinLsOptions(opts ...PinLsOption) (*PinLsSettings, error) {
options := &PinLsSettings{
Type: "all",
func PinIsPinnedOptions(opts ...PinIsPinnedOption) (*PinIsPinnedSettings, error) {
options := &PinIsPinnedSettings{
WithType: "all",
}
for _, opt := range opts {
......@@ -71,6 +87,21 @@ func PinLsOptions(opts ...PinLsOption) (*PinLsSettings, error) {
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) {
options := &PinUpdateSettings{
Unpin: true,
......@@ -86,36 +117,131 @@ func PinUpdateOptions(opts ...PinUpdateOption) (*PinUpdateSettings, error) {
return options, nil
}
type pinType struct{}
type pinOpts struct {
Type pinType
Ls pinLsOpts
IsPinned pinIsPinnedOpts
}
var Pin pinOpts
type pinLsOpts struct{}
// All is an option for Pin.Ls which will make it return all pins. It is
// the default
func (pinType) All() PinLsOption {
return Pin.pinType("all")
func (pinLsOpts) All() PinLsOption {
return Pin.Ls.pinType("all")
}
// Recursive is an option for Pin.Ls which will make it only return recursive
// pins
func (pinType) Recursive() PinLsOption {
return Pin.pinType("recursive")
func (pinLsOpts) Recursive() PinLsOption {
return Pin.Ls.pinType("recursive")
}
// Direct is an option for Pin.Ls which will make it only return direct (non
// recursive) pins
func (pinType) Direct() PinLsOption {
return Pin.pinType("direct")
func (pinLsOpts) Direct() PinLsOption {
return Pin.Ls.pinType("direct")
}
// Indirect is an option for Pin.Ls which will make it only return indirect pins
// (objects referenced by other recursively pinned objects)
func (pinType) Indirect() PinLsOption {
return Pin.pinType("indirect")
func (pinLsOpts) Indirect() PinLsOption {
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
......@@ -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.
// Default is true.
func (pinOpts) Unpin(unpin bool) PinUpdateOption {
......
......@@ -46,6 +46,10 @@ type PinAPI interface {
// Ls returns list of pinned objects on this node
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(context.Context, path.Path, ...options.PinRmOption) error
......
......@@ -28,6 +28,7 @@ func (tp *TestSuite) TestPin(t *testing.T) {
t.Run("TestPinRecursive", tp.TestPinRecursive)
t.Run("TestPinLsIndirect", tp.TestPinLsIndirect)
t.Run("TestPinLsPrecedence", tp.TestPinLsPrecedence)
t.Run("TestPinIsPinned", tp.TestPinIsPinned)
}
func (tp *TestSuite) TestPinAdd(t *testing.T) {
......@@ -84,6 +85,8 @@ func (tp *TestSuite) TestPinSimple(t *testing.T) {
t.Error("unexpected pin type")
}
assertIsPinned(t, ctx, api, p, "recursive")
err = api.Pin().Rm(ctx, p)
if err != nil {
t.Fatal(err)
......@@ -150,7 +153,7 @@ func (tp *TestSuite) TestPinRecursive(t *testing.T) {
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 {
t.Fatal(err)
}
......@@ -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())
}
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 {
t.Fatal(err)
}
......@@ -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())
}
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 {
t.Fatal(err)
}
......@@ -360,6 +363,39 @@ func (tp *TestSuite) TestPinLsPrecedenceRecursiveDirect(t *testing.T) {
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 {
Cid() cid.Cid
}
......@@ -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) {
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 {
t.Fatal(err)
}
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 {
t.Fatal(err)
}
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 {
t.Fatal(err)
}
......@@ -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()
typeMap := map[string]*pinTypeProps{
"recursive": {recursive, opt.Pin.Type.Recursive()},
"direct": {direct, opt.Pin.Type.Direct()},
"indirect": {indirect, opt.Pin.Type.Indirect()},
"recursive": {recursive, opt.Pin.Ls.Recursive()},
"direct": {direct, opt.Pin.Ls.Direct()},
"indirect": {indirect, opt.Pin.Ls.Indirect()},
}
for _, p := range allPins {
......@@ -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) {
if err != nil {
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