aboutsummaryrefslogtreecommitdiffstats
path: root/bug/operation.go
diff options
context:
space:
mode:
Diffstat (limited to 'bug/operation.go')
-rw-r--r--bug/operation.go77
1 files changed, 50 insertions, 27 deletions
diff --git a/bug/operation.go b/bug/operation.go
index a408e167..91b77e56 100644
--- a/bug/operation.go
+++ b/bug/operation.go
@@ -1,11 +1,13 @@
package bug
import (
- "github.com/MichaelMure/git-bug/util/git"
- "github.com/pkg/errors"
-
+ "crypto/sha256"
+ "encoding/json"
"fmt"
"time"
+
+ "github.com/MichaelMure/git-bug/util/git"
+ "github.com/pkg/errors"
)
// OperationType is an operation type identifier
@@ -18,22 +20,23 @@ const (
AddCommentOp
SetStatusOp
LabelChangeOp
+ EditCommentOp
)
// Operation define the interface to fulfill for an edit operation of a Bug
type Operation interface {
- // OpType return the type of operation
- OpType() OperationType
+ // base return the OpBase of the Operation, for package internal use
+ base() *OpBase
+ // Hash return the hash of the operation, to be used for back references
+ Hash() (git.Hash, error)
// Time return the time when the operation was added
Time() time.Time
// GetUnixTime return the unix timestamp when the operation was added
GetUnixTime() int64
- // GetAuthor return the author of the operation
- GetAuthor() Person
// GetFiles return the files needed by this operation
GetFiles() []git.Hash
// Apply the operation to a Snapshot to create the final state
- Apply(snapshot Snapshot) Snapshot
+ Apply(snapshot *Snapshot)
// Validate check if the operation is valid (ex: a title is a single line)
Validate() error
// SetMetadata store arbitrary metadata about the operation
@@ -42,16 +45,42 @@ type Operation interface {
GetMetadata(key string) (string, bool)
}
+func hashRaw(data []byte) git.Hash {
+ hasher := sha256.New()
+ // Write can't fail
+ _, _ = hasher.Write(data)
+ return git.Hash(fmt.Sprintf("%x", hasher.Sum(nil)))
+}
+
+// hash compute the hash of the serialized operation
+func hashOperation(op Operation) (git.Hash, error) {
+ base := op.base()
+
+ if base.hash != "" {
+ return base.hash, nil
+ }
+
+ data, err := json.Marshal(op)
+ if err != nil {
+ return "", err
+ }
+
+ base.hash = hashRaw(data)
+
+ return base.hash, nil
+}
+
// OpBase implement the common code for all operations
type OpBase struct {
- OperationType OperationType `json:"type"`
- Author Person `json:"author"`
- UnixTime int64 `json:"timestamp"`
+ OperationType OperationType `json:"type"`
+ Author Person `json:"author"`
+ UnixTime int64 `json:"timestamp"`
+ hash git.Hash
Metadata map[string]string `json:"metadata,omitempty"`
}
-// NewOpBase is the constructor for an OpBase
-func NewOpBase(opType OperationType, author Person, unixTime int64) *OpBase {
+// newOpBase is the constructor for an OpBase
+func newOpBase(opType OperationType, author Person, unixTime int64) *OpBase {
return &OpBase{
OperationType: opType,
Author: author,
@@ -59,11 +88,6 @@ func NewOpBase(opType OperationType, author Person, unixTime int64) *OpBase {
}
}
-// OpType return the type of operation
-func (op *OpBase) OpType() OperationType {
- return op.OperationType
-}
-
// Time return the time when the operation was added
func (op *OpBase) Time() time.Time {
return time.Unix(op.UnixTime, 0)
@@ -74,27 +98,26 @@ func (op *OpBase) GetUnixTime() int64 {
return op.UnixTime
}
-// GetAuthor return the author of the operation
-func (op *OpBase) GetAuthor() Person {
- return op.Author
-}
-
// GetFiles return the files needed by this operation
func (op *OpBase) GetFiles() []git.Hash {
return nil
}
// Validate check the OpBase for errors
-func OpBaseValidate(op Operation, opType OperationType) error {
- if op.OpType() != opType {
- return fmt.Errorf("incorrect operation type (expected: %v, actual: %v)", opType, op.OpType())
+func opBaseValidate(op Operation, opType OperationType) error {
+ if op.base().OperationType != opType {
+ return fmt.Errorf("incorrect operation type (expected: %v, actual: %v)", opType, op.base().OperationType)
+ }
+
+ if _, err := op.Hash(); err != nil {
+ return errors.Wrap(err, "op is not serializable")
}
if op.GetUnixTime() == 0 {
return fmt.Errorf("time not set")
}
- if err := op.GetAuthor().Validate(); err != nil {
+ if err := op.base().Author.Validate(); err != nil {
return errors.Wrap(err, "author")
}