aboutsummaryrefslogtreecommitdiffstats
path: root/entity
diff options
context:
space:
mode:
Diffstat (limited to 'entity')
-rw-r--r--entity/dag/common_test.go15
-rw-r--r--entity/dag/operation.go9
-rw-r--r--entity/dag/operation_pack.go45
-rw-r--r--entity/dag/operation_pack_test.go20
4 files changed, 79 insertions, 10 deletions
diff --git a/entity/dag/common_test.go b/entity/dag/common_test.go
index fa15cd1f..1898451d 100644
--- a/entity/dag/common_test.go
+++ b/entity/dag/common_test.go
@@ -23,10 +23,11 @@ type op1 struct {
OperationType int `json:"type"`
Field1 string `json:"field_1"`
+ Files []repository.Hash
}
-func newOp1(author identity.Interface, field1 string) *op1 {
- return &op1{author: author, OperationType: 1, Field1: field1}
+func newOp1(author identity.Interface, field1 string, files ...repository.Hash) *op1 {
+ return &op1{author: author, OperationType: 1, Field1: field1, Files: files}
}
func (o *op1) Id() entity.Id {
@@ -34,11 +35,15 @@ func (o *op1) Id() entity.Id {
return entity.DeriveId(data)
}
+func (o *op1) Validate() error { return nil }
+
func (o *op1) Author() identity.Interface {
return o.author
}
-func (o *op1) Validate() error { return nil }
+func (o *op1) GetFiles() []repository.Hash {
+ return o.Files
+}
type op2 struct {
author identity.Interface
@@ -56,12 +61,12 @@ func (o *op2) Id() entity.Id {
return entity.DeriveId(data)
}
+func (o *op2) Validate() error { return nil }
+
func (o *op2) Author() identity.Interface {
return o.author
}
-func (o *op2) Validate() error { return nil }
-
func unmarshaler(author identity.Interface, raw json.RawMessage) (Operation, error) {
var t struct {
OperationType int `json:"type"`
diff --git a/entity/dag/operation.go b/entity/dag/operation.go
index 94974a82..1bfb3d3d 100644
--- a/entity/dag/operation.go
+++ b/entity/dag/operation.go
@@ -3,6 +3,7 @@ package dag
import (
"github.com/MichaelMure/git-bug/entity"
"github.com/MichaelMure/git-bug/identity"
+ "github.com/MichaelMure/git-bug/repository"
)
// Operation is a piece of data defining a change to reflect on the state of an Entity.
@@ -33,3 +34,11 @@ type Operation interface {
// Author returns the author of this operation
Author() identity.Interface
}
+
+// OperationWithFiles is an extended Operation that has files dependency, stored in git.
+type OperationWithFiles interface {
+ Operation
+
+ // GetFiles return the files needed by this operation
+ GetFiles() []repository.Hash
+}
diff --git a/entity/dag/operation_pack.go b/entity/dag/operation_pack.go
index a436fd33..72063c60 100644
--- a/entity/dag/operation_pack.go
+++ b/entity/dag/operation_pack.go
@@ -15,10 +15,8 @@ import (
"github.com/MichaelMure/git-bug/util/lamport"
)
-// TODO: extra data tree
-const extraEntryName = "extra"
-
const opsEntryName = "ops"
+const extraEntryName = "extra"
const versionEntryPrefix = "version-"
const createClockEntryPrefix = "create-clock-"
const editClockEntryPrefix = "edit-clock-"
@@ -118,6 +116,7 @@ func (opp *operationPack) Write(def Definition, repo repository.Repo, parentComm
// Make a Git tree referencing this blob and encoding the other values:
// - format version
// - clocks
+ // - extra data
tree := []repository.TreeEntry{
{ObjectType: repository.Blob, Hash: emptyBlobHash,
Name: fmt.Sprintf(versionEntryPrefix+"%d", def.FormatVersion)},
@@ -133,6 +132,17 @@ func (opp *operationPack) Write(def Definition, repo repository.Repo, parentComm
Name: fmt.Sprintf(createClockEntryPrefix+"%d", opp.CreateTime),
})
}
+ if extraTree := opp.makeExtraTree(); len(extraTree) > 0 {
+ extraTreeHash, err := repo.StoreTree(extraTree)
+ if err != nil {
+ return "", err
+ }
+ tree = append(tree, repository.TreeEntry{
+ ObjectType: repository.Tree,
+ Hash: extraTreeHash,
+ Name: extraEntryName,
+ })
+ }
// Store the tree
treeHash, err := repo.StoreTree(tree)
@@ -163,6 +173,35 @@ func (opp *operationPack) Write(def Definition, repo repository.Repo, parentComm
return commitHash, nil
}
+func (opp *operationPack) makeExtraTree() []repository.TreeEntry {
+ var tree []repository.TreeEntry
+ counter := 0
+ added := make(map[repository.Hash]interface{})
+
+ for _, ops := range opp.Operations {
+ ops, ok := ops.(OperationWithFiles)
+ if !ok {
+ continue
+ }
+
+ for _, file := range ops.GetFiles() {
+ if _, has := added[file]; !has {
+ tree = append(tree, repository.TreeEntry{
+ ObjectType: repository.Blob,
+ Hash: file,
+ // The name is not important here, we only need to
+ // reference the blob.
+ Name: fmt.Sprintf("file%d", counter),
+ })
+ counter++
+ added[file] = struct{}{}
+ }
+ }
+ }
+
+ return tree
+}
+
// readOperationPack read the operationPack encoded in git at the given Tree hash.
//
// Validity of the Lamport clocks is left for the caller to decide.
diff --git a/entity/dag/operation_pack_test.go b/entity/dag/operation_pack_test.go
index a12382af..0fe98dc7 100644
--- a/entity/dag/operation_pack_test.go
+++ b/entity/dag/operation_pack_test.go
@@ -1,6 +1,7 @@
package dag
import (
+ "math/rand"
"testing"
"github.com/stretchr/testify/require"
@@ -11,10 +12,16 @@ import (
func TestOperationPackReadWrite(t *testing.T) {
repo, id1, _, resolver, def := makeTestContext()
+ blobHash1, err := repo.StoreData(randomData())
+ require.NoError(t, err)
+
+ blobHash2, err := repo.StoreData(randomData())
+ require.NoError(t, err)
+
opp := &operationPack{
Author: id1,
Operations: []Operation{
- newOp1(id1, "foo"),
+ newOp1(id1, "foo", blobHash1, blobHash2),
newOp2(id1, "bar"),
},
CreateTime: 123,
@@ -36,7 +43,7 @@ func TestOperationPackReadWrite(t *testing.T) {
opp3 := &operationPack{
Author: id1,
Operations: []Operation{
- newOp1(id1, "foo"),
+ newOp1(id1, "foo", blobHash1, blobHash2),
newOp2(id1, "bar"),
},
CreateTime: 123,
@@ -86,3 +93,12 @@ func TestOperationPackSignedReadWrite(t *testing.T) {
}
require.Equal(t, opp.Id(), opp3.Id())
}
+
+func randomData() []byte {
+ var letterRunes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ b := make([]byte, 32)
+ for i := range b {
+ b[i] = letterRunes[rand.Intn(len(letterRunes))]
+ }
+ return b
+}