2018-07-12 10:55:13 +03:00
|
|
|
package repository
|
|
|
|
|
|
|
|
import (
|
2018-07-14 23:17:37 +03:00
|
|
|
"crypto/sha1"
|
|
|
|
"fmt"
|
2020-06-27 23:00:15 +03:00
|
|
|
"strings"
|
2018-07-25 19:01:32 +03:00
|
|
|
|
2020-07-27 01:14:01 +03:00
|
|
|
"github.com/99designs/keyring"
|
|
|
|
|
2018-09-11 23:04:16 +03:00
|
|
|
"github.com/MichaelMure/git-bug/util/lamport"
|
2018-07-12 10:55:13 +03:00
|
|
|
)
|
|
|
|
|
2019-02-19 02:19:27 +03:00
|
|
|
var _ ClockedRepo = &mockRepoForTest{}
|
2020-06-23 19:02:54 +03:00
|
|
|
var _ TestedRepo = &mockRepoForTest{}
|
2019-02-19 02:19:27 +03:00
|
|
|
|
2018-07-12 10:55:13 +03:00
|
|
|
// mockRepoForTest defines an instance of Repo that can be used for testing.
|
2018-07-14 23:17:37 +03:00
|
|
|
type mockRepoForTest struct {
|
2019-12-08 23:15:06 +03:00
|
|
|
config *MemConfig
|
|
|
|
globalConfig *MemConfig
|
2020-07-27 01:14:01 +03:00
|
|
|
keyring *keyring.ArrayKeyring
|
2020-07-01 20:39:02 +03:00
|
|
|
blobs map[Hash][]byte
|
|
|
|
trees map[Hash]string
|
|
|
|
commits map[Hash]commit
|
|
|
|
refs map[string]Hash
|
2020-06-23 19:02:54 +03:00
|
|
|
clocks map[string]lamport.Clock
|
2018-07-14 23:17:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
type commit struct {
|
2020-07-01 20:39:02 +03:00
|
|
|
treeHash Hash
|
|
|
|
parent Hash
|
2018-07-14 23:17:37 +03:00
|
|
|
}
|
2018-07-12 10:55:13 +03:00
|
|
|
|
2018-09-21 19:18:51 +03:00
|
|
|
func NewMockRepoForTest() *mockRepoForTest {
|
2018-07-14 23:17:37 +03:00
|
|
|
return &mockRepoForTest{
|
2019-12-08 23:15:06 +03:00
|
|
|
config: NewMemConfig(),
|
|
|
|
globalConfig: NewMemConfig(),
|
2020-07-27 01:14:01 +03:00
|
|
|
keyring: keyring.NewArrayKeyring(nil),
|
2020-07-01 20:39:02 +03:00
|
|
|
blobs: make(map[Hash][]byte),
|
|
|
|
trees: make(map[Hash]string),
|
|
|
|
commits: make(map[Hash]commit),
|
|
|
|
refs: make(map[string]Hash),
|
2020-06-23 19:02:54 +03:00
|
|
|
clocks: make(map[string]lamport.Clock),
|
2018-07-14 23:17:37 +03:00
|
|
|
}
|
2018-07-13 22:21:24 +03:00
|
|
|
}
|
|
|
|
|
2019-11-02 00:40:21 +03:00
|
|
|
// LocalConfig give access to the repository scoped configuration
|
2019-10-31 17:46:09 +03:00
|
|
|
func (r *mockRepoForTest) LocalConfig() Config {
|
2019-12-08 23:15:06 +03:00
|
|
|
return r.config
|
2019-10-31 17:46:09 +03:00
|
|
|
}
|
|
|
|
|
2019-11-02 00:40:21 +03:00
|
|
|
// GlobalConfig give access to the git global configuration
|
2019-10-31 17:46:09 +03:00
|
|
|
func (r *mockRepoForTest) GlobalConfig() Config {
|
2019-12-08 23:15:06 +03:00
|
|
|
return r.globalConfig
|
2019-10-31 17:46:09 +03:00
|
|
|
}
|
|
|
|
|
2020-07-27 01:14:01 +03:00
|
|
|
// Keyring give access to a user-wide storage for secrets
|
|
|
|
func (r *mockRepoForTest) Keyring() Keyring {
|
|
|
|
return r.keyring
|
|
|
|
}
|
|
|
|
|
2018-07-12 10:55:13 +03:00
|
|
|
// GetPath returns the path to the repo.
|
2018-07-13 22:21:24 +03:00
|
|
|
func (r *mockRepoForTest) GetPath() string {
|
|
|
|
return "~/mockRepo/"
|
|
|
|
}
|
2018-07-12 10:55:13 +03:00
|
|
|
|
2018-07-13 22:21:24 +03:00
|
|
|
func (r *mockRepoForTest) GetUserName() (string, error) {
|
|
|
|
return "René Descartes", nil
|
2018-07-12 10:55:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetUserEmail returns the email address that the user has used to configure git.
|
2018-07-13 22:21:24 +03:00
|
|
|
func (r *mockRepoForTest) GetUserEmail() (string, error) {
|
|
|
|
return "user@example.com", nil
|
|
|
|
}
|
2018-07-12 10:55:13 +03:00
|
|
|
|
|
|
|
// GetCoreEditor returns the name of the editor that the user has used to configure git.
|
2018-07-13 22:21:24 +03:00
|
|
|
func (r *mockRepoForTest) GetCoreEditor() (string, error) {
|
|
|
|
return "vi", nil
|
|
|
|
}
|
2018-07-12 10:55:13 +03:00
|
|
|
|
2019-05-25 16:13:40 +03:00
|
|
|
// GetRemotes returns the configured remotes repositories.
|
|
|
|
func (r *mockRepoForTest) GetRemotes() (map[string]string, error) {
|
|
|
|
return map[string]string{
|
|
|
|
"origin": "git://github.com/MichaelMure/git-bug",
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2018-07-12 10:55:13 +03:00
|
|
|
// PushRefs push git refs to a remote
|
2018-08-12 22:09:30 +03:00
|
|
|
func (r *mockRepoForTest) PushRefs(remote string, refSpec string) (string, error) {
|
|
|
|
return "", nil
|
2018-07-12 13:44:46 +03:00
|
|
|
}
|
2018-07-13 22:21:24 +03:00
|
|
|
|
2018-08-12 22:09:30 +03:00
|
|
|
func (r *mockRepoForTest) FetchRefs(remote string, refSpec string) (string, error) {
|
|
|
|
return "", nil
|
2018-07-13 22:21:24 +03:00
|
|
|
}
|
|
|
|
|
2020-07-01 20:39:02 +03:00
|
|
|
func (r *mockRepoForTest) StoreData(data []byte) (Hash, error) {
|
2018-07-14 23:17:37 +03:00
|
|
|
rawHash := sha1.Sum(data)
|
2020-07-01 20:39:02 +03:00
|
|
|
hash := Hash(fmt.Sprintf("%x", rawHash))
|
2018-07-14 23:17:37 +03:00
|
|
|
r.blobs[hash] = data
|
|
|
|
return hash, nil
|
|
|
|
}
|
|
|
|
|
2020-07-01 20:39:02 +03:00
|
|
|
func (r *mockRepoForTest) ReadData(hash Hash) ([]byte, error) {
|
2018-07-14 23:17:37 +03:00
|
|
|
data, ok := r.blobs[hash]
|
|
|
|
|
|
|
|
if !ok {
|
2018-07-19 14:33:16 +03:00
|
|
|
return nil, fmt.Errorf("unknown hash")
|
2018-07-14 23:17:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return data, nil
|
2018-07-13 22:21:24 +03:00
|
|
|
}
|
|
|
|
|
2020-07-01 20:39:02 +03:00
|
|
|
func (r *mockRepoForTest) StoreTree(entries []TreeEntry) (Hash, error) {
|
2018-07-14 23:17:37 +03:00
|
|
|
buffer := prepareTreeEntries(entries)
|
|
|
|
rawHash := sha1.Sum(buffer.Bytes())
|
2020-07-01 20:39:02 +03:00
|
|
|
hash := Hash(fmt.Sprintf("%x", rawHash))
|
2018-07-14 23:17:37 +03:00
|
|
|
r.trees[hash] = buffer.String()
|
|
|
|
|
|
|
|
return hash, nil
|
2018-07-13 22:21:24 +03:00
|
|
|
}
|
|
|
|
|
2020-07-01 20:39:02 +03:00
|
|
|
func (r *mockRepoForTest) StoreCommit(treeHash Hash) (Hash, error) {
|
2018-07-14 23:17:37 +03:00
|
|
|
rawHash := sha1.Sum([]byte(treeHash))
|
2020-07-01 20:39:02 +03:00
|
|
|
hash := Hash(fmt.Sprintf("%x", rawHash))
|
2018-07-14 23:17:37 +03:00
|
|
|
r.commits[hash] = commit{
|
|
|
|
treeHash: treeHash,
|
|
|
|
}
|
|
|
|
return hash, nil
|
2018-07-13 22:21:24 +03:00
|
|
|
}
|
|
|
|
|
2020-07-01 20:39:02 +03:00
|
|
|
func (r *mockRepoForTest) StoreCommitWithParent(treeHash Hash, parent Hash) (Hash, error) {
|
2018-07-14 23:17:37 +03:00
|
|
|
rawHash := sha1.Sum([]byte(treeHash + parent))
|
2020-07-01 20:39:02 +03:00
|
|
|
hash := Hash(fmt.Sprintf("%x", rawHash))
|
2018-07-14 23:17:37 +03:00
|
|
|
r.commits[hash] = commit{
|
|
|
|
treeHash: treeHash,
|
|
|
|
parent: parent,
|
|
|
|
}
|
|
|
|
return hash, nil
|
2018-07-13 22:21:24 +03:00
|
|
|
}
|
|
|
|
|
2020-07-01 20:39:02 +03:00
|
|
|
func (r *mockRepoForTest) UpdateRef(ref string, hash Hash) error {
|
2018-07-14 23:17:37 +03:00
|
|
|
r.refs[ref] = hash
|
2018-07-13 22:21:24 +03:00
|
|
|
return nil
|
|
|
|
}
|
2018-07-14 23:17:37 +03:00
|
|
|
|
2020-07-09 15:40:44 +03:00
|
|
|
func (r *mockRepoForTest) RemoveRef(ref string) error {
|
|
|
|
delete(r.refs, ref)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-07-17 02:52:56 +03:00
|
|
|
func (r *mockRepoForTest) RefExist(ref string) (bool, error) {
|
|
|
|
_, exist := r.refs[ref]
|
|
|
|
return exist, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *mockRepoForTest) CopyRef(source string, dest string) error {
|
|
|
|
hash, exist := r.refs[source]
|
|
|
|
|
|
|
|
if !exist {
|
2018-07-19 14:33:16 +03:00
|
|
|
return fmt.Errorf("Unknown ref")
|
2018-07-17 02:52:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
r.refs[dest] = hash
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-07-14 23:17:37 +03:00
|
|
|
func (r *mockRepoForTest) ListRefs(refspec string) ([]string, error) {
|
2020-06-27 23:00:15 +03:00
|
|
|
var keys []string
|
2018-07-14 23:17:37 +03:00
|
|
|
|
|
|
|
for k := range r.refs {
|
2020-06-27 23:00:15 +03:00
|
|
|
if strings.HasPrefix(k, refspec) {
|
|
|
|
keys = append(keys, k)
|
|
|
|
}
|
2018-07-14 23:17:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return keys, nil
|
|
|
|
}
|
|
|
|
|
2020-07-01 20:39:02 +03:00
|
|
|
func (r *mockRepoForTest) ListCommits(ref string) ([]Hash, error) {
|
|
|
|
var hashes []Hash
|
2018-07-14 23:17:37 +03:00
|
|
|
|
|
|
|
hash := r.refs[ref]
|
|
|
|
|
|
|
|
for {
|
|
|
|
commit, ok := r.commits[hash]
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2020-07-01 20:39:02 +03:00
|
|
|
hashes = append([]Hash{hash}, hashes...)
|
2018-07-14 23:17:37 +03:00
|
|
|
hash = commit.parent
|
|
|
|
}
|
|
|
|
|
|
|
|
return hashes, nil
|
|
|
|
}
|
|
|
|
|
2020-07-01 20:39:02 +03:00
|
|
|
func (r *mockRepoForTest) ReadTree(hash Hash) ([]TreeEntry, error) {
|
2018-07-14 23:17:37 +03:00
|
|
|
var data string
|
|
|
|
|
|
|
|
data, ok := r.trees[hash]
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
// Git will understand a commit hash to reach a tree
|
|
|
|
commit, ok := r.commits[hash]
|
|
|
|
|
|
|
|
if !ok {
|
2018-07-19 14:33:16 +03:00
|
|
|
return nil, fmt.Errorf("unknown hash")
|
2018-07-14 23:17:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
data, ok = r.trees[commit.treeHash]
|
|
|
|
|
|
|
|
if !ok {
|
2018-07-19 14:33:16 +03:00
|
|
|
return nil, fmt.Errorf("unknown hash")
|
2018-07-14 23:17:37 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return readTreeEntries(data)
|
|
|
|
}
|
2018-07-17 02:52:56 +03:00
|
|
|
|
2020-07-01 20:39:02 +03:00
|
|
|
func (r *mockRepoForTest) FindCommonAncestor(hash1 Hash, hash2 Hash) (Hash, error) {
|
|
|
|
ancestor1 := []Hash{hash1}
|
2020-06-27 23:00:15 +03:00
|
|
|
|
|
|
|
for hash1 != "" {
|
|
|
|
c, ok := r.commits[hash1]
|
|
|
|
if !ok {
|
|
|
|
return "", fmt.Errorf("unknown commit %v", hash1)
|
|
|
|
}
|
|
|
|
ancestor1 = append(ancestor1, c.parent)
|
|
|
|
hash1 = c.parent
|
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
|
|
|
for _, ancestor := range ancestor1 {
|
|
|
|
if ancestor == hash2 {
|
|
|
|
return ancestor, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
c, ok := r.commits[hash2]
|
|
|
|
if !ok {
|
|
|
|
return "", fmt.Errorf("unknown commit %v", hash1)
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.parent == "" {
|
|
|
|
return "", fmt.Errorf("no ancestor found")
|
|
|
|
}
|
|
|
|
|
|
|
|
hash2 = c.parent
|
|
|
|
}
|
2018-07-17 02:52:56 +03:00
|
|
|
}
|
|
|
|
|
2020-07-01 20:39:02 +03:00
|
|
|
func (r *mockRepoForTest) GetTreeHash(commit Hash) (Hash, error) {
|
2020-06-27 23:00:15 +03:00
|
|
|
c, ok := r.commits[commit]
|
|
|
|
if !ok {
|
|
|
|
return "", fmt.Errorf("unknown commit")
|
|
|
|
}
|
|
|
|
|
|
|
|
return c.treeHash, nil
|
2018-07-17 02:52:56 +03:00
|
|
|
}
|
2018-08-06 21:31:20 +03:00
|
|
|
|
2020-06-23 19:02:54 +03:00
|
|
|
func (r *mockRepoForTest) GetOrCreateClock(name string) (lamport.Clock, error) {
|
|
|
|
if c, ok := r.clocks[name]; ok {
|
|
|
|
return c, nil
|
|
|
|
}
|
2018-08-06 21:31:20 +03:00
|
|
|
|
2020-06-23 19:02:54 +03:00
|
|
|
c := lamport.NewMemClock()
|
|
|
|
r.clocks[name] = c
|
|
|
|
return c, nil
|
2018-08-06 21:31:20 +03:00
|
|
|
}
|
|
|
|
|
2020-06-23 19:02:54 +03:00
|
|
|
func (r *mockRepoForTest) AddRemote(name string, url string) error {
|
|
|
|
panic("implement me")
|
2018-08-06 21:31:20 +03:00
|
|
|
}
|