aboutsummaryrefslogtreecommitdiffstats
path: root/repository
diff options
context:
space:
mode:
authorMichael Muré <batolettre@gmail.com>2020-09-27 00:54:14 +0200
committerMichael Muré <batolettre@gmail.com>2020-09-29 20:42:21 +0200
commit71b7eb14010be0c7799b4d5394798c89e379891b (patch)
treef82d4b7bc6be5165c093d4feb18f5ee642c2c3e6 /repository
parentc87e9abacfbdc4f221e2e328d4b229d6191f42e9 (diff)
downloadgit-bug-71b7eb14010be0c7799b4d5394798c89e379891b.tar.gz
repo: implement local/global/any config everywhere
Diffstat (limited to 'repository')
-rw-r--r--repository/config.go64
-rw-r--r--repository/config_test.go54
-rw-r--r--repository/git.go83
-rw-r--r--repository/git_cli.go56
-rw-r--r--repository/git_config.go18
-rw-r--r--repository/gogit.go25
-rw-r--r--repository/mock_repo.go11
-rw-r--r--repository/repo.go6
-rw-r--r--repository/repo_testing.go299
9 files changed, 400 insertions, 216 deletions
diff --git a/repository/config.go b/repository/config.go
index 70d51f11..4ea326b5 100644
--- a/repository/config.go
+++ b/repository/config.go
@@ -59,3 +59,67 @@ func ParseTimestamp(s string) (time.Time, error) {
return time.Unix(int64(timestamp), 0), nil
}
+
+// mergeConfig is a helper to easily support RepoConfig.AnyConfig()
+// from two separate local and global Config
+func mergeConfig(local ConfigRead, global ConfigRead) *mergedConfig {
+ return &mergedConfig{
+ local: local,
+ global: global,
+ }
+}
+
+var _ ConfigRead = &mergedConfig{}
+
+type mergedConfig struct {
+ local ConfigRead
+ global ConfigRead
+}
+
+func (m *mergedConfig) ReadAll(keyPrefix string) (map[string]string, error) {
+ values, err := m.global.ReadAll(keyPrefix)
+ if err != nil {
+ return nil, err
+ }
+ locals, err := m.local.ReadAll(keyPrefix)
+ if err != nil {
+ return nil, err
+ }
+ for k, val := range locals {
+ values[k] = val
+ }
+ return values, nil
+}
+
+func (m *mergedConfig) ReadBool(key string) (bool, error) {
+ v, err := m.local.ReadBool(key)
+ if err == nil {
+ return v, nil
+ }
+ if err != ErrNoConfigEntry && err != ErrMultipleConfigEntry {
+ return false, err
+ }
+ return m.global.ReadBool(key)
+}
+
+func (m *mergedConfig) ReadString(key string) (string, error) {
+ val, err := m.local.ReadString(key)
+ if err == nil {
+ return val, nil
+ }
+ if err != ErrNoConfigEntry && err != ErrMultipleConfigEntry {
+ return "", err
+ }
+ return m.global.ReadString(key)
+}
+
+func (m *mergedConfig) ReadTimestamp(key string) (time.Time, error) {
+ val, err := m.local.ReadTimestamp(key)
+ if err == nil {
+ return val, nil
+ }
+ if err != ErrNoConfigEntry && err != ErrMultipleConfigEntry {
+ return time.Time{}, err
+ }
+ return m.global.ReadTimestamp(key)
+}
diff --git a/repository/config_test.go b/repository/config_test.go
new file mode 100644
index 00000000..2a763540
--- /dev/null
+++ b/repository/config_test.go
@@ -0,0 +1,54 @@
+package repository
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestMergedConfig(t *testing.T) {
+ local := NewMemConfig()
+ global := NewMemConfig()
+ merged := mergeConfig(local, global)
+
+ require.NoError(t, global.StoreBool("bool", true))
+ require.NoError(t, global.StoreString("string", "foo"))
+ require.NoError(t, global.StoreTimestamp("timestamp", time.Unix(1234, 0)))
+
+ val1, err := merged.ReadBool("bool")
+ require.NoError(t, err)
+ require.Equal(t, val1, true)
+
+ val2, err := merged.ReadString("string")
+ require.NoError(t, err)
+ require.Equal(t, val2, "foo")
+
+ val3, err := merged.ReadTimestamp("timestamp")
+ require.NoError(t, err)
+ require.Equal(t, val3, time.Unix(1234, 0))
+
+ require.NoError(t, local.StoreBool("bool", false))
+ require.NoError(t, local.StoreString("string", "bar"))
+ require.NoError(t, local.StoreTimestamp("timestamp", time.Unix(5678, 0)))
+
+ val1, err = merged.ReadBool("bool")
+ require.NoError(t, err)
+ require.Equal(t, val1, false)
+
+ val2, err = merged.ReadString("string")
+ require.NoError(t, err)
+ require.Equal(t, val2, "bar")
+
+ val3, err = merged.ReadTimestamp("timestamp")
+ require.NoError(t, err)
+ require.Equal(t, val3, time.Unix(5678, 0))
+
+ all, err := merged.ReadAll("")
+ require.NoError(t, err)
+ require.Equal(t, all, map[string]string{
+ "bool": "false",
+ "string": "bar",
+ "timestamp": "5678",
+ })
+}
diff --git a/repository/git.go b/repository/git.go
index 37b79556..dba2d29d 100644
--- a/repository/git.go
+++ b/repository/git.go
@@ -4,8 +4,6 @@ package repository
import (
"bytes"
"fmt"
- "io"
- "os/exec"
"path"
"strings"
"sync"
@@ -22,6 +20,7 @@ var _ TestedRepo = &GitRepo{}
// GitRepo represents an instance of a (local) git repository.
type GitRepo struct {
+ gitCli
path string
clocksMutex sync.Mutex
@@ -30,62 +29,6 @@ type GitRepo struct {
keyring Keyring
}
-// LocalConfig give access to the repository scoped configuration
-func (repo *GitRepo) LocalConfig() Config {
- return newGitConfig(repo, false)
-}
-
-// GlobalConfig give access to the git global configuration
-func (repo *GitRepo) GlobalConfig() Config {
- return newGitConfig(repo, true)
-}
-
-func (repo *GitRepo) Keyring() Keyring {
- return repo.keyring
-}
-
-// Run the given git command with the given I/O reader/writers, returning an error if it fails.
-func (repo *GitRepo) runGitCommandWithIO(stdin io.Reader, stdout, stderr io.Writer, args ...string) error {
- // make sure that the working directory for the command
- // always exist, in particular when running "git init".
- path := strings.TrimSuffix(repo.path, ".git")
-
- // fmt.Printf("[%s] Running git %s\n", path, strings.Join(args, " "))
-
- cmd := exec.Command("git", args...)
- cmd.Dir = path
- cmd.Stdin = stdin
- cmd.Stdout = stdout
- cmd.Stderr = stderr
-
- return cmd.Run()
-}
-
-// Run the given git command and return its stdout, or an error if the command fails.
-func (repo *GitRepo) runGitCommandRaw(stdin io.Reader, args ...string) (string, string, error) {
- var stdout bytes.Buffer
- var stderr bytes.Buffer
- err := repo.runGitCommandWithIO(stdin, &stdout, &stderr, args...)
- return strings.TrimSpace(stdout.String()), strings.TrimSpace(stderr.String()), err
-}
-
-// Run the given git command and return its stdout, or an error if the command fails.
-func (repo *GitRepo) runGitCommandWithStdin(stdin io.Reader, args ...string) (string, error) {
- stdout, stderr, err := repo.runGitCommandRaw(stdin, args...)
- if err != nil {
- if stderr == "" {
- stderr = "Error running git command: " + strings.Join(args, " ")
- }
- err = fmt.Errorf(stderr)
- }
- return stdout, err
-}
-
-// Run the given git command and return its stdout, or an error if the command fails.
-func (repo *GitRepo) runGitCommand(args ...string) (string, error) {
- return repo.runGitCommandWithStdin(nil, args...)
-}
-
// 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, clockLoaders []ClockLoader) (*GitRepo, error) {
@@ -95,6 +38,7 @@ func NewGitRepo(path string, clockLoaders []ClockLoader) (*GitRepo, error) {
}
repo := &GitRepo{
+ gitCli: gitCli{path: path},
path: path,
clocks: make(map[string]lamport.Clock),
keyring: k,
@@ -112,6 +56,7 @@ func NewGitRepo(path string, clockLoaders []ClockLoader) (*GitRepo, error) {
// Fix the path to be sure we are at the root
repo.path = stdout
+ repo.gitCli.path = stdout
for _, loader := range clockLoaders {
allExist := true
@@ -135,6 +80,7 @@ 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),
}
@@ -150,6 +96,7 @@ 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),
}
@@ -162,6 +109,26 @@ func InitBareGitRepo(path string) (*GitRepo, error) {
return repo, nil
}
+// LocalConfig give access to the repository scoped configuration
+func (repo *GitRepo) LocalConfig() Config {
+ return newGitConfig(repo.gitCli, false)
+}
+
+// GlobalConfig give access to the global scoped configuration
+func (repo *GitRepo) GlobalConfig() Config {
+ return newGitConfig(repo.gitCli, true)
+}
+
+// AnyConfig give access to a merged local/global configuration
+func (repo *GitRepo) AnyConfig() ConfigRead {
+ return mergeConfig(repo.LocalConfig(), repo.GlobalConfig())
+}
+
+// Keyring give access to a user-wide storage for secrets
+func (repo *GitRepo) Keyring() Keyring {
+ return repo.keyring
+}
+
// GetPath returns the path to the repo.
func (repo *GitRepo) GetPath() string {
return repo.path
diff --git a/repository/git_cli.go b/repository/git_cli.go
new file mode 100644
index 00000000..085b1cda
--- /dev/null
+++ b/repository/git_cli.go
@@ -0,0 +1,56 @@
+package repository
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os/exec"
+ "strings"
+)
+
+// gitCli is a helper to launch CLI git commands
+type gitCli struct {
+ path string
+}
+
+// Run the given git command with the given I/O reader/writers, returning an error if it fails.
+func (cli gitCli) runGitCommandWithIO(stdin io.Reader, stdout, stderr io.Writer, args ...string) error {
+ // make sure that the working directory for the command
+ // always exist, in particular when running "git init".
+ path := strings.TrimSuffix(cli.path, ".git")
+
+ // fmt.Printf("[%s] Running git %s\n", path, strings.Join(args, " "))
+
+ cmd := exec.Command("git", args...)
+ cmd.Dir = path
+ cmd.Stdin = stdin
+ cmd.Stdout = stdout
+ cmd.Stderr = stderr
+
+ return cmd.Run()
+}
+
+// Run the given git command and return its stdout, or an error if the command fails.
+func (cli gitCli) runGitCommandRaw(stdin io.Reader, args ...string) (string, string, error) {
+ var stdout bytes.Buffer
+ var stderr bytes.Buffer
+ err := cli.runGitCommandWithIO(stdin, &stdout, &stderr, args...)
+ return strings.TrimSpace(stdout.String()), strings.TrimSpace(stderr.String()), err
+}
+
+// Run the given git command and return its stdout, or an error if the command fails.
+func (cli gitCli) runGitCommandWithStdin(stdin io.Reader, args ...string) (string, error) {
+ stdout, stderr, err := cli.runGitCommandRaw(stdin, args...)
+ if err != nil {
+ if stderr == "" {
+ stderr = "Error running git command: " + strings.Join(args, " ")
+ }
+ err = fmt.Errorf(stderr)
+ }
+ return stdout, err
+}
+
+// Run the given git command and return its stdout, or an error if the command fails.
+func (cli gitCli) runGitCommand(args ...string) (string, error) {
+ return cli.runGitCommandWithStdin(nil, args...)
+}
diff --git a/repository/git_config.go b/repository/git_config.go
index 987cf195..b46cc69b 100644
--- a/repository/git_config.go
+++ b/repository/git_config.go
@@ -14,24 +14,24 @@ import (
var _ Config = &gitConfig{}
type gitConfig struct {
- repo *GitRepo
+ cli gitCli
localityFlag string
}
-func newGitConfig(repo *GitRepo, global bool) *gitConfig {
+func newGitConfig(cli gitCli, global bool) *gitConfig {
localityFlag := "--local"
if global {
localityFlag = "--global"
}
return &gitConfig{
- repo: repo,
+ cli: cli,
localityFlag: localityFlag,
}
}
// StoreString store a single key/value pair in the config of the repo
func (gc *gitConfig) StoreString(key string, value string) error {
- _, err := gc.repo.runGitCommand("config", gc.localityFlag, "--replace-all", key, value)
+ _, err := gc.cli.runGitCommand("config", gc.localityFlag, "--replace-all", key, value)
return err
}
@@ -45,7 +45,7 @@ func (gc *gitConfig) StoreTimestamp(key string, value time.Time) error {
// ReadAll read all key/value pair matching the key prefix
func (gc *gitConfig) ReadAll(keyPrefix string) (map[string]string, error) {
- stdout, err := gc.repo.runGitCommand("config", gc.localityFlag, "--includes", "--get-regexp", keyPrefix)
+ stdout, err := gc.cli.runGitCommand("config", gc.localityFlag, "--includes", "--get-regexp", keyPrefix)
// / \
// / ! \
@@ -74,7 +74,7 @@ func (gc *gitConfig) ReadAll(keyPrefix string) (map[string]string, error) {
}
func (gc *gitConfig) ReadString(key string) (string, error) {
- stdout, err := gc.repo.runGitCommand("config", gc.localityFlag, "--includes", "--get-all", key)
+ stdout, err := gc.cli.runGitCommand("config", gc.localityFlag, "--includes", "--get-all", key)
// / \
// / ! \
@@ -116,12 +116,12 @@ func (gc *gitConfig) ReadTimestamp(key string) (time.Time, error) {
}
func (gc *gitConfig) rmSection(keyPrefix string) error {
- _, err := gc.repo.runGitCommand("config", gc.localityFlag, "--remove-section", keyPrefix)
+ _, err := gc.cli.runGitCommand("config", gc.localityFlag, "--remove-section", keyPrefix)
return err
}
func (gc *gitConfig) unsetAll(keyPrefix string) error {
- _, err := gc.repo.runGitCommand("config", gc.localityFlag, "--unset-all", keyPrefix)
+ _, err := gc.cli.runGitCommand("config", gc.localityFlag, "--unset-all", keyPrefix)
return err
}
@@ -180,7 +180,7 @@ func (gc *gitConfig) RemoveAll(keyPrefix string) error {
}
func (gc *gitConfig) gitVersion() (*semver.Version, error) {
- versionOut, err := gc.repo.runGitCommand("version")
+ versionOut, err := gc.cli.runGitCommand("version")
if err != nil {
return nil, err
}
diff --git a/repository/gogit.go b/repository/gogit.go
index b0a4672b..f248235c 100644
--- a/repository/gogit.go
+++ b/repository/gogit.go
@@ -158,14 +158,25 @@ func InitBareGoGitRepo(path string) (*GoGitRepo, error) {
}, nil
}
+// LocalConfig give access to the repository scoped configuration
func (repo *GoGitRepo) LocalConfig() Config {
return newGoGitConfig(repo.r)
}
+// GlobalConfig give access to the global scoped configuration
func (repo *GoGitRepo) GlobalConfig() Config {
- panic("go-git doesn't support writing global 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 newGitConfig(gitCli{repo.path}, true)
}
+// AnyConfig give access to a merged local/global configuration
+func (repo *GoGitRepo) AnyConfig() ConfigRead {
+ return mergeConfig(repo.LocalConfig(), repo.GlobalConfig())
+}
+
+// Keyring give access to a user-wide storage for secrets
func (repo *GoGitRepo) Keyring() Keyring {
return repo.keyring
}
@@ -288,6 +299,7 @@ func (repo *GoGitRepo) ReadData(hash Hash) ([]byte, error) {
return ioutil.ReadAll(r)
}
+// StoreTree will store a mapping key-->Hash as a Git tree
func (repo *GoGitRepo) StoreTree(mapping []TreeEntry) (Hash, error) {
var tree object.Tree
@@ -319,6 +331,7 @@ func (repo *GoGitRepo) StoreTree(mapping []TreeEntry) (Hash, error) {
return Hash(hash.String()), nil
}
+// ReadTree will return the list of entries in a Git tree
func (repo *GoGitRepo) ReadTree(hash Hash) ([]TreeEntry, error) {
obj, err := repo.r.TreeObject(plumbing.NewHash(hash.String()))
if err != nil {
@@ -342,10 +355,12 @@ func (repo *GoGitRepo) ReadTree(hash Hash) ([]TreeEntry, error) {
return treeEntries, nil
}
+// StoreCommit will store a Git commit with the given Git tree
func (repo *GoGitRepo) StoreCommit(treeHash Hash) (Hash, error) {
return repo.StoreCommitWithParent(treeHash, "")
}
+// StoreCommit will store a Git commit with the given Git tree
func (repo *GoGitRepo) StoreCommitWithParent(treeHash Hash, parent Hash) (Hash, error) {
cfg, err := repo.r.Config()
if err != nil {
@@ -386,6 +401,7 @@ func (repo *GoGitRepo) StoreCommitWithParent(treeHash Hash, parent Hash) (Hash,
return Hash(hash.String()), nil
}
+// GetTreeHash return the git tree hash referenced in a commit
func (repo *GoGitRepo) GetTreeHash(commit Hash) (Hash, error) {
obj, err := repo.r.CommitObject(plumbing.NewHash(commit.String()))
if err != nil {
@@ -395,6 +411,7 @@ func (repo *GoGitRepo) GetTreeHash(commit Hash) (Hash, error) {
return Hash(obj.TreeHash.String()), nil
}
+// FindCommonAncestor will return the last common ancestor of two chain of commit
func (repo *GoGitRepo) FindCommonAncestor(commit1 Hash, commit2 Hash) (Hash, error) {
obj1, err := repo.r.CommitObject(plumbing.NewHash(commit1.String()))
if err != nil {
@@ -413,14 +430,17 @@ func (repo *GoGitRepo) FindCommonAncestor(commit1 Hash, commit2 Hash) (Hash, err
return Hash(commits[0].Hash.String()), nil
}
+// UpdateRef will create or update a Git reference
func (repo *GoGitRepo) UpdateRef(ref string, hash Hash) error {
return repo.r.Storer.SetReference(plumbing.NewHashReference(plumbing.ReferenceName(ref), plumbing.NewHash(hash.String())))
}
+// RemoveRef will remove a Git reference
func (repo *GoGitRepo) RemoveRef(ref string) error {
return repo.r.Storer.RemoveReference(plumbing.ReferenceName(ref))
}
+// ListRefs will return a list of Git ref matching the given refspec
func (repo *GoGitRepo) ListRefs(refPrefix string) ([]string, error) {
refIter, err := repo.r.References()
if err != nil {
@@ -442,6 +462,7 @@ func (repo *GoGitRepo) ListRefs(refPrefix string) ([]string, error) {
return refs, nil
}
+// RefExist will check if a reference exist in Git
func (repo *GoGitRepo) RefExist(ref string) (bool, error) {
_, err := repo.r.Reference(plumbing.ReferenceName(ref), false)
if err == nil {
@@ -452,6 +473,7 @@ func (repo *GoGitRepo) RefExist(ref string) (bool, error) {
return false, err
}
+// CopyRef will create a new reference with the same value as another one
func (repo *GoGitRepo) CopyRef(source string, dest string) error {
r, err := repo.r.Reference(plumbing.ReferenceName(source), false)
if err != nil {
@@ -460,6 +482,7 @@ func (repo *GoGitRepo) CopyRef(source string, dest string) error {
return repo.r.Storer.SetReference(plumbing.NewHashReference(plumbing.ReferenceName(dest), r.Hash()))
}
+// ListCommits will return the list of tree hashes of a ref, in chronological order
func (repo *GoGitRepo) ListCommits(ref string) ([]Hash, error) {
r, err := repo.r.Reference(plumbing.ReferenceName(ref), false)
if err != nil {
diff --git a/repository/mock_repo.go b/repository/mock_repo.go
index 07425765..628939aa 100644
--- a/repository/mock_repo.go
+++ b/repository/mock_repo.go
@@ -35,20 +35,20 @@ func NewMockRepoForTest() *mockRepoForTest {
var _ RepoConfig = &mockRepoConfig{}
type mockRepoConfig struct {
- config *MemConfig
+ localConfig *MemConfig
globalConfig *MemConfig
}
func NewMockRepoConfig() *mockRepoConfig {
return &mockRepoConfig{
- config: NewMemConfig(),
+ localConfig: NewMemConfig(),
globalConfig: NewMemConfig(),
}
}
// LocalConfig give access to the repository scoped configuration
func (r *mockRepoConfig) LocalConfig() Config {
- return r.config
+ return r.localConfig
}
// GlobalConfig give access to the git global configuration
@@ -56,6 +56,11 @@ func (r *mockRepoConfig) GlobalConfig() Config {
return r.globalConfig
}
+// AnyConfig give access to a merged local/global configuration
+func (r *mockRepoConfig) AnyConfig() ConfigRead {
+ return mergeConfig(r.localConfig, r.globalConfig)
+}
+
var _ RepoKeyring = &mockRepoKeyring{}
type mockRepoKeyring struct {
diff --git a/repository/repo.go b/repository/repo.go
index 6349007b..2eb27e82 100644
--- a/repository/repo.go
+++ b/repository/repo.go
@@ -32,6 +32,12 @@ type ClockedRepo interface {
type RepoConfig interface {
// LocalConfig give access to the repository scoped configuration
LocalConfig() Config
+
+ // GlobalConfig give access to the global scoped configuration
+ GlobalConfig() Config
+
+ // AnyConfig give access to a merged local/global configuration
+ AnyConfig() ConfigRead
}
// RepoKeyring give access to a user-wide storage for secrets
diff --git a/repository/repo_testing.go b/repository/repo_testing.go
index 53375a5b..cfa26631 100644
--- a/repository/repo_testing.go
+++ b/repository/repo_testing.go
@@ -53,160 +53,169 @@ func RepoTest(t *testing.T, creator RepoCreator, cleaner RepoCleaner) {
true: "Bare",
} {
t.Run(name, func(t *testing.T) {
- t.Run("Blob-Tree-Commit-Ref", func(t *testing.T) {
- repo := creator(bare)
- defer cleaner(repo)
-
- // Blob
-
- data := randomData()
-
- blobHash1, err := repo.StoreData(data)
- require.NoError(t, err)
- require.True(t, blobHash1.IsValid())
-
- blob1Read, err := repo.ReadData(blobHash1)
- require.NoError(t, err)
- require.Equal(t, data, blob1Read)
-
- // Tree
-
- blobHash2, err := repo.StoreData(randomData())
- require.NoError(t, err)
- blobHash3, err := repo.StoreData(randomData())
- require.NoError(t, err)
-
- tree1 := []TreeEntry{
- {
- ObjectType: Blob,
- Hash: blobHash1,
- Name: "blob1",
- },
- {
- ObjectType: Blob,
- Hash: blobHash2,
- Name: "blob2",
- },
- }
-
- treeHash1, err := repo.StoreTree(tree1)
- require.NoError(t, err)
- require.True(t, treeHash1.IsValid())
-
- tree1Read, err := repo.ReadTree(treeHash1)
- require.NoError(t, err)
- require.ElementsMatch(t, tree1, tree1Read)
-
- tree2 := []TreeEntry{
- {
- ObjectType: Tree,
- Hash: treeHash1,
- Name: "tree1",
- },
- {
- ObjectType: Blob,
- Hash: blobHash3,
- Name: "blob3",
- },
- }
-
- treeHash2, err := repo.StoreTree(tree2)
- require.NoError(t, err)
- require.True(t, treeHash2.IsValid())
-
- tree2Read, err := repo.ReadTree(treeHash2)
- require.NoError(t, err)
- require.ElementsMatch(t, tree2, tree2Read)
-
- // Commit
-
- commit1, err := repo.StoreCommit(treeHash1)
- require.NoError(t, err)
- require.True(t, commit1.IsValid())
-
- treeHash1Read, err := repo.GetTreeHash(commit1)
- require.NoError(t, err)
- require.Equal(t, treeHash1, treeHash1Read)
-
- commit2, err := repo.StoreCommitWithParent(treeHash2, commit1)
- require.NoError(t, err)
- require.True(t, commit2.IsValid())
-
- treeHash2Read, err := repo.GetTreeHash(commit2)
- require.NoError(t, err)
- require.Equal(t, treeHash2, treeHash2Read)
-
- // Ref
-
- exist1, err := repo.RefExist("refs/bugs/ref1")
- require.NoError(t, err)
- require.False(t, exist1)
-
- err = repo.UpdateRef("refs/bugs/ref1", commit2)
- require.NoError(t, err)
-
- exist1, err = repo.RefExist("refs/bugs/ref1")
- require.NoError(t, err)
- require.True(t, exist1)
-
- ls, err := repo.ListRefs("refs/bugs")
- require.NoError(t, err)
- require.ElementsMatch(t, []string{"refs/bugs/ref1"}, ls)
-
- err = repo.CopyRef("refs/bugs/ref1", "refs/bugs/ref2")
- require.NoError(t, err)
-
- ls, err = repo.ListRefs("refs/bugs")
- require.NoError(t, err)
- require.ElementsMatch(t, []string{"refs/bugs/ref1", "refs/bugs/ref2"}, ls)
-
- commits, err := repo.ListCommits("refs/bugs/ref2")
- require.NoError(t, err)
- require.ElementsMatch(t, []Hash{commit1, commit2}, commits)
-
- // Graph
-
- commit3, err := repo.StoreCommitWithParent(treeHash1, commit1)
- require.NoError(t, err)
-
- ancestorHash, err := repo.FindCommonAncestor(commit2, commit3)
- require.NoError(t, err)
- require.Equal(t, commit1, ancestorHash)
-
- err = repo.RemoveRef("refs/bugs/ref1")
- require.NoError(t, err)
- })
+ repo := creator(bare)
+ defer cleaner(repo)
- t.Run("Local config", func(t *testing.T) {
- repo := creator(bare)
- defer cleaner(repo)
+ t.Run("Data", func(t *testing.T) {
+ RepoDataTest(t, repo)
+ })
- testConfig(t, repo.LocalConfig())
+ t.Run("Config", func(t *testing.T) {
+ RepoConfigTest(t, repo)
})
t.Run("Clocks", func(t *testing.T) {
- repo := creator(bare)
- defer cleaner(repo)
-
- clock, err := repo.GetOrCreateClock("foo")
- require.NoError(t, err)
- require.Equal(t, lamport.Time(1), clock.Time())
+ RepoClockTest(t, repo)
+ })
+ })
+ }
+}
- time, err := clock.Increment()
- require.NoError(t, err)
- require.Equal(t, lamport.Time(1), time)
- require.Equal(t, lamport.Time(2), clock.Time())
+// helper to test a RepoConfig
+func RepoConfigTest(t *testing.T, repo RepoConfig) {
+ testConfig(t, repo.LocalConfig())
+}
- clock2, err := repo.GetOrCreateClock("foo")
- require.NoError(t, err)
- require.Equal(t, lamport.Time(2), clock2.Time())
+// helper to test a RepoData
+func RepoDataTest(t *testing.T, repo RepoData) {
+ // Blob
+
+ data := randomData()
+
+ blobHash1, err := repo.StoreData(data)
+ require.NoError(t, err)
+ require.True(t, blobHash1.IsValid())
+
+ blob1Read, err := repo.ReadData(blobHash1)
+ require.NoError(t, err)
+ require.Equal(t, data, blob1Read)
+
+ // Tree
+
+ blobHash2, err := repo.StoreData(randomData())
+ require.NoError(t, err)
+ blobHash3, err := repo.StoreData(randomData())
+ require.NoError(t, err)
+
+ tree1 := []TreeEntry{
+ {
+ ObjectType: Blob,
+ Hash: blobHash1,
+ Name: "blob1",
+ },
+ {
+ ObjectType: Blob,
+ Hash: blobHash2,
+ Name: "blob2",
+ },
+ }
- clock3, err := repo.GetOrCreateClock("bar")
- require.NoError(t, err)
- require.Equal(t, lamport.Time(1), clock3.Time())
- })
- })
+ treeHash1, err := repo.StoreTree(tree1)
+ require.NoError(t, err)
+ require.True(t, treeHash1.IsValid())
+
+ tree1Read, err := repo.ReadTree(treeHash1)
+ require.NoError(t, err)
+ require.ElementsMatch(t, tree1, tree1Read)
+
+ tree2 := []TreeEntry{
+ {
+ ObjectType: Tree,
+ Hash: treeHash1,
+ Name: "tree1",
+ },
+ {
+ ObjectType: Blob,
+ Hash: blobHash3,
+ Name: "blob3",
+ },
}
+
+ treeHash2, err := repo.StoreTree(tree2)
+ require.NoError(t, err)
+ require.True(t, treeHash2.IsValid())
+
+ tree2Read, err := repo.ReadTree(treeHash2)
+ require.NoError(t, err)
+ require.ElementsMatch(t, tree2, tree2Read)
+
+ // Commit
+
+ commit1, err := repo.StoreCommit(treeHash1)
+ require.NoError(t, err)
+ require.True(t, commit1.IsValid())
+
+ treeHash1Read, err := repo.GetTreeHash(commit1)
+ require.NoError(t, err)
+ require.Equal(t, treeHash1, treeHash1Read)
+
+ commit2, err := repo.StoreCommitWithParent(treeHash2, commit1)
+ require.NoError(t, err)
+ require.True(t, commit2.IsValid())
+
+ treeHash2Read, err := repo.GetTreeHash(commit2)
+ require.NoError(t, err)
+ require.Equal(t, treeHash2, treeHash2Read)
+
+ // Ref
+
+ exist1, err := repo.RefExist("refs/bugs/ref1")
+ require.NoError(t, err)
+ require.False(t, exist1)
+
+ err = repo.UpdateRef("refs/bugs/ref1", commit2)
+ require.NoError(t, err)
+
+ exist1, err = repo.RefExist("refs/bugs/ref1")
+ require.NoError(t, err)
+ require.True(t, exist1)
+
+ ls, err := repo.ListRefs("refs/bugs")
+ require.NoError(t, err)
+ require.ElementsMatch(t, []string{"refs/bugs/ref1"}, ls)
+
+ err = repo.CopyRef("refs/bugs/ref1", "refs/bugs/ref2")
+ require.NoError(t, err)
+
+ ls, err = repo.ListRefs("refs/bugs")
+ require.NoError(t, err)
+ require.ElementsMatch(t, []string{"refs/bugs/ref1", "refs/bugs/ref2"}, ls)
+
+ commits, err := repo.ListCommits("refs/bugs/ref2")
+ require.NoError(t, err)
+ require.ElementsMatch(t, []Hash{commit1, commit2}, commits)
+
+ // Graph
+
+ commit3, err := repo.StoreCommitWithParent(treeHash1, commit1)
+ require.NoError(t, err)
+
+ ancestorHash, err := repo.FindCommonAncestor(commit2, commit3)
+ require.NoError(t, err)
+ require.Equal(t, commit1, ancestorHash)
+
+ err = repo.RemoveRef("refs/bugs/ref1")
+ require.NoError(t, err)
+}
+
+// helper to test a RepoClock
+func RepoClockTest(t *testing.T, repo RepoClock) {
+ clock, err := repo.GetOrCreateClock("foo")
+ require.NoError(t, err)
+ require.Equal(t, lamport.Time(1), clock.Time())
+
+ time, err := clock.Increment()
+ require.NoError(t, err)
+ require.Equal(t, lamport.Time(1), time)
+ require.Equal(t, lamport.Time(2), clock.Time())
+
+ clock2, err := repo.GetOrCreateClock("foo")
+ require.NoError(t, err)
+ require.Equal(t, lamport.Time(2), clock2.Time())
+
+ clock3, err := repo.GetOrCreateClock("bar")
+ require.NoError(t, err)
+ require.Equal(t, lamport.Time(1), clock3.Time())
}
func randomData() []byte {