mirror of
https://github.com/ipfs/kubo.git
synced 2025-07-20 22:22:50 +08:00
coreapi: implement Object.Diff
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
This commit is contained in:
core/coreapi
@ -31,6 +31,39 @@ type ObjectStat struct {
|
|||||||
CumulativeSize int
|
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
|
// ObjectAPI specifies the interface to MerkleDAG and contains useful utilities
|
||||||
// for manipulating MerkleDAG data structures.
|
// for manipulating MerkleDAG data structures.
|
||||||
type ObjectAPI interface {
|
type ObjectAPI interface {
|
||||||
@ -65,4 +98,8 @@ type ObjectAPI interface {
|
|||||||
|
|
||||||
// SetData sets the data contained in the node
|
// SetData sets the data contained in the node
|
||||||
SetData(context.Context, Path, io.Reader) (ResolvedPath, error)
|
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)
|
||||||
}
|
}
|
||||||
|
@ -297,6 +297,35 @@ func (api *ObjectAPI) patchData(ctx context.Context, path coreiface.Path, r io.R
|
|||||||
return coreiface.IpfsPath(pbnd.Cid()), nil
|
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 {
|
func (api *ObjectAPI) core() coreiface.CoreAPI {
|
||||||
return (*CoreAPI)(api)
|
return (*CoreAPI)(api)
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ipfs/go-ipfs/core/coreapi/interface"
|
||||||
opt "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
|
opt "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -385,3 +386,42 @@ func TestObjectSetData(t *testing.T) {
|
|||||||
t.Error("unexpected data")
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user