aboutsummaryrefslogtreecommitdiffstats
path: root/bug/operation.go
diff options
context:
space:
mode:
Diffstat (limited to 'bug/operation.go')
-rw-r--r--bug/operation.go79
1 files changed, 35 insertions, 44 deletions
diff --git a/bug/operation.go b/bug/operation.go
index daef7b8c..dd95e096 100644
--- a/bug/operation.go
+++ b/bug/operation.go
@@ -6,10 +6,11 @@ import (
"fmt"
"time"
- "github.com/MichaelMure/git-bug/identity"
+ "github.com/pkg/errors"
+ "github.com/MichaelMure/git-bug/entity"
+ "github.com/MichaelMure/git-bug/identity"
"github.com/MichaelMure/git-bug/util/git"
- "github.com/pkg/errors"
)
// OperationType is an operation type identifier
@@ -31,8 +32,8 @@ const (
type Operation interface {
// 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)
+ // Id return the identifier of the operation, to be used for back references
+ Id() entity.Id
// Time return the time when the operation was added
Time() time.Time
// GetUnixTime return the unix timestamp when the operation was added
@@ -53,42 +54,42 @@ type Operation interface {
GetAuthor() identity.Interface
}
-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)))
+func deriveId(data []byte) entity.Id {
+ sum := sha256.Sum256(data)
+ return entity.Id(fmt.Sprintf("%x", sum))
}
-// hash compute the hash of the serialized operation
-func hashOperation(op Operation) (git.Hash, error) {
- // TODO: this might not be the best idea: if a single bit change in the output of json.Marshal, this will break.
- // Idea: hash the segment of serialized data (= immutable) instead of the go object in memory
-
+func idOperation(op Operation) entity.Id {
base := op.base()
- if base.hash != "" {
- return base.hash, nil
+ if base.id == "" {
+ // something went really wrong
+ panic("op's id not set")
}
+ if base.id == entity.UnsetId {
+ // This means we are trying to get the op's Id *before* it has been stored, for instance when
+ // adding multiple ops in one go in an OperationPack.
+ // As the Id is computed based on the actual bytes written on the disk, we are going to predict
+ // those and then get the Id. This is safe as it will be the exact same code writing on disk later.
+
+ data, err := json.Marshal(op)
+ if err != nil {
+ panic(err)
+ }
- data, err := json.Marshal(op)
- if err != nil {
- return "", err
+ base.id = deriveId(data)
}
-
- base.hash = hashRaw(data)
-
- return base.hash, nil
+ return base.id
}
// OpBase implement the common code for all operations
type OpBase struct {
- OperationType OperationType
- Author identity.Interface
- UnixTime int64
- Metadata map[string]string
- // Not serialized. Store the op's hash in memory.
- hash git.Hash
+ OperationType OperationType `json:"type"`
+ Author identity.Interface `json:"author"`
+ UnixTime int64 `json:"timestamp"`
+ Metadata map[string]string `json:"metadata,omitempty"`
+ // Not serialized. Store the op's id in memory.
+ id entity.Id
// Not serialized. Store the extra metadata in memory,
// compiled from SetMetadataOperation.
extraMetadata map[string]string
@@ -100,24 +101,14 @@ func newOpBase(opType OperationType, author identity.Interface, unixTime int64)
OperationType: opType,
Author: author,
UnixTime: unixTime,
+ id: entity.UnsetId,
}
}
-func (op OpBase) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- OperationType OperationType `json:"type"`
- Author identity.Interface `json:"author"`
- UnixTime int64 `json:"timestamp"`
- Metadata map[string]string `json:"metadata,omitempty"`
- }{
- OperationType: op.OperationType,
- Author: op.Author,
- UnixTime: op.UnixTime,
- Metadata: op.Metadata,
- })
-}
-
func (op *OpBase) UnmarshalJSON(data []byte) error {
+ // Compute the Id when loading the op from disk.
+ op.id = deriveId(data)
+
aux := struct {
OperationType OperationType `json:"type"`
Author json.RawMessage `json:"author"`
@@ -192,7 +183,7 @@ func (op *OpBase) SetMetadata(key string, value string) {
}
op.Metadata[key] = value
- op.hash = ""
+ op.id = entity.UnsetId
}
// GetMetadata retrieve arbitrary metadata about the operation