aboutsummaryrefslogtreecommitdiffstats
path: root/bug
diff options
context:
space:
mode:
Diffstat (limited to 'bug')
-rw-r--r--bug/bug.go105
-rw-r--r--bug/operation.go4
-rw-r--r--bug/operation_pack.go30
-rw-r--r--bug/operations/create.go6
-rw-r--r--bug/operations/operation_test.go57
-rw-r--r--bug/operations/operations.go10
6 files changed, 138 insertions, 74 deletions
diff --git a/bug/bug.go b/bug/bug.go
index fc7c0c2a..9803a970 100644
--- a/bug/bug.go
+++ b/bug/bug.go
@@ -1,6 +1,7 @@
package bug
import (
+ "errors"
"fmt"
"github.com/MichaelMure/git-bug/repository"
"github.com/MichaelMure/git-bug/util"
@@ -9,6 +10,8 @@ import (
const BugsRefPattern = "refs/bugs/"
const BugsRemoteRefPattern = "refs/remote/%s/bugs/"
+const OpsEntryName = "ops"
+const RootEntryName = "root"
// Bug hold the data of a bug thread, organized in a way close to
// how it will be persisted inside Git. This is the datastructure
@@ -42,6 +45,80 @@ func NewBug() (*Bug, error) {
}, nil
}
+// Read and parse a Bug from git
+func ReadBug(repo repository.Repo, id string) (*Bug, error) {
+ hashes, err := repo.ListCommits(BugsRefPattern + id)
+
+ if err != nil {
+ return nil, err
+ }
+
+ parsedId, err := uuid.FromString(id)
+
+ if err != nil {
+ return nil, err
+ }
+
+ bug := Bug{
+ id: parsedId,
+ }
+
+ for _, hash := range hashes {
+ entries, err := repo.ListEntries(hash)
+
+ bug.lastCommit = hash
+
+ if err != nil {
+ return nil, err
+ }
+
+ var opsEntry repository.TreeEntry
+ opsFound := false
+ var rootEntry repository.TreeEntry
+ rootFound := false
+
+ for _, entry := range entries {
+ if entry.Name == OpsEntryName {
+ opsEntry = entry
+ opsFound = true
+ continue
+ }
+ if entry.Name == RootEntryName {
+ rootEntry = entry
+ rootFound = true
+ }
+ }
+
+ if !opsFound {
+ return nil, errors.New("Invalid tree, missing the ops entry")
+ }
+
+ if !rootFound {
+ return nil, errors.New("Invalid tree, missing the root entry")
+ }
+
+ if bug.root == "" {
+ bug.root = rootEntry.Hash
+ }
+
+ data, err := repo.ReadData(opsEntry.Hash)
+
+ if err != nil {
+ return nil, err
+ }
+
+ op, err := ParseOperationPack(data)
+
+ if err != nil {
+ return nil, err
+ }
+
+ bug.packs = append(bug.packs, *op)
+ }
+
+ return &bug, nil
+}
+
// IsValid check if the Bug data is valid
func (bug *Bug) IsValid() bool {
// non-empty
@@ -104,12 +181,13 @@ func (bug *Bug) Commit(repo repository.Repo) error {
root := bug.root
if root == "" {
root = hash
+ bug.root = hash
}
// Write a Git tree referencing this blob
- hash, err = repo.StoreTree(map[string]util.Hash{
- "ops": hash, // the last pack of ops
- "root": root, // always the first pack of ops (might be the same)
+ hash, err = repo.StoreTree([]repository.TreeEntry{
+ {repository.Blob, hash, OpsEntryName}, // the last pack of ops
+ {repository.Blob, root, RootEntryName}, // always the first pack of ops (might be the same)
})
if err != nil {
return err
@@ -126,6 +204,8 @@ func (bug *Bug) Commit(repo repository.Repo) error {
return err
}
+ bug.lastCommit = hash
+
// Create or update the Git reference for this bug
ref := fmt.Sprintf("%s%s", BugsRefPattern, bug.id.String())
err = repo.UpdateRef(ref, hash)
@@ -140,8 +220,12 @@ func (bug *Bug) Commit(repo repository.Repo) error {
return nil
}
+func (bug *Bug) Id() string {
+ return fmt.Sprintf("%x", bug.id)
+}
+
func (bug *Bug) HumanId() string {
- return bug.id.String()
+ return fmt.Sprintf("%.8s", bug.Id())
}
func (bug *Bug) firstOp() Operation {
@@ -157,3 +241,16 @@ func (bug *Bug) firstOp() Operation {
return nil
}
+
+// Compile a bug in a easily usable snapshot
+func (bug *Bug) Compile() Snapshot {
+ snap := Snapshot{}
+
+ it := NewOperationIterator(bug)
+
+ for it.Next() {
+ snap = it.Value().Apply(snap)
+ }
+
+ return snap
+}
diff --git a/bug/operation.go b/bug/operation.go
index 591c7176..4414f2ad 100644
--- a/bug/operation.go
+++ b/bug/operation.go
@@ -3,7 +3,7 @@ package bug
type OperationType int
const (
- UNKNOW OperationType = iota
+ UNKNOWN OperationType = iota
CREATE
SET_TITLE
ADD_COMMENT
@@ -15,7 +15,7 @@ type Operation interface {
}
type OpBase struct {
- OperationType OperationType `json:"op"`
+ OperationType OperationType
}
func (op OpBase) OpType() OperationType {
diff --git a/bug/operation_pack.go b/bug/operation_pack.go
index 67a2a072..60016474 100644
--- a/bug/operation_pack.go
+++ b/bug/operation_pack.go
@@ -1,7 +1,8 @@
package bug
import (
- "encoding/json"
+ "bytes"
+ "encoding/gob"
"github.com/MichaelMure/git-bug/repository"
"github.com/MichaelMure/git-bug/util"
)
@@ -13,22 +14,35 @@ import (
// inside Git to form the complete ordered chain of operation to
// apply to get the final state of the Bug
type OperationPack struct {
- Operations []Operation `json:"ops"`
- hash util.Hash
+ Operations []Operation
}
-func Parse() (OperationPack, error) {
- // TODO
- return OperationPack{}, nil
+func ParseOperationPack(data []byte) (*OperationPack, error) {
+ reader := bytes.NewReader(data)
+ decoder := gob.NewDecoder(reader)
+
+ var opp OperationPack
+
+ err := decoder.Decode(&opp)
+
+ if err != nil {
+ return nil, err
+ }
+
+ return &opp, nil
}
func (opp *OperationPack) Serialize() ([]byte, error) {
- jsonBytes, err := json.Marshal(*opp)
+ var data bytes.Buffer
+
+ encoder := gob.NewEncoder(&data)
+ err := encoder.Encode(*opp)
+
if err != nil {
return nil, err
}
- return jsonBytes, nil
+ return data.Bytes(), nil
}
// Append a new operation to the pack
diff --git a/bug/operations/create.go b/bug/operations/create.go
index 1c34f85d..49b648a2 100644
--- a/bug/operations/create.go
+++ b/bug/operations/create.go
@@ -11,9 +11,9 @@ var _ bug.Operation = CreateOperation{}
type CreateOperation struct {
bug.OpBase
- Title string `json:"t"`
- Message string `json:"m"`
- Author bug.Person `json:"a"`
+ Title string
+ Message string
+ Author bug.Person
}
func NewCreateOp(author bug.Person, title, message string) CreateOperation {
diff --git a/bug/operations/operation_test.go b/bug/operations/operation_test.go
deleted file mode 100644
index e53e524b..00000000
--- a/bug/operations/operation_test.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package operations
-
-import (
- "github.com/MichaelMure/git-bug/bug"
- "testing"
-)
-
-// Different type with the same fields
-type CreateOperation2 struct {
- Title string
- Message string
-}
-
-func (op CreateOperation2) OpType() bug.OperationType {
- return bug.UNKNOW
-}
-
-func (op CreateOperation2) Apply(snapshot bug.Snapshot) bug.Snapshot {
- // no-op
- return snapshot
-}
-
-func TestOperationsEquality(t *testing.T) {
- var rene = bug.Person{
- Name: "René Descartes",
- Email: "rene@descartes.fr",
- }
-
- var A bug.Operation = NewCreateOp(rene, "title", "message")
- var B bug.Operation = NewCreateOp(rene, "title", "message")
- var C bug.Operation = NewCreateOp(rene, "title", "different message")
-
- if A != B {
- t.Fatal("Equal value ops should be tested equals")
- }
-
- if A == C {
- t.Fatal("Different value ops should be tested different")
- }
-
- D := CreateOperation2{Title: "title", Message: "message"}
-
- if A == D {
- t.Fatal("Operations equality should handle the type")
- }
-
- var isaac = bug.Person{
- Name: "Isaac Newton",
- Email: "isaac@newton.uk",
- }
-
- var E bug.Operation = NewCreateOp(isaac, "title", "message")
-
- if A == E {
- t.Fatal("Operation equality should handle the author")
- }
-}
diff --git a/bug/operations/operations.go b/bug/operations/operations.go
new file mode 100644
index 00000000..f42d6e9a
--- /dev/null
+++ b/bug/operations/operations.go
@@ -0,0 +1,10 @@
+package operations
+
+import "encoding/gob"
+
+// Package initialisation used to register operation's type for (de)serialization
+func init() {
+ gob.Register(AddCommentOperation{})
+ gob.Register(CreateOperation{})
+ gob.Register(SetTitleOperation{})
+}