diff options
Diffstat (limited to 'bug')
-rw-r--r-- | bug/bug.go | 105 | ||||
-rw-r--r-- | bug/operation.go | 4 | ||||
-rw-r--r-- | bug/operation_pack.go | 30 | ||||
-rw-r--r-- | bug/operations/create.go | 6 | ||||
-rw-r--r-- | bug/operations/operation_test.go | 57 | ||||
-rw-r--r-- | bug/operations/operations.go | 10 |
6 files changed, 138 insertions, 74 deletions
@@ -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{}) +} |