diff options
Diffstat (limited to 'repository')
-rw-r--r-- | repository/git.go | 132 | ||||
-rw-r--r-- | repository/git_testing.go | 6 | ||||
-rw-r--r-- | repository/gogit.go | 227 | ||||
-rw-r--r-- | repository/gogit_config.go | 6 | ||||
-rw-r--r-- | repository/gogit_test.go | 6 | ||||
-rw-r--r-- | repository/gogit_testing.go | 6 | ||||
-rw-r--r-- | repository/keyring.go | 4 | ||||
-rw-r--r-- | repository/mock_repo.go | 84 | ||||
-rw-r--r-- | repository/repo.go | 36 | ||||
-rw-r--r-- | repository/repo_testing.go | 28 |
10 files changed, 403 insertions, 132 deletions
diff --git a/repository/git.go b/repository/git.go index 504cdd89..bc9d8772 100644 --- a/repository/git.go +++ b/repository/git.go @@ -4,10 +4,15 @@ package repository import ( "bytes" "fmt" - "path" + "os" + "path/filepath" "strings" "sync" + "github.com/blevesearch/bleve" + "github.com/go-git/go-billy/v5" + "github.com/go-git/go-billy/v5/osfs" + "github.com/MichaelMure/git-bug/util/lamport" ) @@ -26,12 +31,15 @@ type GitRepo struct { clocksMutex sync.Mutex clocks map[string]lamport.Clock + indexesMutex sync.Mutex + indexes map[string]bleve.Index + keyring Keyring } -// NewGitRepo determines if the given working directory is inside of a git repository, +// OpenGitRepo 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, clockLoaders []ClockLoader) (*GitRepo, error) { +func OpenGitRepo(path string, clockLoaders []ClockLoader) (*GitRepo, error) { k, err := defaultKeyring() if err != nil { return nil, err @@ -41,6 +49,7 @@ func NewGitRepo(path string, clockLoaders []ClockLoader) (*GitRepo, error) { gitCli: gitCli{path: path}, path: path, clocks: make(map[string]lamport.Clock), + indexes: make(map[string]bleve.Index), keyring: k, } @@ -80,9 +89,10 @@ func NewGitRepo(path string, clockLoaders []ClockLoader) (*GitRepo, error) { // InitGitRepo create a new empty git repo at the given path func InitGitRepo(path string) (*GitRepo, error) { repo := &GitRepo{ - gitCli: gitCli{path: path}, - path: path + "/.git", - clocks: make(map[string]lamport.Clock), + gitCli: gitCli{path: path}, + path: path + "/.git", + clocks: make(map[string]lamport.Clock), + indexes: make(map[string]bleve.Index), } _, err := repo.runGitCommand("init", path) @@ -96,9 +106,10 @@ func InitGitRepo(path string) (*GitRepo, error) { // InitBareGitRepo create a new --bare empty git repo at the given path func InitBareGitRepo(path string) (*GitRepo, error) { repo := &GitRepo{ - gitCli: gitCli{path: path}, - path: path, - clocks: make(map[string]lamport.Clock), + gitCli: gitCli{path: path}, + path: path, + clocks: make(map[string]lamport.Clock), + indexes: make(map[string]bleve.Index), } _, err := repo.runGitCommand("init", "--bare", path) @@ -109,6 +120,17 @@ func InitBareGitRepo(path string) (*GitRepo, error) { return repo, nil } +func (repo *GitRepo) Close() error { + var firstErr error + for _, index := range repo.indexes { + err := index.Close() + if err != nil && firstErr == nil { + firstErr = err + } + } + return firstErr +} + // LocalConfig give access to the repository scoped configuration func (repo *GitRepo) LocalConfig() Config { return newGitConfig(repo.gitCli, false) @@ -174,6 +196,63 @@ func (repo *GitRepo) GetRemotes() (map[string]string, error) { return remotes, nil } +// LocalStorage return a billy.Filesystem giving access to $RepoPath/.git/git-bug +func (repo *GitRepo) LocalStorage() billy.Filesystem { + return osfs.New(repo.path) +} + +// GetBleveIndex return a bleve.Index that can be used to index documents +func (repo *GitRepo) GetBleveIndex(name string) (bleve.Index, error) { + repo.indexesMutex.Lock() + defer repo.indexesMutex.Unlock() + + if index, ok := repo.indexes[name]; ok { + return index, nil + } + + path := filepath.Join(repo.path, "indexes", name) + + index, err := bleve.Open(path) + if err == nil { + repo.indexes[name] = index + return index, nil + } + + err = os.MkdirAll(path, os.ModeDir) + if err != nil { + return nil, err + } + + mapping := bleve.NewIndexMapping() + mapping.DefaultAnalyzer = "en" + + index, err = bleve.New(path, mapping) + if err != nil { + return nil, err + } + + repo.indexes[name] = index + + return index, nil +} + +// ClearBleveIndex will wipe the given index +func (repo *GitRepo) ClearBleveIndex(name string) error { + repo.indexesMutex.Lock() + defer repo.indexesMutex.Unlock() + + path := filepath.Join(repo.path, "indexes", name) + + err := os.RemoveAll(path) + if err != nil { + return err + } + + delete(repo.indexes, name) + + return nil +} + // FetchRefs fetch git refs from a remote func (repo *GitRepo) FetchRefs(remote, refSpec string) (string, error) { stdout, err := repo.runGitCommand("fetch", remote, refSpec) @@ -358,6 +437,9 @@ func (repo *GitRepo) GetTreeHash(commit Hash) (Hash, error) { // GetOrCreateClock return a Lamport clock stored in the Repo. // If the clock doesn't exist, it's created. func (repo *GitRepo) GetOrCreateClock(name string) (lamport.Clock, error) { + repo.clocksMutex.Lock() + defer repo.clocksMutex.Unlock() + c, err := repo.getClock(name) if err == nil { return c, nil @@ -366,12 +448,7 @@ func (repo *GitRepo) GetOrCreateClock(name string) (lamport.Clock, error) { return nil, err } - repo.clocksMutex.Lock() - defer repo.clocksMutex.Unlock() - - p := path.Join(repo.path, clockPath, name+"-clock") - - c, err = lamport.NewPersistedClock(p) + c, err = lamport.NewPersistedClock(repo.LocalStorage(), name+"-clock") if err != nil { return nil, err } @@ -381,16 +458,11 @@ func (repo *GitRepo) GetOrCreateClock(name string) (lamport.Clock, error) { } func (repo *GitRepo) getClock(name string) (lamport.Clock, error) { - repo.clocksMutex.Lock() - defer repo.clocksMutex.Unlock() - if c, ok := repo.clocks[name]; ok { return c, nil } - p := path.Join(repo.path, clockPath, name+"-clock") - - c, err := lamport.LoadPersistedClock(p) + c, err := lamport.LoadPersistedClock(repo.LocalStorage(), name+"-clock") if err == nil { repo.clocks[name] = c return c, nil @@ -408,3 +480,21 @@ func (repo *GitRepo) AddRemote(name string, url string) error { return err } + +// GetLocalRemote return the URL to use to add this repo as a local remote +func (repo *GitRepo) GetLocalRemote() string { + return repo.path +} + +// EraseFromDisk delete this repository entirely from the disk +func (repo *GitRepo) EraseFromDisk() error { + err := repo.Close() + if err != nil { + return err + } + + path := filepath.Clean(strings.TrimSuffix(repo.path, string(filepath.Separator)+".git")) + + // fmt.Println("Cleaning repo:", path) + return os.RemoveAll(path) +} diff --git a/repository/git_testing.go b/repository/git_testing.go index 874cc86c..2168d53e 100644 --- a/repository/git_testing.go +++ b/repository/git_testing.go @@ -48,14 +48,12 @@ func SetupReposAndRemote() (repoA, repoB, remote TestedRepo) { repoB = CreateGoGitTestRepo(false) remote = CreateGoGitTestRepo(true) - remoteAddr := "file://" + remote.GetPath() - - err := repoA.AddRemote("origin", remoteAddr) + err := repoA.AddRemote("origin", remote.GetLocalRemote()) if err != nil { log.Fatal(err) } - err = repoB.AddRemote("origin", remoteAddr) + err = repoB.AddRemote("origin", remote.GetLocalRemote()) if err != nil { log.Fatal(err) } diff --git a/repository/gogit.go b/repository/gogit.go index c59409d4..bdac259d 100644 --- a/repository/gogit.go +++ b/repository/gogit.go @@ -6,13 +6,15 @@ import ( "io/ioutil" "os" "os/exec" - stdpath "path" "path/filepath" "sort" "strings" "sync" "time" + "github.com/blevesearch/bleve" + "github.com/go-git/go-billy/v5" + "github.com/go-git/go-billy/v5/osfs" gogit "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/config" "github.com/go-git/go-git/v5/plumbing" @@ -23,6 +25,7 @@ import ( ) var _ ClockedRepo = &GoGitRepo{} +var _ TestedRepo = &GoGitRepo{} type GoGitRepo struct { r *gogit.Repository @@ -31,10 +34,15 @@ type GoGitRepo struct { clocksMutex sync.Mutex clocks map[string]lamport.Clock - keyring Keyring + indexesMutex sync.Mutex + indexes map[string]bleve.Index + + keyring Keyring + localStorage billy.Filesystem } -func NewGoGitRepo(path string, clockLoaders []ClockLoader) (*GoGitRepo, error) { +// OpenGoGitRepo open an already existing repo at the given path +func OpenGoGitRepo(path string, clockLoaders []ClockLoader) (*GoGitRepo, error) { path, err := detectGitPath(path) if err != nil { return nil, err @@ -51,10 +59,12 @@ func NewGoGitRepo(path string, clockLoaders []ClockLoader) (*GoGitRepo, error) { } repo := &GoGitRepo{ - r: r, - path: path, - clocks: make(map[string]lamport.Clock), - keyring: k, + r: r, + path: path, + clocks: make(map[string]lamport.Clock), + indexes: make(map[string]bleve.Index), + keyring: k, + localStorage: osfs.New(filepath.Join(path, "git-bug")), } for _, loader := range clockLoaders { @@ -76,6 +86,50 @@ func NewGoGitRepo(path string, clockLoaders []ClockLoader) (*GoGitRepo, error) { return repo, nil } +// InitGoGitRepo create a new empty git repo at the given path +func InitGoGitRepo(path string) (*GoGitRepo, error) { + r, err := gogit.PlainInit(path, false) + if err != nil { + return nil, err + } + + k, err := defaultKeyring() + if err != nil { + return nil, err + } + + return &GoGitRepo{ + r: r, + path: filepath.Join(path, ".git"), + clocks: make(map[string]lamport.Clock), + indexes: make(map[string]bleve.Index), + keyring: k, + localStorage: osfs.New(filepath.Join(path, ".git", "git-bug")), + }, nil +} + +// InitBareGoGitRepo create a new --bare empty git repo at the given path +func InitBareGoGitRepo(path string) (*GoGitRepo, error) { + r, err := gogit.PlainInit(path, true) + if err != nil { + return nil, err + } + + k, err := defaultKeyring() + if err != nil { + return nil, err + } + + return &GoGitRepo{ + r: r, + path: path, + clocks: make(map[string]lamport.Clock), + indexes: make(map[string]bleve.Index), + keyring: k, + localStorage: osfs.New(filepath.Join(path, "git-bug")), + }, nil +} + func detectGitPath(path string) (string, error) { // normalize the path path, err := filepath.Abs(path) @@ -84,12 +138,12 @@ func detectGitPath(path string) (string, error) { } for { - fi, err := os.Stat(stdpath.Join(path, ".git")) + fi, err := os.Stat(filepath.Join(path, ".git")) if err == nil { if !fi.IsDir() { return "", fmt.Errorf(".git exist but is not a directory") } - return stdpath.Join(path, ".git"), nil + return filepath.Join(path, ".git"), nil } if !os.IsNotExist(err) { // unknown error @@ -117,7 +171,7 @@ func isGitDir(path string) (bool, error) { markers := []string{"HEAD", "objects", "refs"} for _, marker := range markers { - _, err := os.Stat(stdpath.Join(path, marker)) + _, err := os.Stat(filepath.Join(path, marker)) if err == nil { continue } @@ -132,44 +186,15 @@ func isGitDir(path string) (bool, error) { return true, nil } -// InitGoGitRepo create a new empty git repo at the given path -func InitGoGitRepo(path string) (*GoGitRepo, error) { - r, err := gogit.PlainInit(path, false) - if err != nil { - return nil, err - } - - k, err := defaultKeyring() - if err != nil { - return nil, err - } - - return &GoGitRepo{ - r: r, - path: path + "/.git", - clocks: make(map[string]lamport.Clock), - keyring: k, - }, nil -} - -// InitBareGoGitRepo create a new --bare empty git repo at the given path -func InitBareGoGitRepo(path string) (*GoGitRepo, error) { - r, err := gogit.PlainInit(path, true) - if err != nil { - return nil, err - } - - k, err := defaultKeyring() - if err != nil { - return nil, err +func (repo *GoGitRepo) Close() error { + var firstErr error + for _, index := range repo.indexes { + err := index.Close() + if err != nil && firstErr == nil { + firstErr = err + } } - - return &GoGitRepo{ - r: r, - path: path, - clocks: make(map[string]lamport.Clock), - keyring: k, - }, nil + return firstErr } // LocalConfig give access to the repository scoped configuration @@ -179,10 +204,7 @@ func (repo *GoGitRepo) LocalConfig() Config { // GlobalConfig give access to the global scoped configuration func (repo *GoGitRepo) GlobalConfig() Config { - // TODO: replace that with go-git native implementation once it's supported - // see: https://github.com/go-git/go-git - // see: https://github.com/src-d/go-git/issues/760 - return newGoGitGlobalConfig(repo.r) + return newGoGitGlobalConfig() } // AnyConfig give access to a merged local/global configuration @@ -195,11 +217,6 @@ func (repo *GoGitRepo) Keyring() Keyring { return repo.keyring } -// GetPath returns the path to the repo. -func (repo *GoGitRepo) GetPath() string { - return repo.path -} - // GetUserName returns the name the the user has used to configure git func (repo *GoGitRepo) GetUserName() (string, error) { return repo.AnyConfig().ReadString("user.name") @@ -270,6 +287,69 @@ func (repo *GoGitRepo) GetRemotes() (map[string]string, error) { return result, nil } +// LocalStorage return a billy.Filesystem giving access to $RepoPath/.git/git-bug +func (repo *GoGitRepo) LocalStorage() billy.Filesystem { + return repo.localStorage +} + +// GetBleveIndex return a bleve.Index that can be used to index documents +func (repo *GoGitRepo) GetBleveIndex(name string) (bleve.Index, error) { + repo.indexesMutex.Lock() + defer repo.indexesMutex.Unlock() + + if index, ok := repo.indexes[name]; ok { + return index, nil + } + + path := filepath.Join(repo.path, "git-bug", "indexes", name) + + index, err := bleve.Open(path) + if err == nil { + repo.indexes[name] = index + return index, nil + } + + err = os.MkdirAll(path, os.ModePerm) + if err != nil { + return nil, err + } + + mapping := bleve.NewIndexMapping() + mapping.DefaultAnalyzer = "en" + + index, err = bleve.New(path, mapping) + if err != nil { + return nil, err + } + + repo.indexes[name] = index + + return index, nil +} + +// ClearBleveIndex will wipe the given index +func (repo *GoGitRepo) ClearBleveIndex(name string) error { + repo.indexesMutex.Lock() + defer repo.indexesMutex.Unlock() + + path := filepath.Join(repo.path, "indexes", name) + + err := os.RemoveAll(path) + if err != nil { + return err + } + + if index, ok := repo.indexes[name]; ok { + err = index.Close() + if err != nil { + return err + } + delete(repo.indexes, name) + } + + return nil +} + // FetchRefs fetch git refs from a remote func (repo *GoGitRepo) FetchRefs(remote string, refSpec string) (string, error) { buf := bytes.NewBuffer(nil) @@ -600,6 +680,9 @@ func (repo *GoGitRepo) ListCommits(ref string) ([]Hash, error) { // GetOrCreateClock return a Lamport clock stored in the Repo. // If the clock doesn't exist, it's created. func (repo *GoGitRepo) GetOrCreateClock(name string) (lamport.Clock, error) { + repo.clocksMutex.Lock() + defer repo.clocksMutex.Unlock() + c, err := repo.getClock(name) if err == nil { return c, nil @@ -608,12 +691,7 @@ func (repo *GoGitRepo) GetOrCreateClock(name string) (lamport.Clock, error) { return nil, err } - repo.clocksMutex.Lock() - defer repo.clocksMutex.Unlock() - - p := stdpath.Join(repo.path, clockPath, name+"-clock") - - c, err = lamport.NewPersistedClock(p) + c, err = lamport.NewPersistedClock(repo.localStorage, name+"-clock") if err != nil { return nil, err } @@ -623,16 +701,11 @@ func (repo *GoGitRepo) GetOrCreateClock(name string) (lamport.Clock, error) { } func (repo *GoGitRepo) getClock(name string) (lamport.Clock, error) { - repo.clocksMutex.Lock() - defer repo.clocksMutex.Unlock() - if c, ok := repo.clocks[name]; ok { return c, nil } - p := stdpath.Join(repo.path, clockPath, name+"-clock") - - c, err := lamport.LoadPersistedClock(p) + c, err := lamport.LoadPersistedClock(repo.localStorage, name+"-clock") if err == nil { repo.clocks[name] = c return c, nil @@ -653,3 +726,21 @@ func (repo *GoGitRepo) AddRemote(name string, url string) error { return err } + +// GetLocalRemote return the URL to use to add this repo as a local remote +func (repo *GoGitRepo) GetLocalRemote() string { + return repo.path +} + +// EraseFromDisk delete this repository entirely from the disk +func (repo *GoGitRepo) EraseFromDisk() error { + err := repo.Close() + if err != nil { + return err + } + + path := filepath.Clean(strings.TrimSuffix(repo.path, string(filepath.Separator)+".git")) + + // fmt.Println("Cleaning repo:", path) + return os.RemoveAll(path) +} diff --git a/repository/gogit_config.go b/repository/gogit_config.go index 2f9a4cc3..ba61adca 100644 --- a/repository/gogit_config.go +++ b/repository/gogit_config.go @@ -24,7 +24,11 @@ func newGoGitLocalConfig(repo *gogit.Repository) *goGitConfig { } } -func newGoGitGlobalConfig(repo *gogit.Repository) *goGitConfig { +func newGoGitGlobalConfig() *goGitConfig { + // TODO: replace that with go-git native implementation once it's supported + // see: https://github.com/go-git/go-git + // see: https://github.com/src-d/go-git/issues/760 + return &goGitConfig{ ConfigRead: &goGitConfigReader{getConfig: func() (*config.Config, error) { return config.LoadConfig(config.GlobalScope) diff --git a/repository/gogit_test.go b/repository/gogit_test.go index fba990d3..a2bb49b9 100644 --- a/repository/gogit_test.go +++ b/repository/gogit_test.go @@ -19,7 +19,7 @@ func TestNewGoGitRepo(t *testing.T) { _, err = InitGoGitRepo(plainRoot) require.NoError(t, err) - plainGitDir := path.Join(plainRoot, ".git") + plainGitDir := filepath.Join(plainRoot, ".git") // Bare bareRoot, err := ioutil.TempDir("", "") @@ -52,13 +52,13 @@ func TestNewGoGitRepo(t *testing.T) { } for i, tc := range tests { - r, err := NewGoGitRepo(tc.inPath, nil) + r, err := OpenGoGitRepo(tc.inPath, nil) if tc.err { require.Error(t, err, i) } else { require.NoError(t, err, i) - assert.Equal(t, filepath.ToSlash(tc.outPath), filepath.ToSlash(r.GetPath()), i) + assert.Equal(t, filepath.ToSlash(tc.outPath), filepath.ToSlash(r.path), i) } } } diff --git a/repository/gogit_testing.go b/repository/gogit_testing.go index f20ff6be..a8bff41e 100644 --- a/repository/gogit_testing.go +++ b/repository/gogit_testing.go @@ -42,14 +42,12 @@ func SetupGoGitReposAndRemote() (repoA, repoB, remote TestedRepo) { repoB = CreateGoGitTestRepo(false) remote = CreateGoGitTestRepo(true) - remoteAddr := "file://" + remote.GetPath() - - err := repoA.AddRemote("origin", remoteAddr) + err := repoA.AddRemote("origin", remote.GetLocalRemote()) if err != nil { log.Fatal(err) } - err = repoB.AddRemote("origin", remoteAddr) + err = repoB.AddRemote("origin", remote.GetLocalRemote()) if err != nil { log.Fatal(err) } diff --git a/repository/keyring.go b/repository/keyring.go index f690b0b3..4cb3c9ff 100644 --- a/repository/keyring.go +++ b/repository/keyring.go @@ -2,7 +2,7 @@ package repository import ( "os" - "path" + "path/filepath" "github.com/99designs/keyring" ) @@ -38,7 +38,7 @@ func defaultKeyring() (Keyring, error) { ServiceName: "git-bug", // Fallback encrypted file - FileDir: path.Join(ucd, "git-bug", "keyring"), + FileDir: filepath.Join(ucd, "git-bug", "keyring"), // As we write the file in the user's config directory, this file should already be protected by the OS against // other user's access. We actually don't terribly need to protect it further and a password prompt across all // UI's would be a pain. Therefore we use here a constant password so the file will be unreadable by generic file diff --git a/repository/mock_repo.go b/repository/mock_repo.go index 628939aa..8a1724ef 100644 --- a/repository/mock_repo.go +++ b/repository/mock_repo.go @@ -4,8 +4,12 @@ import ( "crypto/sha1" "fmt" "strings" + "sync" "github.com/99designs/keyring" + "github.com/blevesearch/bleve" + "github.com/go-git/go-billy/v5" + "github.com/go-git/go-billy/v5/memfs" "github.com/MichaelMure/git-bug/util/lamport" ) @@ -18,15 +22,21 @@ type mockRepoForTest struct { *mockRepoConfig *mockRepoKeyring *mockRepoCommon + *mockRepoStorage + *mockRepoBleve *mockRepoData *mockRepoClock } +func (m *mockRepoForTest) Close() error { return nil } + func NewMockRepoForTest() *mockRepoForTest { return &mockRepoForTest{ mockRepoConfig: NewMockRepoConfig(), mockRepoKeyring: NewMockRepoKeyring(), mockRepoCommon: NewMockRepoCommon(), + mockRepoStorage: NewMockRepoStorage(), + mockRepoBleve: newMockRepoBleve(), mockRepoData: NewMockRepoData(), mockRepoClock: NewMockRepoClock(), } @@ -86,11 +96,6 @@ func NewMockRepoCommon() *mockRepoCommon { return &mockRepoCommon{} } -// GetPath returns the path to the repo. -func (r *mockRepoCommon) GetPath() string { - return "~/mockRepo/" -} - func (r *mockRepoCommon) GetUserName() (string, error) { return "René Descartes", nil } @@ -112,6 +117,62 @@ func (r *mockRepoCommon) GetRemotes() (map[string]string, error) { }, nil } +var _ RepoStorage = &mockRepoStorage{} + +type mockRepoStorage struct { + localFs billy.Filesystem +} + +func NewMockRepoStorage() *mockRepoStorage { + return &mockRepoStorage{localFs: memfs.New()} +} + +func (m *mockRepoStorage) LocalStorage() billy.Filesystem { + return m.localFs +} + +var _ RepoBleve = &mockRepoBleve{} + +type mockRepoBleve struct { + indexesMutex sync.Mutex + indexes map[string]bleve.Index +} + +func newMockRepoBleve() *mockRepoBleve { + return &mockRepoBleve{ + indexes: make(map[string]bleve.Index), + } +} + +func (m *mockRepoBleve) GetBleveIndex(name string) (bleve.Index, error) { + m.indexesMutex.Lock() + defer m.indexesMutex.Unlock() + + if index, ok := m.indexes[name]; ok { + return index, nil + } + + mapping := bleve.NewIndexMapping() + mapping.DefaultAnalyzer = "en" + + index, err := bleve.NewMemOnly(mapping) + if err != nil { + return nil, err + } + + m.indexes[name] = index + + return index, nil +} + +func (m *mockRepoBleve) ClearBleveIndex(name string) error { + m.indexesMutex.Lock() + defer m.indexesMutex.Unlock() + + delete(m.indexes, name) + return nil +} + var _ RepoData = &mockRepoData{} type commit struct { @@ -314,7 +375,17 @@ func (r *mockRepoData) AddRemote(name string, url string) error { panic("implement me") } +func (m mockRepoForTest) GetLocalRemote() string { + panic("implement me") +} + +func (m mockRepoForTest) EraseFromDisk() error { + // nothing to do + return nil +} + type mockRepoClock struct { + mu sync.Mutex clocks map[string]lamport.Clock } @@ -325,6 +396,9 @@ func NewMockRepoClock() *mockRepoClock { } func (r *mockRepoClock) GetOrCreateClock(name string) (lamport.Clock, error) { + r.mu.Lock() + defer r.mu.Unlock() + if c, ok := r.clocks[name]; ok { return c, nil } diff --git a/repository/repo.go b/repository/repo.go index 4b45a1c5..eb9296d4 100644 --- a/repository/repo.go +++ b/repository/repo.go @@ -4,6 +4,9 @@ package repository import ( "errors" + "github.com/blevesearch/bleve" + "github.com/go-git/go-billy/v5" + "github.com/MichaelMure/git-bug/util/lamport" ) @@ -20,6 +23,15 @@ type Repo interface { RepoKeyring RepoCommon RepoData + RepoStorage + RepoBleve + + Close() error +} + +type RepoCommonStorage interface { + RepoCommon + RepoStorage } // ClockedRepo is a Repo that also has Lamport clocks @@ -48,9 +60,6 @@ type RepoKeyring interface { // RepoCommon represent the common function the we want all the repo to implement type RepoCommon interface { - // GetPath returns the path to the repo. - GetPath() string - // GetUserName returns the name the the user has used to configure git GetUserName() (string, error) @@ -64,6 +73,21 @@ type RepoCommon interface { GetRemotes() (map[string]string, error) } +// RepoStorage give access to the filesystem +type RepoStorage interface { + // LocalStorage return a billy.Filesystem giving access to $RepoPath/.git/git-bug + LocalStorage() billy.Filesystem +} + +// RepoBleve give access to Bleve to implement full-text search indexes. +type RepoBleve interface { + // GetBleveIndex return a bleve.Index that can be used to index documents + GetBleveIndex(name string) (bleve.Index, error) + + // ClearBleveIndex will wipe the given index + ClearBleveIndex(name string) error +} + // RepoData give access to the git data storage type RepoData interface { // FetchRefs fetch git refs from a remote @@ -145,4 +169,10 @@ type TestedRepo interface { type repoTest interface { // AddRemote add a new remote to the repository AddRemote(name string, url string) error + + // GetLocalRemote return the URL to use to add this repo as a local remote + GetLocalRemote() string + + // EraseFromDisk delete this repository entirely from the disk + EraseFromDisk() error } diff --git a/repository/repo_testing.go b/repository/repo_testing.go index 41b3609e..c0e1fa79 100644 --- a/repository/repo_testing.go +++ b/repository/repo_testing.go @@ -3,8 +3,6 @@ package repository import ( "log" "math/rand" - "os" - "strings" "testing" "github.com/stretchr/testify/require" @@ -15,25 +13,13 @@ import ( func CleanupTestRepos(repos ...Repo) { var firstErr error for _, repo := range repos { - path := repo.GetPath() - if strings.HasSuffix(path, "/.git") { - // for a normal repository (not --bare), we want to remove everything - // including the parent directory where files are checked out - path = strings.TrimSuffix(path, "/.git") - - // Testing non-bare repo should also check path is - // only .git (i.e. ./.git), but doing so, we should - // try to remove the current directory and hav some - // trouble. In the present case, this case should not - // occur. - // TODO consider warning or error when path == ".git" - } - // fmt.Println("Cleaning repo:", path) - err := os.RemoveAll(path) - if err != nil { - log.Println(err) - if firstErr == nil { - firstErr = err + if repo, ok := repo.(TestedRepo); ok { + err := repo.EraseFromDisk() + if err != nil { + log.Println(err) + if firstErr == nil { + firstErr = err + } } } } |