1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-06-25 15:08:45 +08:00

coreapi: implement Object.Diff

License: MIT
Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
This commit is contained in:
Łukasz Magiera
2018-02-02 21:50:22 +01:00
parent 7ac229e286
commit 432ab62127
3 changed files with 106 additions and 0 deletions

View File

@ -31,6 +31,39 @@ type ObjectStat struct {
CumulativeSize int
}
const (
// DiffAdd is a Type of ObjectChange where a link was added to the graph
DiffAdd = iota
// DiffRemove is a Type of ObjectChange where a link was removed from the graph
DiffRemove
// DiffMod is a Type of ObjectChange where a link was changed in the graph
DiffMod
)
// ObjectChange represents a change ia a graph
// TODO: do we want this to be an interface?
type ObjectChange struct {
// Type of the change, either:
// * DiffAdd - Added a link
// * DiffRemove - Removed a link
// * DiffMod - Modified a link
Type int
// Path to the changed link
Path string
// Before holds the link path before the change. Note that when a link is
// added, this will be nil.
Before Path
// After holds the link path after the change. Note that when a link is
// removed, this will be nil.
After Path
}
// ObjectAPI specifies the interface to MerkleDAG and contains useful utilities
// for manipulating MerkleDAG data structures.
type ObjectAPI interface {
@ -65,4 +98,8 @@ type ObjectAPI interface {
// SetData sets the data contained in the node
SetData(context.Context, Path, io.Reader) (ResolvedPath, error)
// Diff returns a set of changes needed to transform the first object into the
// second.
Diff(context.Context, Path, Path) ([]ObjectChange, error)
}

View File

@ -297,6 +297,35 @@ func (api *ObjectAPI) patchData(ctx context.Context, path coreiface.Path, r io.R
return coreiface.IpfsPath(pbnd.Cid()), nil
}
func (api *ObjectAPI) Diff(ctx context.Context, before coreiface.Path, after coreiface.Path) ([]coreiface.ObjectChange, error) {
beforeNd, err := api.core().ResolveNode(ctx, before)
if err != nil {
return nil, err
}
afterNd, err := api.core().ResolveNode(ctx, after)
if err != nil {
return nil, err
}
changes, err := dagutils.Diff(ctx, api.node.DAG, beforeNd, afterNd)
if err != nil {
return nil, err
}
out := make([]coreiface.ObjectChange, len(changes))
for i, change := range changes {
out[i] = coreiface.ObjectChange{
Type: change.Type,
Path: change.Path,
Before: coreiface.IpfsPath(change.Before),
After: coreiface.IpfsPath(change.After),
}
}
return out, nil
}
func (api *ObjectAPI) core() coreiface.CoreAPI {
return (*CoreAPI)(api)
}

View File

@ -8,6 +8,7 @@ import (
"strings"
"testing"
"github.com/ipfs/go-ipfs/core/coreapi/interface"
opt "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
)
@ -385,3 +386,42 @@ func TestObjectSetData(t *testing.T) {
t.Error("unexpected data")
}
}
func TestDiffTest(t *testing.T) {
ctx := context.Background()
_, api, err := makeAPI(ctx)
if err != nil {
t.Fatal(err)
}
p1, err := api.Object().Put(ctx, strings.NewReader(`{"Data":"foo"}`))
if err != nil {
t.Fatal(err)
}
p2, err := api.Object().Put(ctx, strings.NewReader(`{"Data":"bar"}`))
if err != nil {
t.Fatal(err)
}
changes, err := api.Object().Diff(ctx, p1, p2)
if err != nil {
t.Fatal(err)
}
if len(changes) != 1 {
t.Fatal("unexpected changes len")
}
if changes[0].Type != iface.DiffMod {
t.Fatal("unexpected change type")
}
if changes[0].Before.String() != p1.String() {
t.Fatal("unexpected before path")
}
if changes[0].After.String() != p2.String() {
t.Fatal("unexpected before path")
}
}