aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Muré <batolettre@gmail.com>2018-09-12 16:57:04 +0200
committerMichael Muré <batolettre@gmail.com>2018-09-12 16:57:46 +0200
commit60fcfcdcb0e89741528cfc99a94a48f204d48e6b (patch)
tree48189b7f85e10b1bdf6a4b897ac0b966c4cec23c
parent3605887345792d2f981f971c6c4a2cb7f86a343e (diff)
downloadgit-bug-60fcfcdcb0e89741528cfc99a94a48f204d48e6b.tar.gz
bug: change the OperationPack serialization format for Json
See https://github.com/MichaelMure/git-bug/issues/5 for the details of this choice
-rw-r--r--bug/bug.go10
-rw-r--r--bug/operation.go14
-rw-r--r--bug/operation_pack.go76
-rw-r--r--bug/person.go4
-rw-r--r--graphql/graph/gen_graph.go4
-rw-r--r--operations/add_comment.go12
-rw-r--r--operations/create.go12
-rw-r--r--operations/label_change.go4
-rw-r--r--operations/operations.go14
-rw-r--r--operations/set_status.go2
-rw-r--r--operations/set_title.go4
-rw-r--r--tests/operation_pack_test.go24
12 files changed, 111 insertions, 69 deletions
diff --git a/bug/bug.go b/bug/bug.go
index ac078866..e548757e 100644
--- a/bug/bug.go
+++ b/bug/bug.go
@@ -1,6 +1,7 @@
package bug
import (
+ "encoding/json"
"errors"
"fmt"
"strings"
@@ -193,20 +194,21 @@ func readBug(repo repository.Repo, ref string) (*Bug, error) {
return nil, err
}
- op, err := ParseOperationPack(data)
+ opp := &OperationPack{}
+ err = json.Unmarshal(data, &opp)
if err != nil {
return nil, err
}
// tag the pack with the commit hash
- op.commitHash = hash
+ opp.commitHash = hash
if err != nil {
return nil, err
}
- bug.packs = append(bug.packs, *op)
+ bug.packs = append(bug.packs, *opp)
}
return &bug, nil
@@ -450,7 +452,7 @@ func makeMediaTree(pack OperationPack) []repository.TreeEntry {
added := make(map[git.Hash]interface{})
for _, ops := range pack.Operations {
- for _, file := range ops.Files() {
+ for _, file := range ops.GetFiles() {
if _, has := added[file]; !has {
tree = append(tree, repository.TreeEntry{
ObjectType: repository.Blob,
diff --git a/bug/operation.go b/bug/operation.go
index f6c63144..5d42a175 100644
--- a/bug/operation.go
+++ b/bug/operation.go
@@ -27,8 +27,8 @@ type Operation interface {
GetUnixTime() int64
// Apply the operation to a Snapshot to create the final state
Apply(snapshot Snapshot) Snapshot
- // Files return the files needed by this operation
- Files() []git.Hash
+ // GetFiles return the files needed by this operation
+ GetFiles() []git.Hash
// TODO: data validation (ex: a title is a single line)
// Validate() bool
@@ -36,9 +36,9 @@ type Operation interface {
// OpBase implement the common code for all operations
type OpBase struct {
- OperationType OperationType
- Author Person
- UnixTime int64
+ OperationType OperationType `json:"type"`
+ Author Person `json:"author"`
+ UnixTime int64 `json:"timestamp"`
}
// NewOpBase is the constructor for an OpBase
@@ -65,7 +65,7 @@ func (op OpBase) GetUnixTime() int64 {
return op.UnixTime
}
-// Files return the files needed by this operation
-func (op OpBase) Files() []git.Hash {
+// GetFiles return the files needed by this operation
+func (op OpBase) GetFiles() []git.Hash {
return nil
}
diff --git a/bug/operation_pack.go b/bug/operation_pack.go
index 8568fa16..fe26952f 100644
--- a/bug/operation_pack.go
+++ b/bug/operation_pack.go
@@ -1,13 +1,16 @@
package bug
import (
- "bytes"
- "encoding/gob"
+ "encoding/json"
+ "fmt"
+ "reflect"
"github.com/MichaelMure/git-bug/repository"
"github.com/MichaelMure/git-bug/util/git"
)
+const formatVersion = 1
+
// OperationPack represent an ordered set of operation to apply
// to a Bug. These operations are stored in a single Git commit.
//
@@ -21,34 +24,65 @@ type OperationPack struct {
commitHash git.Hash
}
-// ParseOperationPack will deserialize an OperationPack from raw bytes
-func ParseOperationPack(data []byte) (*OperationPack, error) {
- reader := bytes.NewReader(data)
- decoder := gob.NewDecoder(reader)
+var operations map[OperationType]reflect.Type
- var opp OperationPack
+func Register(t OperationType, op interface{}) {
+ if operations == nil {
+ operations = make(map[OperationType]reflect.Type)
+ }
+ operations[t] = reflect.TypeOf(op)
+}
- err := decoder.Decode(&opp)
+func (opp *OperationPack) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Version uint `json:"version"`
+ Operations []Operation `json:"ops"`
+ }{
+ Version: formatVersion,
+ Operations: opp.Operations,
+ })
+}
- if err != nil {
- return nil, err
+func (opp *OperationPack) UnmarshalJSON(data []byte) error {
+ aux := struct {
+ Version uint `json:"version"`
+ Operations []json.RawMessage `json:"ops"`
+ }{}
+
+ if err := json.Unmarshal(data, &aux); err != nil {
+ return err
}
- return &opp, nil
-}
+ if aux.Version != formatVersion {
+ return fmt.Errorf("unknown format version %v", aux.Version)
+ }
-// Serialize will serialise an OperationPack into raw bytes
-func (opp *OperationPack) Serialize() ([]byte, error) {
- var data bytes.Buffer
+ for _, raw := range aux.Operations {
+ var t struct {
+ OperationType OperationType `json:"type"`
+ }
- encoder := gob.NewEncoder(&data)
- err := encoder.Encode(*opp)
+ if err := json.Unmarshal(raw, &t); err != nil {
+ return err
+ }
- if err != nil {
- return nil, err
+ opType, ok := operations[t.OperationType]
+ if !ok {
+ return fmt.Errorf("unknown operation type %v", t.OperationType)
+ }
+
+ op := reflect.New(opType).Interface()
+
+ if err := json.Unmarshal(raw, op); err != nil {
+ return err
+ }
+
+ deref := reflect.ValueOf(op).Elem().Interface()
+
+ opp.Operations = append(opp.Operations, deref.(Operation))
}
- return data.Bytes(), nil
+ return nil
}
// Append a new operation to the pack
@@ -69,7 +103,7 @@ func (opp *OperationPack) IsValid() bool {
// Write will serialize and store the OperationPack as a git blob and return
// its hash
func (opp *OperationPack) Write(repo repository.Repo) (git.Hash, error) {
- data, err := opp.Serialize()
+ data, err := json.Marshal(opp)
if err != nil {
return "", err
diff --git a/bug/person.go b/bug/person.go
index 9afaac0d..d9f1108b 100644
--- a/bug/person.go
+++ b/bug/person.go
@@ -8,8 +8,8 @@ import (
)
type Person struct {
- Name string
- Email string
+ Name string `json:"name"`
+ Email string `json:"email"`
}
// GetUser will query the repository for user detail and build the corresponding Person
diff --git a/graphql/graph/gen_graph.go b/graphql/graph/gen_graph.go
index 6969f008..a3ea1738 100644
--- a/graphql/graph/gen_graph.go
+++ b/graphql/graph/gen_graph.go
@@ -340,7 +340,7 @@ func (ec *executionContext) _AddCommentOperation_files(ctx context.Context, fiel
rctx.Field = field
rctx.PushField(field.Alias)
defer rctx.Pop()
- res := obj.Files()
+ res := obj.Files
arr1 := graphql.Array{}
for idx1 := range res {
arr1 = append(arr1, func() graphql.Marshaler {
@@ -1157,7 +1157,7 @@ func (ec *executionContext) _CreateOperation_files(ctx context.Context, field gr
rctx.Field = field
rctx.PushField(field.Alias)
defer rctx.Pop()
- res := obj.Files()
+ res := obj.Files
arr1 := graphql.Array{}
for idx1 := range res {
arr1 = append(arr1, func() graphql.Marshaler {
diff --git a/operations/add_comment.go b/operations/add_comment.go
index 24fa2696..8c4b8b9c 100644
--- a/operations/add_comment.go
+++ b/operations/add_comment.go
@@ -11,16 +11,16 @@ var _ bug.Operation = AddCommentOperation{}
type AddCommentOperation struct {
bug.OpBase
- Message string
+ Message string `json:"message"`
// TODO: change for a map[string]util.hash to store the filename ?
- files []git.Hash
+ Files []git.Hash `json:"files"`
}
func (op AddCommentOperation) Apply(snapshot bug.Snapshot) bug.Snapshot {
comment := bug.Comment{
Message: op.Message,
Author: op.Author,
- Files: op.files,
+ Files: op.Files,
UnixTime: op.UnixTime,
}
@@ -29,15 +29,15 @@ func (op AddCommentOperation) Apply(snapshot bug.Snapshot) bug.Snapshot {
return snapshot
}
-func (op AddCommentOperation) Files() []git.Hash {
- return op.files
+func (op AddCommentOperation) GetFiles() []git.Hash {
+ return op.Files
}
func NewAddCommentOp(author bug.Person, message string, files []git.Hash) AddCommentOperation {
return AddCommentOperation{
OpBase: bug.NewOpBase(bug.AddCommentOp, author),
Message: message,
- files: files,
+ Files: files,
}
}
diff --git a/operations/create.go b/operations/create.go
index 81e5af93..a671171e 100644
--- a/operations/create.go
+++ b/operations/create.go
@@ -11,9 +11,9 @@ var _ bug.Operation = CreateOperation{}
type CreateOperation struct {
bug.OpBase
- Title string
- Message string
- files []git.Hash
+ Title string `json:"title"`
+ Message string `json:"message"`
+ Files []git.Hash `json:"files"`
}
func (op CreateOperation) Apply(snapshot bug.Snapshot) bug.Snapshot {
@@ -30,8 +30,8 @@ func (op CreateOperation) Apply(snapshot bug.Snapshot) bug.Snapshot {
return snapshot
}
-func (op CreateOperation) Files() []git.Hash {
- return op.files
+func (op CreateOperation) GetFiles() []git.Hash {
+ return op.Files
}
func NewCreateOp(author bug.Person, title, message string, files []git.Hash) CreateOperation {
@@ -39,7 +39,7 @@ func NewCreateOp(author bug.Person, title, message string, files []git.Hash) Cre
OpBase: bug.NewOpBase(bug.CreateOp, author),
Title: title,
Message: message,
- files: files,
+ Files: files,
}
}
diff --git a/operations/label_change.go b/operations/label_change.go
index 551b8be0..26e7e94c 100644
--- a/operations/label_change.go
+++ b/operations/label_change.go
@@ -14,8 +14,8 @@ var _ bug.Operation = LabelChangeOperation{}
// LabelChangeOperation define a Bug operation to add or remove labels
type LabelChangeOperation struct {
bug.OpBase
- Added []bug.Label
- Removed []bug.Label
+ Added []bug.Label `json:"added"`
+ Removed []bug.Label `json:"removed"`
}
// Apply apply the operation
diff --git a/operations/operations.go b/operations/operations.go
index 0bfd3b84..348f8cc8 100644
--- a/operations/operations.go
+++ b/operations/operations.go
@@ -1,12 +1,14 @@
package operations
-import "encoding/gob"
+import (
+ "github.com/MichaelMure/git-bug/bug"
+)
// Package initialisation used to register operation's type for (de)serialization
func init() {
- gob.Register(AddCommentOperation{})
- gob.Register(CreateOperation{})
- gob.Register(SetTitleOperation{})
- gob.Register(SetStatusOperation{})
- gob.Register(LabelChangeOperation{})
+ bug.Register(bug.CreateOp, CreateOperation{})
+ bug.Register(bug.SetTitleOp, SetTitleOperation{})
+ bug.Register(bug.AddCommentOp, AddCommentOperation{})
+ bug.Register(bug.SetStatusOp, SetStatusOperation{})
+ bug.Register(bug.LabelChangeOp, LabelChangeOperation{})
}
diff --git a/operations/set_status.go b/operations/set_status.go
index bafcf5ee..37ebac10 100644
--- a/operations/set_status.go
+++ b/operations/set_status.go
@@ -10,7 +10,7 @@ var _ bug.Operation = SetStatusOperation{}
type SetStatusOperation struct {
bug.OpBase
- Status bug.Status
+ Status bug.Status `json:"status"`
}
func (op SetStatusOperation) Apply(snapshot bug.Snapshot) bug.Snapshot {
diff --git a/operations/set_title.go b/operations/set_title.go
index 5bd6260a..7aa76268 100644
--- a/operations/set_title.go
+++ b/operations/set_title.go
@@ -10,8 +10,8 @@ var _ bug.Operation = SetTitleOperation{}
type SetTitleOperation struct {
bug.OpBase
- Title string
- Was string
+ Title string `json:"title"`
+ Was string `json:"was"`
}
func (op SetTitleOperation) Apply(snapshot bug.Snapshot) bug.Snapshot {
diff --git a/tests/operation_pack_test.go b/tests/operation_pack_test.go
index 35b77a8f..62f406a4 100644
--- a/tests/operation_pack_test.go
+++ b/tests/operation_pack_test.go
@@ -1,30 +1,34 @@
package tests
import (
- "github.com/MichaelMure/git-bug/bug"
+ "encoding/json"
+ "reflect"
"testing"
+
+ "github.com/MichaelMure/git-bug/bug"
)
func TestOperationPackSerialize(t *testing.T) {
- opp := bug.OperationPack{}
+ opp := &bug.OperationPack{}
opp.Append(createOp)
opp.Append(setTitleOp)
opp.Append(addCommentOp)
+ opp.Append(setStatusOp)
+ opp.Append(labelChangeOp)
- data, err := opp.Serialize()
-
+ data, err := json.Marshal(opp)
if err != nil {
t.Fatal(err)
}
- if len(data) == 0 {
- t.Fatal("empty serialized data")
- }
-
- _, err = bug.ParseOperationPack(data)
-
+ var opp2 *bug.OperationPack
+ err = json.Unmarshal(data, &opp2)
if err != nil {
t.Fatal(err)
}
+
+ if !reflect.DeepEqual(opp, opp2) {
+ t.Fatalf("%v and %v are different", opp, opp2)
+ }
}