aboutsummaryrefslogtreecommitdiffstats
path: root/bug
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 /bug
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
Diffstat (limited to 'bug')
-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
4 files changed, 70 insertions, 34 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