aboutsummaryrefslogtreecommitdiffstats
path: root/repository
diff options
context:
space:
mode:
authorMichael Muré <batolettre@gmail.com>2018-08-06 20:31:20 +0200
committerMichael Muré <batolettre@gmail.com>2018-08-06 20:31:20 +0200
commit435be2b693aee89ed34a2d1e7291b3b141b19717 (patch)
tree89244a9dcb995c27002995e9f25f9be631101713 /repository
parent593891b8e01fd89866b30854a60aece1dad5f6ab (diff)
downloadgit-bug-435be2b693aee89ed34a2d1e7291b3b141b19717.tar.gz
bug: add a Lamport logical clock to be able to sort bugs by creation time and edit time without having to rely on a timestamp
Diffstat (limited to 'repository')
-rw-r--r--repository/git.go97
-rw-r--r--repository/mock_repo.go46
-rw-r--r--repository/repo.go12
3 files changed, 144 insertions, 11 deletions
diff --git a/repository/git.go b/repository/git.go
index aa0e72b7..5748d52a 100644
--- a/repository/git.go
+++ b/repository/git.go
@@ -3,18 +3,27 @@ package repository
import (
"bytes"
+ "errors"
"fmt"
"io"
"os"
"os/exec"
+ "path"
"strings"
"github.com/MichaelMure/git-bug/util"
)
+const createClockFile = "/.git/git-bug/create-clock"
+const editClockFile = "/.git/git-bug/edit-clock"
+
+var ErrNotARepo = errors.New("not a git repository")
+
// GitRepo represents an instance of a (local) git repository.
type GitRepo struct {
- Path string
+ Path string
+ createClock *util.PersistedLamport
+ editClock *util.PersistedLamport
}
// Run the given git command with the given I/O reader/writers, returning an error if it fails.
@@ -62,35 +71,62 @@ func (repo *GitRepo) runGitCommandInline(args ...string) error {
// NewGitRepo determines if the given working directory is inside of a git repository,
// and returns the corresponding GitRepo instance if it is.
-func NewGitRepo(path string) (*GitRepo, error) {
+func NewGitRepo(path string, witnesser func(repo *GitRepo) error) (*GitRepo, error) {
repo := &GitRepo{Path: path}
+
+ // Check the repo and retrieve the root path
stdout, err := repo.runGitCommand("rev-parse", "--show-toplevel")
if err != nil {
- return nil, err
+ return nil, ErrNotARepo
}
// Fix the path to be sure we are at the root
repo.Path = stdout
+ err = repo.LoadClocks()
+
+ if err != nil {
+ // No clock yet, trying to initialize them
+ repo.createClocks()
+
+ err = witnesser(repo)
+ if err != nil {
+ return nil, err
+ }
+
+ err = repo.WriteClocks()
+ if err != nil {
+ return nil, err
+ }
+
+ return repo, nil
+ }
+
return repo, nil
}
func InitGitRepo(path string) (*GitRepo, error) {
repo := &GitRepo{Path: path}
+ repo.createClocks()
+
_, err := repo.runGitCommand("init", path)
if err != nil {
return nil, err
}
+
return repo, nil
}
func InitBareGitRepo(path string) (*GitRepo, error) {
repo := &GitRepo{Path: path}
+ repo.createClocks()
+
_, err := repo.runGitCommand("init", "--bare", path)
if err != nil {
return nil, err
}
+
return repo, nil
}
@@ -308,8 +344,63 @@ func (repo *GitRepo) GetTreeHash(commit util.Hash) (util.Hash, error) {
}
// Add a new remote to the repository
+// Not in the interface because it's only used for testing
func (repo *GitRepo) AddRemote(name string, url string) error {
_, err := repo.runGitCommand("remote", "add", name, url)
return err
}
+
+func (repo *GitRepo) createClocks() {
+ createPath := path.Join(repo.Path, createClockFile)
+ repo.createClock = util.NewPersistedLamport(createPath)
+
+ editPath := path.Join(repo.Path, editClockFile)
+ repo.editClock = util.NewPersistedLamport(editPath)
+}
+
+func (repo *GitRepo) LoadClocks() error {
+ createClock, err := util.LoadPersistedLamport(repo.GetPath() + createClockFile)
+ if err != nil {
+ return err
+ }
+
+ editClock, err := util.LoadPersistedLamport(repo.GetPath() + editClockFile)
+ if err != nil {
+ return err
+ }
+
+ repo.createClock = createClock
+ repo.editClock = editClock
+ return nil
+}
+
+func (repo *GitRepo) WriteClocks() error {
+ err := repo.createClock.Write()
+ if err != nil {
+ return err
+ }
+
+ err = repo.editClock.Write()
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (repo *GitRepo) CreateTimeIncrement() (util.LamportTime, error) {
+ return repo.createClock.Increment()
+}
+
+func (repo *GitRepo) EditTimeIncrement() (util.LamportTime, error) {
+ return repo.editClock.Increment()
+}
+
+func (repo *GitRepo) CreateWitness(time util.LamportTime) error {
+ return repo.createClock.Witness(time)
+}
+
+func (repo *GitRepo) EditWitness(time util.LamportTime) error {
+ return repo.editClock.Witness(time)
+}
diff --git a/repository/mock_repo.go b/repository/mock_repo.go
index f8653c64..eb48f85f 100644
--- a/repository/mock_repo.go
+++ b/repository/mock_repo.go
@@ -10,10 +10,12 @@ import (
// mockRepoForTest defines an instance of Repo that can be used for testing.
type mockRepoForTest struct {
- blobs map[util.Hash][]byte
- trees map[util.Hash]string
- commits map[util.Hash]commit
- refs map[string]util.Hash
+ blobs map[util.Hash][]byte
+ trees map[util.Hash]string
+ commits map[util.Hash]commit
+ refs map[string]util.Hash
+ createClock util.LamportClock
+ editClock util.LamportClock
}
type commit struct {
@@ -23,10 +25,12 @@ type commit struct {
func NewMockRepoForTest() Repo {
return &mockRepoForTest{
- blobs: make(map[util.Hash][]byte),
- trees: make(map[util.Hash]string),
- commits: make(map[util.Hash]commit),
- refs: make(map[string]util.Hash),
+ blobs: make(map[util.Hash][]byte),
+ trees: make(map[util.Hash]string),
+ commits: make(map[util.Hash]commit),
+ refs: make(map[string]util.Hash),
+ createClock: util.NewLamportClock(),
+ editClock: util.NewLamportClock(),
}
}
@@ -200,3 +204,29 @@ func (r *mockRepoForTest) FindCommonAncestor(hash1 util.Hash, hash2 util.Hash) (
func (r *mockRepoForTest) GetTreeHash(commit util.Hash) (util.Hash, error) {
panic("implement me")
}
+
+func (r *mockRepoForTest) LoadClocks() error {
+ return nil
+}
+
+func (r *mockRepoForTest) WriteClocks() error {
+ return nil
+}
+
+func (r *mockRepoForTest) CreateTimeIncrement() (util.LamportTime, error) {
+ return r.createClock.Increment(), nil
+}
+
+func (r *mockRepoForTest) EditTimeIncrement() (util.LamportTime, error) {
+ return r.editClock.Increment(), nil
+}
+
+func (r *mockRepoForTest) CreateWitness(time util.LamportTime) error {
+ r.createClock.Witness(time)
+ return nil
+}
+
+func (r *mockRepoForTest) EditWitness(time util.LamportTime) error {
+ r.editClock.Witness(time)
+ return nil
+}
diff --git a/repository/repo.go b/repository/repo.go
index 38d8a6cb..057223ad 100644
--- a/repository/repo.go
+++ b/repository/repo.go
@@ -69,6 +69,18 @@ type Repo interface {
// Return the git tree hash referenced in a commit
GetTreeHash(commit util.Hash) (util.Hash, error)
+
+ LoadClocks() error
+
+ WriteClocks() error
+
+ CreateTimeIncrement() (util.LamportTime, error)
+
+ EditTimeIncrement() (util.LamportTime, error)
+
+ CreateWitness(time util.LamportTime) error
+
+ EditWitness(time util.LamportTime) error
}
func prepareTreeEntries(entries []TreeEntry) bytes.Buffer {