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