diff options
author | Michael Muré <batolettre@gmail.com> | 2018-09-12 16:57:04 +0200 |
---|---|---|
committer | Michael Muré <batolettre@gmail.com> | 2018-09-12 16:57:46 +0200 |
commit | 60fcfcdcb0e89741528cfc99a94a48f204d48e6b (patch) | |
tree | 48189b7f85e10b1bdf6a4b897ac0b966c4cec23c | |
parent | 3605887345792d2f981f971c6c4a2cb7f86a343e (diff) | |
download | git-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.go | 10 | ||||
-rw-r--r-- | bug/operation.go | 14 | ||||
-rw-r--r-- | bug/operation_pack.go | 76 | ||||
-rw-r--r-- | bug/person.go | 4 | ||||
-rw-r--r-- | graphql/graph/gen_graph.go | 4 | ||||
-rw-r--r-- | operations/add_comment.go | 12 | ||||
-rw-r--r-- | operations/create.go | 12 | ||||
-rw-r--r-- | operations/label_change.go | 4 | ||||
-rw-r--r-- | operations/operations.go | 14 | ||||
-rw-r--r-- | operations/set_status.go | 2 | ||||
-rw-r--r-- | operations/set_title.go | 4 | ||||
-rw-r--r-- | tests/operation_pack_test.go | 24 |
12 files changed, 111 insertions, 69 deletions
@@ -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) + } } |