@cryptotaxi247 / kubo / commits / 432ab6212

coreapi: implement Object.Diff

License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>

Łukasz Magiera committed Feb 2, 2018 at 21:50 UTC 432ab62127c9d5773027e3e8cc4e4aa0170df511
3 files changed +106
core/coreapi/interface/object.go
+37
@@ -31,6 +31,39 @@ type ObjectStat struct {
31 CumulativeSize int
32 }
33
34 +
35 +const (
36 + // DiffAdd is a Type of ObjectChange where a link was added to the graph
37 + DiffAdd = iota
38 +
39 + // DiffRemove is a Type of ObjectChange where a link was removed from the graph
40 + DiffRemove
41 +
42 + // DiffMod is a Type of ObjectChange where a link was changed in the graph
43 + DiffMod
44 +)
45 +
46 +// ObjectChange represents a change ia a graph
47 +// TODO: do we want this to be an interface?
48 +type ObjectChange struct {
49 + // Type of the change, either:
50 + // * DiffAdd - Added a link
51 + // * DiffRemove - Removed a link
52 + // * DiffMod - Modified a link
53 + Type int
54 +
55 + // Path to the changed link
56 + Path string
57 +
58 + // Before holds the link path before the change. Note that when a link is
59 + // added, this will be nil.
60 + Before Path
61 +
62 + // After holds the link path after the change. Note that when a link is
63 + // removed, this will be nil.
64 + After Path
65 +}
66 +
67 // ObjectAPI specifies the interface to MerkleDAG and contains useful utilities
68 // for manipulating MerkleDAG data structures.
69 type ObjectAPI interface {
@@ -65,4 +98,8 @@ type ObjectAPI interface {
98
99 // SetData sets the data contained in the node
100 SetData(context.Context, Path, io.Reader) (ResolvedPath, error)
101 +
102 + // Diff returns a set of changes needed to transform the first object into the
103 + // second.
104 + Diff(context.Context, Path, Path) ([]ObjectChange, error)
105 }
core/coreapi/object.go
+29
@@ -297,6 +297,35 @@ func (api *ObjectAPI) patchData(ctx context.Context, path coreiface.Path, r io.R
297 return coreiface.IpfsPath(pbnd.Cid()), nil
298 }
299
300 +func (api *ObjectAPI) Diff(ctx context.Context, before coreiface.Path, after coreiface.Path) ([]coreiface.ObjectChange, error) {
301 + beforeNd, err := api.core().ResolveNode(ctx, before)
302 + if err != nil {
303 + return nil, err
304 + }
305 +
306 + afterNd, err := api.core().ResolveNode(ctx, after)
307 + if err != nil {
308 + return nil, err
309 + }
310 +
311 + changes, err := dagutils.Diff(ctx, api.node.DAG, beforeNd, afterNd)
312 + if err != nil {
313 + return nil, err
314 + }
315 +
316 + out := make([]coreiface.ObjectChange, len(changes))
317 + for i, change := range changes {
318 + out[i] = coreiface.ObjectChange{
319 + Type: change.Type,
320 + Path: change.Path,
321 + Before: coreiface.IpfsPath(change.Before),
322 + After: coreiface.IpfsPath(change.After),
323 + }
324 + }
325 +
326 + return out, nil
327 +}
328 +
329 func (api *ObjectAPI) core() coreiface.CoreAPI {
330 return (*CoreAPI)(api)
331 }
core/coreapi/object_test.go
+40
@@ -8,6 +8,7 @@ import (
8 "strings"
9 "testing"
10
11 + "github.com/ipfs/go-ipfs/core/coreapi/interface"
12 opt "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
13 )
14
@@ -385,3 +386,42 @@ func TestObjectSetData(t *testing.T) {
386 t.Error("unexpected data")
387 }
388 }
389 +
390 +func TestDiffTest(t *testing.T) {
391 + ctx := context.Background()
392 + _, api, err := makeAPI(ctx)
393 + if err != nil {
394 + t.Fatal(err)
395 + }
396 +
397 + p1, err := api.Object().Put(ctx, strings.NewReader(`{"Data":"foo"}`))
398 + if err != nil {
399 + t.Fatal(err)
400 + }
401 +
402 + p2, err := api.Object().Put(ctx, strings.NewReader(`{"Data":"bar"}`))
403 + if err != nil {
404 + t.Fatal(err)
405 + }
406 +
407 + changes, err := api.Object().Diff(ctx, p1, p2)
408 + if err != nil {
409 + t.Fatal(err)
410 + }
411 +
412 + if len(changes) != 1 {
413 + t.Fatal("unexpected changes len")
414 + }
415 +
416 + if changes[0].Type != iface.DiffMod {
417 + t.Fatal("unexpected change type")
418 + }
419 +
420 + if changes[0].Before.String() != p1.String() {
421 + t.Fatal("unexpected before path")
422 + }
423 +
424 + if changes[0].After.String() != p2.String() {
425 + t.Fatal("unexpected before path")
426 + }
427 +}