From ab935674a26f2eef5d8014c615b9b5bc1f402135 Mon Sep 17 00:00:00 2001 From: amine Date: Thu, 31 Oct 2019 15:46:09 +0100 Subject: repository: config interface and implementation rework --- repository/config.go | 23 ++++++ repository/config_git.go | 185 +++++++++++++++++++++++++++++++++++++++++++ repository/config_runtime.go | 59 ++++++++++++++ repository/git.go | 175 +++++++--------------------------------- repository/git_test.go | 33 ++++---- repository/git_testing.go | 5 +- repository/mock_repo.go | 23 ++++-- repository/repo.go | 21 +---- 8 files changed, 334 insertions(+), 190 deletions(-) create mode 100644 repository/config.go create mode 100644 repository/config_git.go create mode 100644 repository/config_runtime.go diff --git a/repository/config.go b/repository/config.go new file mode 100644 index 00000000..a2bb33fd --- /dev/null +++ b/repository/config.go @@ -0,0 +1,23 @@ +package repository + +// Config represent the common function interacting with the repository config storage +type Config interface { + // Store writes a single key/value pair in the config of the repo + Store(key string, value string) error + + // ReadAll reads all key/value pair matching the key prefix + ReadAll(keyPrefix string) (map[string]string, error) + + // ReadBool read a single boolean value from the config + // Return ErrNoConfigEntry or ErrMultipleConfigEntry if + // there is zero or more than one entry for this key + ReadBool(key string) (bool, error) + + // ReadBool read a single string value from the config + // Return ErrNoConfigEntry or ErrMultipleConfigEntry if + // there is zero or more than one entry for this key + ReadString(key string) (string, error) + + // RemoveAll removes all key/value pair matching the key prefix + RemoveAll(keyPrefix string) error +} diff --git a/repository/config_git.go b/repository/config_git.go new file mode 100644 index 00000000..81b9b819 --- /dev/null +++ b/repository/config_git.go @@ -0,0 +1,185 @@ +package repository + +import ( + "fmt" + "strconv" + "strings" + + "github.com/blang/semver" + "github.com/pkg/errors" +) + +type gitConfig struct { + version *semver.Version + execFn func(args ...string) (string, error) +} + +func NewGitConfig(repo *GitRepo, global bool) *gitConfig { + version, _ := repo.GitVersion() + + if global { + return &gitConfig{ + execFn: func(args ...string) (string, error) { + args = append([]string{"config", "--global"}, args...) + return repo.runGitCommand(args...) + }, + version: version, + } + } + + return &gitConfig{ + execFn: func(args ...string) (string, error) { + args = append([]string{"config"}, args...) + return repo.runGitCommand(args...) + }, + version: version, + } +} + +// StoreConfig store a single key/value pair in the config of the repo +func (gc *gitConfig) Store(key string, value string) error { + _, err := gc.execFn("--replace-all", key, value) + + return err +} + +// ReadConfigs read all key/value pair matching the key prefix +func (gc *gitConfig) ReadAll(keyPrefix string) (map[string]string, error) { + stdout, err := gc.execFn("--get-regexp", keyPrefix) + + // / \ + // / ! \ + // ------- + // + // There can be a legitimate error here, but I see no portable way to + // distinguish them from the git error that say "no matching value exist" + if err != nil { + return nil, nil + } + + lines := strings.Split(stdout, "\n") + + result := make(map[string]string, len(lines)) + + for _, line := range lines { + if strings.TrimSpace(line) == "" { + continue + } + + parts := strings.Fields(line) + if len(parts) != 2 { + return nil, fmt.Errorf("bad git config: %s", line) + } + + result[parts[0]] = parts[1] + } + + return result, nil +} + +func (gc *gitConfig) ReadString(key string) (string, error) { + stdout, err := gc.execFn("--get-all", key) + + // / \ + // / ! \ + // ------- + // + // There can be a legitimate error here, but I see no portable way to + // distinguish them from the git error that say "no matching value exist" + if err != nil { + return "", ErrNoConfigEntry + } + + lines := strings.Split(stdout, "\n") + + if len(lines) == 0 { + return "", ErrNoConfigEntry + } + if len(lines) > 1 { + return "", ErrMultipleConfigEntry + } + + return lines[0], nil +} + +func (gc *gitConfig) ReadBool(key string) (bool, error) { + val, err := gc.ReadString(key) + if err != nil { + return false, err + } + + return strconv.ParseBool(val) +} + +func (gc *gitConfig) rmSection(keyPrefix string) error { + _, err := gc.execFn("--remove-section", keyPrefix) + return err +} + +func (gc *gitConfig) unsetAll(keyPrefix string) error { + _, err := gc.execFn("--unset-all", keyPrefix) + return err +} + +// return keyPrefix section +// example: sectionFromKey(a.b.c.d) return a.b.c +func sectionFromKey(keyPrefix string) string { + s := strings.Split(keyPrefix, ".") + if len(s) == 1 { + return keyPrefix + } + + return strings.Join(s[:len(s)-1], ".") +} + +// rmConfigs with git version lesser than 2.18 +func (gc *gitConfig) rmConfigsGitVersionLT218(keyPrefix string) error { + // try to remove key/value pair by key + err := gc.unsetAll(keyPrefix) + if err != nil { + return gc.rmSection(keyPrefix) + } + + m, err := gc.ReadAll(sectionFromKey(keyPrefix)) + if err != nil { + return err + } + + // if section doesn't have any left key/value remove the section + if len(m) == 0 { + return gc.rmSection(sectionFromKey(keyPrefix)) + } + + return nil +} + +// RmConfigs remove all key/value pair matching the key prefix +func (gc *gitConfig) RemoveAll(keyPrefix string) error { + // starting from git 2.18.0 sections are automatically deleted when the last existing + // key/value is removed. Before 2.18.0 we should remove the section + // see https://github.com/git/git/blob/master/Documentation/RelNotes/2.18.0.txt#L379 + lt218, err := gc.gitVersionLT218() + if err != nil { + return errors.Wrap(err, "getting git version") + } + + if lt218 { + return gc.rmConfigsGitVersionLT218(keyPrefix) + } + + err = gc.unsetAll(keyPrefix) + if err != nil { + return gc.rmSection(keyPrefix) + } + + return nil +} + +func (gc *gitConfig) gitVersionLT218() (bool, error) { + gitVersion218, err := semver.Make("2.18.0") + if err != nil { + return false, err + } + + return gc.version.LT(gitVersion218), nil +} diff --git a/repository/config_runtime.go b/repository/config_runtime.go new file mode 100644 index 00000000..8a17edb4 --- /dev/null +++ b/repository/config_runtime.go @@ -0,0 +1,59 @@ +package repository + +import ( + "strconv" + "strings" +) + +type runtimeConfig struct { + config map[string]string +} + +func newRuntimeConfig(config map[string]string) *runtimeConfig { + return &runtimeConfig{config: config} +} + +func (rtc *runtimeConfig) Store(key, value string) error { + rtc.config[key] = value + return nil +} + +func (rtc *runtimeConfig) ReadAll(keyPrefix string) (map[string]string, error) { + result := make(map[string]string) + for key, val := range rtc.config { + if strings.HasPrefix(key, keyPrefix) { + result[key] = val + } + } + return result, nil +} + +func (rtc *runtimeConfig) ReadString(key string) (string, error) { + // unlike git, the mock can only store one value for the same key + val, ok := rtc.config[key] + if !ok { + return "", ErrNoConfigEntry + } + + return val, nil +} + +func (rtc *runtimeConfig) ReadBool(key string) (bool, error) { + // unlike git, the mock can only store one value for the same key + val, ok := rtc.config[key] + if !ok { + return false, ErrNoConfigEntry + } + + return strconv.ParseBool(val) +} + +// RmConfigs remove all key/value pair matching the key prefix +func (rtc *runtimeConfig) RemoveAll(keyPrefix string) error { + for key := range rtc.config { + if strings.HasPrefix(key, keyPrefix) { + delete(rtc.config, key) + } + } + return nil +} diff --git a/repository/git.go b/repository/git.go index 93016cd9..5ca81c14 100644 --- a/repository/git.go +++ b/repository/git.go @@ -8,7 +8,6 @@ import ( "os/exec" "path" "regexp" - "strconv" "strings" "github.com/blang/semver" @@ -33,16 +32,26 @@ type GitRepo struct { editClock *lamport.Persisted } +// LocalConfig . +func (repo *GitRepo) LocalConfig() Config { + return NewGitConfig(repo, false) +} + +// GlobalConfig . +func (repo *GitRepo) GlobalConfig() Config { + return NewGitConfig(repo, true) +} + // 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 { - repopath:=repo.Path - if repopath==".git" { + repopath := repo.Path + if repopath == ".git" { // seeduvax> trangely the git command sometimes fail for very unknown // reason wihtout this replacement. // observed with rev-list command when git-bug is called from git // hook script, even the same command with same args runs perfectly - // when called directly from the same hook script. - repopath="" + // when called directly from the same hook script. + repopath = "" } // fmt.Printf("[%s] Running git %s\n", repopath, strings.Join(args, " ")) @@ -125,7 +134,7 @@ func NewGitRepo(path string, witnesser Witnesser) (*GitRepo, error) { // InitGitRepo create a new empty git repo at the given path func InitGitRepo(path string) (*GitRepo, error) { - repo := &GitRepo{Path: path+"/.git"} + repo := &GitRepo{Path: path + "/.git"} err := repo.createClocks() if err != nil { return nil, err @@ -197,149 +206,10 @@ func (repo *GitRepo) GetRemotes() (map[string]string, error) { return remotes, nil } -// StoreConfig store a single key/value pair in the config of the repo -func (repo *GitRepo) StoreConfig(key string, value string) error { - _, err := repo.runGitCommand("config", "--replace-all", key, value) - - return err -} - -// ReadConfigs read all key/value pair matching the key prefix -func (repo *GitRepo) ReadConfigs(keyPrefix string) (map[string]string, error) { - stdout, err := repo.runGitCommand("config", "--get-regexp", keyPrefix) - - // / \ - // / ! \ - // ------- - // - // There can be a legitimate error here, but I see no portable way to - // distinguish them from the git error that say "no matching value exist" - if err != nil { - return nil, nil - } - - lines := strings.Split(stdout, "\n") - - result := make(map[string]string, len(lines)) - - for _, line := range lines { - if strings.TrimSpace(line) == "" { - continue - } - - parts := strings.Fields(line) - if len(parts) != 2 { - return nil, fmt.Errorf("bad git config: %s", line) - } - - result[parts[0]] = parts[1] - } - - return result, nil -} - -func (repo *GitRepo) ReadConfigBool(key string) (bool, error) { - val, err := repo.ReadConfigString(key) - if err != nil { - return false, err - } - - return strconv.ParseBool(val) -} - -func (repo *GitRepo) ReadConfigString(key string) (string, error) { - stdout, err := repo.runGitCommand("config", "--get-all", key) - - // / \ - // / ! \ - // ------- - // - // There can be a legitimate error here, but I see no portable way to - // distinguish them from the git error that say "no matching value exist" - if err != nil { - return "", ErrNoConfigEntry - } - - lines := strings.Split(stdout, "\n") - - if len(lines) == 0 { - return "", ErrNoConfigEntry - } - if len(lines) > 1 { - return "", ErrMultipleConfigEntry - } - - return lines[0], nil -} - -func (repo *GitRepo) rmSection(keyPrefix string) error { - _, err := repo.runGitCommand("config", "--remove-section", keyPrefix) - return err -} - -func (repo *GitRepo) unsetAll(keyPrefix string) error { - _, err := repo.runGitCommand("config", "--unset-all", keyPrefix) - return err -} - -// return keyPrefix section -// example: sectionFromKey(a.b.c.d) return a.b.c -func sectionFromKey(keyPrefix string) string { - s := strings.Split(keyPrefix, ".") - if len(s) == 1 { - return keyPrefix - } - - return strings.Join(s[:len(s)-1], ".") -} - -// rmConfigs with git version lesser than 2.18 -func (repo *GitRepo) rmConfigsGitVersionLT218(keyPrefix string) error { - // try to remove key/value pair by key - err := repo.unsetAll(keyPrefix) - if err != nil { - return repo.rmSection(keyPrefix) - } - - m, err := repo.ReadConfigs(sectionFromKey(keyPrefix)) - if err != nil { - return err - } - - // if section doesn't have any left key/value remove the section - if len(m) == 0 { - return repo.rmSection(sectionFromKey(keyPrefix)) - } - - return nil -} - -// RmConfigs remove all key/value pair matching the key prefix -func (repo *GitRepo) RmConfigs(keyPrefix string) error { - // starting from git 2.18.0 sections are automatically deleted when the last existing - // key/value is removed. Before 2.18.0 we should remove the section - // see https://github.com/git/git/blob/master/Documentation/RelNotes/2.18.0.txt#L379 - lt218, err := repo.gitVersionLT218() - if err != nil { - return errors.Wrap(err, "getting git version") - } - - if lt218 { - return repo.rmConfigsGitVersionLT218(keyPrefix) - } - - err = repo.unsetAll(keyPrefix) - if err != nil { - return repo.rmSection(keyPrefix) - } - - return nil -} - -func (repo *GitRepo) gitVersionLT218() (bool, error) { +func (repo *GitRepo) GitVersion() (*semver.Version, error) { versionOut, err := repo.runGitCommand("version") if err != nil { - return false, err + return nil, err } // extract the version and truncate potential bad parts @@ -348,10 +218,19 @@ func (repo *GitRepo) gitVersionLT218() (bool, error) { extracted := r.FindString(versionOut) if extracted == "" { - return false, fmt.Errorf("unreadable git version %s", versionOut) + return nil, fmt.Errorf("unreadable git version %s", versionOut) } version, err := semver.Make(extracted) + if err != nil { + return nil, err + } + + return &version, nil +} + +func (repo *GitRepo) gitVersionLT218() (bool, error) { + version, err := repo.GitVersion() if err != nil { return false, err } diff --git a/repository/git_test.go b/repository/git_test.go index 20bf6ec3..628e7911 100644 --- a/repository/git_test.go +++ b/repository/git_test.go @@ -11,56 +11,57 @@ func TestConfig(t *testing.T) { repo := CreateTestRepo(false) defer CleanupTestRepos(t, repo) - err := repo.StoreConfig("section.key", "value") + config := repo.LocalConfig() + + err := config.Store("section.key", "value") assert.NoError(t, err) - val, err := repo.ReadConfigString("section.key") + val, err := config.ReadString("section.key") assert.Equal(t, "value", val) - err = repo.StoreConfig("section.true", "true") + err = config.Store("section.true", "true") assert.NoError(t, err) - val2, err := repo.ReadConfigBool("section.true") + val2, err := config.ReadBool("section.true") assert.Equal(t, true, val2) - configs, err := repo.ReadConfigs("section") + configs, err := config.ReadAll("section") assert.NoError(t, err) assert.Equal(t, configs, map[string]string{ "section.key": "value", "section.true": "true", }) - err = repo.RmConfigs("section.true") + err = config.RemoveAll("section.true") assert.NoError(t, err) - configs, err = repo.ReadConfigs("section") + configs, err = config.ReadAll("section") assert.NoError(t, err) assert.Equal(t, configs, map[string]string{ "section.key": "value", }) - _, err = repo.ReadConfigBool("section.true") + _, err = config.ReadBool("section.true") assert.Equal(t, ErrNoConfigEntry, err) - err = repo.RmConfigs("section.nonexistingkey") + err = config.RemoveAll("section.nonexistingkey") assert.Error(t, err) - err = repo.RmConfigs("section.key") + err = config.RemoveAll("section.key") assert.NoError(t, err) - _, err = repo.ReadConfigString("section.key") + _, err = config.ReadString("section.key") assert.Equal(t, ErrNoConfigEntry, err) - err = repo.RmConfigs("nonexistingsection") + err = config.RemoveAll("nonexistingsection") assert.Error(t, err) - err = repo.RmConfigs("section") + err = config.RemoveAll("section") assert.Error(t, err) - _, err = repo.ReadConfigString("section.key") + _, err = config.ReadString("section.key") assert.Error(t, err) - err = repo.RmConfigs("section.key") + err = config.RemoveAll("section.key") assert.Error(t, err) - } diff --git a/repository/git_testing.go b/repository/git_testing.go index 36c53c1d..5f1eaf7c 100644 --- a/repository/git_testing.go +++ b/repository/git_testing.go @@ -31,10 +31,11 @@ func CreateTestRepo(bare bool) *GitRepo { log.Fatal(err) } - if err := repo.StoreConfig("user.name", "testuser"); err != nil { + config := repo.LocalConfig() + if err := config.Store("user.name", "testuser"); err != nil { log.Fatal("failed to set user.name for test repository: ", err) } - if err := repo.StoreConfig("user.email", "testuser@example.com"); err != nil { + if err := config.Store("user.email", "testuser@example.com"); err != nil { log.Fatal("failed to set user.email for test repository: ", err) } diff --git a/repository/mock_repo.go b/repository/mock_repo.go index 23534b89..356f59d8 100644 --- a/repository/mock_repo.go +++ b/repository/mock_repo.go @@ -14,13 +14,14 @@ var _ ClockedRepo = &mockRepoForTest{} // mockRepoForTest defines an instance of Repo that can be used for testing. type mockRepoForTest struct { - config map[string]string - blobs map[git.Hash][]byte - trees map[git.Hash]string - commits map[git.Hash]commit - refs map[string]git.Hash - createClock lamport.Clock - editClock lamport.Clock + config map[string]string + globalConfig map[string]string + blobs map[git.Hash][]byte + trees map[git.Hash]string + commits map[git.Hash]commit + refs map[string]git.Hash + createClock lamport.Clock + editClock lamport.Clock } type commit struct { @@ -40,6 +41,14 @@ func NewMockRepoForTest() *mockRepoForTest { } } +func (r *mockRepoForTest) LocalConfig() Config { + return newRuntimeConfig(r.config) +} + +func (r *mockRepoForTest) GlobalConfig() Config { + return newRuntimeConfig(r.globalConfig) +} + // GetPath returns the path to the repo. func (r *mockRepoForTest) GetPath() string { return "~/mockRepo/" diff --git a/repository/repo.go b/repository/repo.go index 44204493..f17d594b 100644 --- a/repository/repo.go +++ b/repository/repo.go @@ -30,24 +30,11 @@ type RepoCommon interface { // GetRemotes returns the configured remotes repositories. GetRemotes() (map[string]string, error) - // StoreConfig store a single key/value pair in the config of the repo - StoreConfig(key string, value string) error + // LocalConfig . + LocalConfig() Config - // ReadConfigs read all key/value pair matching the key prefix - ReadConfigs(keyPrefix string) (map[string]string, error) - - // ReadConfigBool read a single boolean value from the config - // Return ErrNoConfigEntry or ErrMultipleConfigEntry if there is zero or more than one entry - // for this key - ReadConfigBool(key string) (bool, error) - - // ReadConfigBool read a single string value from the config - // Return ErrNoConfigEntry or ErrMultipleConfigEntry if there is zero or more than one entry - // for this key - ReadConfigString(key string) (string, error) - - // RmConfigs remove all key/value pair matching the key prefix - RmConfigs(keyPrefix string) error + // GlobalConfig . + GlobalConfig() Config } // Repo represents a source code repository. -- cgit From 7f177c4750b4acf70cc3fd3d43c19685179e527b Mon Sep 17 00:00:00 2001 From: amine Date: Thu, 31 Oct 2019 19:05:50 +0100 Subject: repository: add ReadTimestamp methods and improve naming --- repository/config.go | 7 +++++ repository/config_git.go | 21 +++++++++++-- repository/config_mem.go | 74 ++++++++++++++++++++++++++++++++++++++++++++ repository/config_runtime.go | 59 ----------------------------------- repository/git.go | 4 +-- repository/mock_repo.go | 4 +-- 6 files changed, 104 insertions(+), 65 deletions(-) create mode 100644 repository/config_mem.go delete mode 100644 repository/config_runtime.go diff --git a/repository/config.go b/repository/config.go index a2bb33fd..70f11081 100644 --- a/repository/config.go +++ b/repository/config.go @@ -1,5 +1,7 @@ package repository +import "time" + // Config represent the common function interacting with the repository config storage type Config interface { // Store writes a single key/value pair in the config of the repo @@ -18,6 +20,11 @@ type Config interface { // there is zero or more than one entry for this key ReadString(key string) (string, error) + // ReadTimestamp read a single timestamp value from the config + // Return ErrNoConfigEntry or ErrMultipleConfigEntry if + // there is zero or more than one entry for this key + ReadTimestamp(key string) (*time.Time, error) + // RemoveAll removes all key/value pair matching the key prefix RemoveAll(keyPrefix string) error } diff --git a/repository/config_git.go b/repository/config_git.go index 81b9b819..80b23cc7 100644 --- a/repository/config_git.go +++ b/repository/config_git.go @@ -4,17 +4,20 @@ import ( "fmt" "strconv" "strings" + "time" "github.com/blang/semver" "github.com/pkg/errors" ) +var _ Config = &gitConfig{} + type gitConfig struct { version *semver.Version execFn func(args ...string) (string, error) } -func NewGitConfig(repo *GitRepo, global bool) *gitConfig { +func newGitConfig(repo *GitRepo, global bool) *gitConfig { version, _ := repo.GitVersion() if global { @@ -29,7 +32,7 @@ func NewGitConfig(repo *GitRepo, global bool) *gitConfig { return &gitConfig{ execFn: func(args ...string) (string, error) { - args = append([]string{"config"}, args...) + args = append([]string{"config", "--local"}, args...) return repo.runGitCommand(args...) }, version: version, @@ -111,6 +114,20 @@ func (gc *gitConfig) ReadBool(key string) (bool, error) { return strconv.ParseBool(val) } +func (gc *gitConfig) ReadTimestamp(key string) (*time.Time, error) { + value, err := gc.ReadString(key) + if err != nil { + return nil, err + } + timestamp, err := strconv.Atoi(value) + if err != nil { + return nil, err + } + + t := time.Unix(int64(timestamp), 0) + return &t, nil +} + func (gc *gitConfig) rmSection(keyPrefix string) error { _, err := gc.execFn("--remove-section", keyPrefix) return err diff --git a/repository/config_mem.go b/repository/config_mem.go new file mode 100644 index 00000000..e8809f5e --- /dev/null +++ b/repository/config_mem.go @@ -0,0 +1,74 @@ +package repository + +import ( + "strconv" + "strings" + "time" +) + +type memConfig struct { + config map[string]string +} + +func newMemConfig(config map[string]string) *memConfig { + return &memConfig{config: config} +} + +func (mc *memConfig) Store(key, value string) error { + mc.config[key] = value + return nil +} + +func (mc *memConfig) ReadAll(keyPrefix string) (map[string]string, error) { + result := make(map[string]string) + for key, val := range mc.config { + if strings.HasPrefix(key, keyPrefix) { + result[key] = val + } + } + return result, nil +} + +func (mc *memConfig) ReadString(key string) (string, error) { + // unlike git, the mock can only store one value for the same key + val, ok := mc.config[key] + if !ok { + return "", ErrNoConfigEntry + } + + return val, nil +} + +func (mc *memConfig) ReadBool(key string) (bool, error) { + // unlike git, the mock can only store one value for the same key + val, ok := mc.config[key] + if !ok { + return false, ErrNoConfigEntry + } + + return strconv.ParseBool(val) +} + +func (mc *memConfig) ReadTimestamp(key string) (*time.Time, error) { + value, err := mc.ReadString(key) + if err != nil { + return nil, err + } + timestamp, err := strconv.Atoi(value) + if err != nil { + return nil, err + } + + t := time.Unix(int64(timestamp), 0) + return &t, nil +} + +// RmConfigs remove all key/value pair matching the key prefix +func (mc *memConfig) RemoveAll(keyPrefix string) error { + for key := range mc.config { + if strings.HasPrefix(key, keyPrefix) { + delete(mc.config, key) + } + } + return nil +} diff --git a/repository/config_runtime.go b/repository/config_runtime.go deleted file mode 100644 index 8a17edb4..00000000 --- a/repository/config_runtime.go +++ /dev/null @@ -1,59 +0,0 @@ -package repository - -import ( - "strconv" - "strings" -) - -type runtimeConfig struct { - config map[string]string -} - -func newRuntimeConfig(config map[string]string) *runtimeConfig { - return &runtimeConfig{config: config} -} - -func (rtc *runtimeConfig) Store(key, value string) error { - rtc.config[key] = value - return nil -} - -func (rtc *runtimeConfig) ReadAll(keyPrefix string) (map[string]string, error) { - result := make(map[string]string) - for key, val := range rtc.config { - if strings.HasPrefix(key, keyPrefix) { - result[key] = val - } - } - return result, nil -} - -func (rtc *runtimeConfig) ReadString(key string) (string, error) { - // unlike git, the mock can only store one value for the same key - val, ok := rtc.config[key] - if !ok { - return "", ErrNoConfigEntry - } - - return val, nil -} - -func (rtc *runtimeConfig) ReadBool(key string) (bool, error) { - // unlike git, the mock can only store one value for the same key - val, ok := rtc.config[key] - if !ok { - return false, ErrNoConfigEntry - } - - return strconv.ParseBool(val) -} - -// RmConfigs remove all key/value pair matching the key prefix -func (rtc *runtimeConfig) RemoveAll(keyPrefix string) error { - for key := range rtc.config { - if strings.HasPrefix(key, keyPrefix) { - delete(rtc.config, key) - } - } - return nil -} diff --git a/repository/git.go b/repository/git.go index 5ca81c14..c25309f5 100644 --- a/repository/git.go +++ b/repository/git.go @@ -34,12 +34,12 @@ type GitRepo struct { // LocalConfig . func (repo *GitRepo) LocalConfig() Config { - return NewGitConfig(repo, false) + return newGitConfig(repo, false) } // GlobalConfig . func (repo *GitRepo) GlobalConfig() Config { - return NewGitConfig(repo, true) + return newGitConfig(repo, true) } // Run the given git command with the given I/O reader/writers, returning an error if it fails. diff --git a/repository/mock_repo.go b/repository/mock_repo.go index 356f59d8..bdf36ac2 100644 --- a/repository/mock_repo.go +++ b/repository/mock_repo.go @@ -42,11 +42,11 @@ func NewMockRepoForTest() *mockRepoForTest { } func (r *mockRepoForTest) LocalConfig() Config { - return newRuntimeConfig(r.config) + return newMemConfig(r.config) } func (r *mockRepoForTest) GlobalConfig() Config { - return newRuntimeConfig(r.globalConfig) + return newMemConfig(r.globalConfig) } // GetPath returns the path to the repo. -- cgit From 104224c9f081fbe79757976a8c1f903ae94c3f8a Mon Sep 17 00:00:00 2001 From: amine Date: Fri, 1 Nov 2019 18:39:45 +0100 Subject: repository: add StoreTimestamp/StoreBool to the config interface repository: move the gitVersion logic to *gitConfig struct --- repository/config.go | 25 ++++++++++++-- repository/config_git.go | 86 ++++++++++++++++++++++++++++++----------------- repository/config_mem.go | 12 ++++++- repository/git.go | 40 ---------------------- repository/git_test.go | 4 +-- repository/git_testing.go | 4 +-- 6 files changed, 93 insertions(+), 78 deletions(-) diff --git a/repository/config.go b/repository/config.go index 70f11081..ec5094e0 100644 --- a/repository/config.go +++ b/repository/config.go @@ -1,11 +1,20 @@ package repository -import "time" +import ( + "strconv" + "time" +) // Config represent the common function interacting with the repository config storage type Config interface { - // Store writes a single key/value pair in the config of the repo - Store(key string, value string) error + // Store writes a single key/value pair in the config + StoreString(key, value string) error + + // Store writes a key and timestamp value to the config + StoreTimestamp(key string, value time.Time) error + + // Store writes a key and boolean value to the config + StoreBool(key string, value bool) error // ReadAll reads all key/value pair matching the key prefix ReadAll(keyPrefix string) (map[string]string, error) @@ -28,3 +37,13 @@ type Config interface { // RemoveAll removes all key/value pair matching the key prefix RemoveAll(keyPrefix string) error } + +func parseTimestamp(s string) (*time.Time, error) { + timestamp, err := strconv.Atoi(s) + if err != nil { + return nil, err + } + + t := time.Unix(int64(timestamp), 0) + return &t, nil +} diff --git a/repository/config_git.go b/repository/config_git.go index 80b23cc7..67ca3436 100644 --- a/repository/config_git.go +++ b/repository/config_git.go @@ -2,6 +2,7 @@ package repository import ( "fmt" + "regexp" "strconv" "strings" "time" @@ -13,42 +14,41 @@ import ( var _ Config = &gitConfig{} type gitConfig struct { - version *semver.Version - execFn func(args ...string) (string, error) + execFn func(args ...string) (string, error) } func newGitConfig(repo *GitRepo, global bool) *gitConfig { - version, _ := repo.GitVersion() - + configCmdFlag := "--local" if global { - return &gitConfig{ - execFn: func(args ...string) (string, error) { - args = append([]string{"config", "--global"}, args...) - return repo.runGitCommand(args...) - }, - version: version, - } + configCmdFlag = "--global" } - return &gitConfig{ execFn: func(args ...string) (string, error) { - args = append([]string{"config", "--local"}, args...) + if len(args) > 0 && args[0] == "config" { + args = append([]string{args[0], configCmdFlag}, args[1:]...) + } return repo.runGitCommand(args...) }, - version: version, } } // StoreConfig store a single key/value pair in the config of the repo -func (gc *gitConfig) Store(key string, value string) error { - _, err := gc.execFn("--replace-all", key, value) - +func (gc *gitConfig) StoreString(key string, value string) error { + _, err := gc.execFn("config", "--replace-all", key, value) return err } +func (gc *gitConfig) StoreBool(key string, value bool) error { + return gc.StoreString(key, strconv.FormatBool(value)) +} + +func (gc *gitConfig) StoreTimestamp(key string, value time.Time) error { + return gc.StoreString(key, strconv.Itoa(int(value.Unix()))) +} + // ReadConfigs read all key/value pair matching the key prefix func (gc *gitConfig) ReadAll(keyPrefix string) (map[string]string, error) { - stdout, err := gc.execFn("--get-regexp", keyPrefix) + stdout, err := gc.execFn("config", "--get-regexp", keyPrefix) // / \ // / ! \ @@ -81,7 +81,7 @@ func (gc *gitConfig) ReadAll(keyPrefix string) (map[string]string, error) { } func (gc *gitConfig) ReadString(key string) (string, error) { - stdout, err := gc.execFn("--get-all", key) + stdout, err := gc.execFn("config", "--get-all", key) // / \ // / ! \ @@ -119,22 +119,16 @@ func (gc *gitConfig) ReadTimestamp(key string) (*time.Time, error) { if err != nil { return nil, err } - timestamp, err := strconv.Atoi(value) - if err != nil { - return nil, err - } - - t := time.Unix(int64(timestamp), 0) - return &t, nil + return parseTimestamp(value) } func (gc *gitConfig) rmSection(keyPrefix string) error { - _, err := gc.execFn("--remove-section", keyPrefix) + _, err := gc.execFn("config", "--remove-section", keyPrefix) return err } func (gc *gitConfig) unsetAll(keyPrefix string) error { - _, err := gc.execFn("--unset-all", keyPrefix) + _, err := gc.execFn("config", "--unset-all", keyPrefix) return err } @@ -192,11 +186,43 @@ func (gc *gitConfig) RemoveAll(keyPrefix string) error { return nil } +func (gc *gitConfig) gitVersion() (*semver.Version, error) { + versionOut, err := gc.execFn("version") + if err != nil { + return nil, err + } + return parseGitVersion(versionOut) +} + +func parseGitVersion(versionOut string) (*semver.Version, error) { + // extract the version and truncate potential bad parts + // ex: 2.23.0.rc1 instead of 2.23.0-rc1 + r := regexp.MustCompile(`(\d+\.){1,2}\d+`) + + extracted := r.FindString(versionOut) + if extracted == "" { + return nil, fmt.Errorf("unreadable git version %s", versionOut) + } + + version, err := semver.Make(extracted) + if err != nil { + return nil, err + } + + return &version, nil +} + func (gc *gitConfig) gitVersionLT218() (bool, error) { - gitVersion218, err := semver.Make("2.18.0") + version, err := gc.gitVersion() + if err != nil { + return false, err + } + + version218string := "2.18.0" + gitVersion218, err := semver.Make(version218string) if err != nil { return false, err } - return gc.version.LT(gitVersion218), nil + return version.LT(gitVersion218), nil } diff --git a/repository/config_mem.go b/repository/config_mem.go index e8809f5e..e2cffd9c 100644 --- a/repository/config_mem.go +++ b/repository/config_mem.go @@ -6,6 +6,8 @@ import ( "time" ) +var _ Config = &memConfig{} + type memConfig struct { config map[string]string } @@ -14,11 +16,19 @@ func newMemConfig(config map[string]string) *memConfig { return &memConfig{config: config} } -func (mc *memConfig) Store(key, value string) error { +func (mc *memConfig) StoreString(key, value string) error { mc.config[key] = value return nil } +func (mc *memConfig) StoreBool(key string, value bool) error { + return mc.StoreString(key, strconv.FormatBool(value)) +} + +func (mc *memConfig) StoreTimestamp(key string, value time.Time) error { + return mc.StoreString(key, strconv.Itoa(int(value.Unix()))) +} + func (mc *memConfig) ReadAll(keyPrefix string) (map[string]string, error) { result := make(map[string]string) for key, val := range mc.config { diff --git a/repository/git.go b/repository/git.go index c25309f5..0951b577 100644 --- a/repository/git.go +++ b/repository/git.go @@ -7,10 +7,8 @@ import ( "io" "os/exec" "path" - "regexp" "strings" - "github.com/blang/semver" "github.com/pkg/errors" "github.com/MichaelMure/git-bug/util/git" @@ -206,44 +204,6 @@ func (repo *GitRepo) GetRemotes() (map[string]string, error) { return remotes, nil } -func (repo *GitRepo) GitVersion() (*semver.Version, error) { - versionOut, err := repo.runGitCommand("version") - if err != nil { - return nil, err - } - - // extract the version and truncate potential bad parts - // ex: 2.23.0.rc1 instead of 2.23.0-rc1 - r := regexp.MustCompile(`(\d+\.){1,2}\d+`) - - extracted := r.FindString(versionOut) - if extracted == "" { - return nil, fmt.Errorf("unreadable git version %s", versionOut) - } - - version, err := semver.Make(extracted) - if err != nil { - return nil, err - } - - return &version, nil -} - -func (repo *GitRepo) gitVersionLT218() (bool, error) { - version, err := repo.GitVersion() - if err != nil { - return false, err - } - - version218string := "2.18.0" - gitVersion218, err := semver.Make(version218string) - if err != nil { - return false, err - } - - return version.LT(gitVersion218), nil -} - // FetchRefs fetch git refs from a remote func (repo *GitRepo) FetchRefs(remote, refSpec string) (string, error) { stdout, err := repo.runGitCommand("fetch", remote, refSpec) diff --git a/repository/git_test.go b/repository/git_test.go index 628e7911..cb115526 100644 --- a/repository/git_test.go +++ b/repository/git_test.go @@ -13,13 +13,13 @@ func TestConfig(t *testing.T) { config := repo.LocalConfig() - err := config.Store("section.key", "value") + err := config.StoreString("section.key", "value") assert.NoError(t, err) val, err := config.ReadString("section.key") assert.Equal(t, "value", val) - err = config.Store("section.true", "true") + err = config.StoreString("section.true", "true") assert.NoError(t, err) val2, err := config.ReadBool("section.true") diff --git a/repository/git_testing.go b/repository/git_testing.go index 5f1eaf7c..37a15d93 100644 --- a/repository/git_testing.go +++ b/repository/git_testing.go @@ -32,10 +32,10 @@ func CreateTestRepo(bare bool) *GitRepo { } config := repo.LocalConfig() - if err := config.Store("user.name", "testuser"); err != nil { + if err := config.StoreString("user.name", "testuser"); err != nil { log.Fatal("failed to set user.name for test repository: ", err) } - if err := config.Store("user.email", "testuser@example.com"); err != nil { + if err := config.StoreString("user.email", "testuser@example.com"); err != nil { log.Fatal("failed to set user.email for test repository: ", err) } -- cgit From 93048080705cb9f3806fa456dc0642e3a143849b Mon Sep 17 00:00:00 2001 From: amine Date: Fri, 1 Nov 2019 21:37:16 +0100 Subject: repository: use `repo.runGitCommand` and `flagLocality` instead of execFn --- repository/config_git.go | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/repository/config_git.go b/repository/config_git.go index 67ca3436..bdc86201 100644 --- a/repository/config_git.go +++ b/repository/config_git.go @@ -14,27 +14,24 @@ import ( var _ Config = &gitConfig{} type gitConfig struct { - execFn func(args ...string) (string, error) + repo *GitRepo + localityFlag string } func newGitConfig(repo *GitRepo, global bool) *gitConfig { - configCmdFlag := "--local" + localityFlag := "--local" if global { - configCmdFlag = "--global" + localityFlag = "--global" } return &gitConfig{ - execFn: func(args ...string) (string, error) { - if len(args) > 0 && args[0] == "config" { - args = append([]string{args[0], configCmdFlag}, args[1:]...) - } - return repo.runGitCommand(args...) - }, + repo: repo, + localityFlag: localityFlag, } } // StoreConfig store a single key/value pair in the config of the repo func (gc *gitConfig) StoreString(key string, value string) error { - _, err := gc.execFn("config", "--replace-all", key, value) + _, err := gc.repo.runGitCommand("config", "gc.localityFlag", "--replace-all", key, value) return err } @@ -48,7 +45,7 @@ func (gc *gitConfig) StoreTimestamp(key string, value time.Time) error { // ReadConfigs read all key/value pair matching the key prefix func (gc *gitConfig) ReadAll(keyPrefix string) (map[string]string, error) { - stdout, err := gc.execFn("config", "--get-regexp", keyPrefix) + stdout, err := gc.repo.runGitCommand("config", "gc.localityFlag", "--get-regexp", keyPrefix) // / \ // / ! \ @@ -81,7 +78,7 @@ func (gc *gitConfig) ReadAll(keyPrefix string) (map[string]string, error) { } func (gc *gitConfig) ReadString(key string) (string, error) { - stdout, err := gc.execFn("config", "--get-all", key) + stdout, err := gc.repo.runGitCommand("config", "gc.localityFlag", "--get-all", key) // / \ // / ! \ @@ -123,12 +120,12 @@ func (gc *gitConfig) ReadTimestamp(key string) (*time.Time, error) { } func (gc *gitConfig) rmSection(keyPrefix string) error { - _, err := gc.execFn("config", "--remove-section", keyPrefix) + _, err := gc.repo.runGitCommand("config", "gc.localityFlag", "--remove-section", keyPrefix) return err } func (gc *gitConfig) unsetAll(keyPrefix string) error { - _, err := gc.execFn("config", "--unset-all", keyPrefix) + _, err := gc.repo.runGitCommand("config", "gc.localityFlag", "--unset-all", keyPrefix) return err } @@ -187,7 +184,7 @@ func (gc *gitConfig) RemoveAll(keyPrefix string) error { } func (gc *gitConfig) gitVersion() (*semver.Version, error) { - versionOut, err := gc.execFn("version") + versionOut, err := gc.repo.runGitCommand("version") if err != nil { return nil, err } -- cgit From b85b2c57a73a6068fdc446866f79115315082997 Mon Sep 17 00:00:00 2001 From: amine Date: Fri, 1 Nov 2019 21:47:34 +0100 Subject: repository: improve documentation and fix typo mistake --- repository/config_git.go | 10 +++++----- repository/git.go | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/repository/config_git.go b/repository/config_git.go index bdc86201..22666de7 100644 --- a/repository/config_git.go +++ b/repository/config_git.go @@ -31,7 +31,7 @@ func newGitConfig(repo *GitRepo, global bool) *gitConfig { // StoreConfig 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.repo.runGitCommand("config", gc.localityFlag, "--replace-all", key, value) return err } @@ -45,7 +45,7 @@ func (gc *gitConfig) StoreTimestamp(key string, value time.Time) error { // ReadConfigs 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", "--get-regexp", keyPrefix) + stdout, err := gc.repo.runGitCommand("config", gc.localityFlag, "--get-regexp", keyPrefix) // / \ // / ! \ @@ -78,7 +78,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", "--get-all", key) + stdout, err := gc.repo.runGitCommand("config", gc.localityFlag, "--get-all", key) // / \ // / ! \ @@ -120,12 +120,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.repo.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.repo.runGitCommand("config", gc.localityFlag, "--unset-all", keyPrefix) return err } diff --git a/repository/git.go b/repository/git.go index 0951b577..2b00d1f2 100644 --- a/repository/git.go +++ b/repository/git.go @@ -30,12 +30,12 @@ type GitRepo struct { editClock *lamport.Persisted } -// LocalConfig . +// LocalConfig give access to the repository scoped configuration func (repo *GitRepo) LocalConfig() Config { return newGitConfig(repo, false) } -// GlobalConfig . +// GlobalConfig give access to the git global configuration func (repo *GitRepo) GlobalConfig() Config { return newGitConfig(repo, true) } -- cgit From 618f896f667b272c1272b1289c8ff3f3310c3168 Mon Sep 17 00:00:00 2001 From: amine Date: Fri, 1 Nov 2019 22:01:21 +0100 Subject: cache: update RepoCache and identity to use new repository Config --- cache/repo_cache.go | 35 ++++++++++------------------------- identity/identity.go | 8 ++++---- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/cache/repo_cache.go b/cache/repo_cache.go index bc095856..ec4cf436 100644 --- a/cache/repo_cache.go +++ b/cache/repo_cache.go @@ -99,6 +99,16 @@ func NewRepoCache(r repository.ClockedRepo) (*RepoCache, error) { return c, c.write() } +// LocalConfig give access to the repository scoped configuration +func (c *RepoCache) LocalConfig() repository.Config { + return c.repo.LocalConfig() +} + +// GlobalConfig give access to the git global configuration +func (c *RepoCache) GlobalConfig() repository.Config { + return c.repo.GlobalConfig() +} + // GetPath returns the path to the repo. func (c *RepoCache) GetPath() string { return c.repo.GetPath() @@ -124,31 +134,6 @@ func (c *RepoCache) GetUserEmail() (string, error) { return c.repo.GetUserEmail() } -// StoreConfig store a single key/value pair in the config of the repo -func (c *RepoCache) StoreConfig(key string, value string) error { - return c.repo.StoreConfig(key, value) -} - -// ReadConfigs read all key/value pair matching the key prefix -func (c *RepoCache) ReadConfigs(keyPrefix string) (map[string]string, error) { - return c.repo.ReadConfigs(keyPrefix) -} - -// ReadConfigBool read a single boolean value from the config -func (c *RepoCache) ReadConfigBool(key string) (bool, error) { - return c.repo.ReadConfigBool(key) -} - -// ReadConfigBool read a single string value from the config -func (c *RepoCache) ReadConfigString(key string) (string, error) { - return c.repo.ReadConfigString(key) -} - -// RmConfigs remove all key/value pair matching the key prefix -func (c *RepoCache) RmConfigs(keyPrefix string) error { - return c.repo.RmConfigs(keyPrefix) -} - func (c *RepoCache) lock() error { lockPath := repoLockFilePath(c.repo) diff --git a/identity/identity.go b/identity/identity.go index 765b77cd..b7d44a4b 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -220,7 +220,7 @@ func NewFromGitUser(repo repository.Repo) (*Identity, error) { // IsUserIdentitySet tell if the user identity is correctly set. func IsUserIdentitySet(repo repository.RepoCommon) (bool, error) { - configs, err := repo.ReadConfigs(identityConfigKey) + configs, err := repo.LocalConfig().ReadAll(identityConfigKey) if err != nil { return false, err } @@ -234,12 +234,12 @@ func IsUserIdentitySet(repo repository.RepoCommon) (bool, error) { // SetUserIdentity store the user identity's id in the git config func SetUserIdentity(repo repository.RepoCommon, identity *Identity) error { - return repo.StoreConfig(identityConfigKey, identity.Id().String()) + return repo.LocalConfig().StoreString(identityConfigKey, identity.Id().String()) } // GetUserIdentity read the current user identity, set with a git config entry func GetUserIdentity(repo repository.Repo) (*Identity, error) { - configs, err := repo.ReadConfigs(identityConfigKey) + configs, err := repo.LocalConfig().ReadAll(identityConfigKey) if err != nil { return nil, err } @@ -263,7 +263,7 @@ func GetUserIdentity(repo repository.Repo) (*Identity, error) { i, err := ReadLocal(repo, id) if err == ErrIdentityNotExist { - innerErr := repo.RmConfigs(identityConfigKey) + innerErr := repo.LocalConfig().RemoveAll(identityConfigKey) if innerErr != nil { _, _ = fmt.Fprintln(os.Stderr, errors.Wrap(innerErr, "can't clear user identity").Error()) } -- cgit From 60c6bd360f164b8f955b21cd1d0bc0cca6e5cb51 Mon Sep 17 00:00:00 2001 From: amine Date: Fri, 1 Nov 2019 22:40:21 +0100 Subject: bridge: use new repository configuration interface commands/webui: use new repository configuration interface --- bridge/core/bridge.go | 10 +++++----- commands/webui.go | 2 +- repository/config_git.go | 4 ++-- repository/git_test.go | 32 ++++++++++++++---------------- repository/mock_repo.go | 51 ++---------------------------------------------- repository/repo.go | 4 ++-- 6 files changed, 27 insertions(+), 76 deletions(-) diff --git a/bridge/core/bridge.go b/bridge/core/bridge.go index 6fd28b03..47a89389 100644 --- a/bridge/core/bridge.go +++ b/bridge/core/bridge.go @@ -134,7 +134,7 @@ func DefaultBridge(repo *cache.RepoCache) (*Bridge, error) { // ConfiguredBridges return the list of bridge that are configured for the given // repo func ConfiguredBridges(repo repository.RepoCommon) ([]string, error) { - configs, err := repo.ReadConfigs(bridgeConfigKeyPrefix + ".") + configs, err := repo.LocalConfig().ReadAll(bridgeConfigKeyPrefix + ".") if err != nil { return nil, errors.Wrap(err, "can't read configured bridges") } @@ -171,7 +171,7 @@ func ConfiguredBridges(repo repository.RepoCommon) ([]string, error) { func BridgeExist(repo repository.RepoCommon, name string) bool { keyPrefix := fmt.Sprintf("git-bug.bridge.%s.", name) - conf, err := repo.ReadConfigs(keyPrefix) + conf, err := repo.LocalConfig().ReadAll(keyPrefix) return err == nil && len(conf) > 0 } @@ -188,7 +188,7 @@ func RemoveBridge(repo repository.RepoCommon, name string) error { } keyPrefix := fmt.Sprintf("git-bug.bridge.%s", name) - return repo.RmConfigs(keyPrefix) + return repo.LocalConfig().RemoveAll(keyPrefix) } // Configure run the target specific configuration process @@ -211,7 +211,7 @@ func (b *Bridge) storeConfig(conf Configuration) error { for key, val := range conf { storeKey := fmt.Sprintf("git-bug.bridge.%s.%s", b.Name, key) - err := b.repo.StoreConfig(storeKey, val) + err := b.repo.LocalConfig().StoreString(storeKey, val) if err != nil { return errors.Wrap(err, "error while storing bridge configuration") } @@ -235,7 +235,7 @@ func (b *Bridge) ensureConfig() error { func loadConfig(repo repository.RepoCommon, name string) (Configuration, error) { keyPrefix := fmt.Sprintf("git-bug.bridge.%s.", name) - pairs, err := repo.ReadConfigs(keyPrefix) + pairs, err := repo.LocalConfig().ReadAll(keyPrefix) if err != nil { return nil, errors.Wrap(err, "error while reading bridge configuration") } diff --git a/commands/webui.go b/commands/webui.go index d6b6a661..8e735e55 100644 --- a/commands/webui.go +++ b/commands/webui.go @@ -100,7 +100,7 @@ func runWebUI(cmd *cobra.Command, args []string) error { fmt.Printf("Graphql Playground: http://%s/playground\n", addr) fmt.Println("Press Ctrl+c to quit") - configOpen, err := repo.ReadConfigBool(webUIOpenConfigKey) + configOpen, err := repo.LocalConfig().ReadBool(webUIOpenConfigKey) if err == repository.ErrNoConfigEntry { // default to true configOpen = true diff --git a/repository/config_git.go b/repository/config_git.go index 22666de7..eac882a2 100644 --- a/repository/config_git.go +++ b/repository/config_git.go @@ -29,7 +29,7 @@ func newGitConfig(repo *GitRepo, global bool) *gitConfig { } } -// StoreConfig store a single key/value pair in the config of the repo +// 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) return err @@ -43,7 +43,7 @@ func (gc *gitConfig) StoreTimestamp(key string, value time.Time) error { return gc.StoreString(key, strconv.Itoa(int(value.Unix()))) } -// ReadConfigs read all key/value pair matching the key prefix +// 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, "--get-regexp", keyPrefix) diff --git a/repository/git_test.go b/repository/git_test.go index cb115526..88587a15 100644 --- a/repository/git_test.go +++ b/repository/git_test.go @@ -11,57 +11,55 @@ func TestConfig(t *testing.T) { repo := CreateTestRepo(false) defer CleanupTestRepos(t, repo) - config := repo.LocalConfig() - - err := config.StoreString("section.key", "value") + err := repo.LocalConfig().StoreString("section.key", "value") assert.NoError(t, err) - val, err := config.ReadString("section.key") + val, err := repo.LocalConfig().ReadString("section.key") assert.Equal(t, "value", val) - err = config.StoreString("section.true", "true") + err = repo.LocalConfig().StoreString("section.true", "true") assert.NoError(t, err) - val2, err := config.ReadBool("section.true") + val2, err := repo.LocalConfig().ReadBool("section.true") assert.Equal(t, true, val2) - configs, err := config.ReadAll("section") + configs, err := repo.LocalConfig().ReadAll("section") assert.NoError(t, err) assert.Equal(t, configs, map[string]string{ "section.key": "value", "section.true": "true", }) - err = config.RemoveAll("section.true") + err = repo.LocalConfig().RemoveAll("section.true") assert.NoError(t, err) - configs, err = config.ReadAll("section") + configs, err = repo.LocalConfig().ReadAll("section") assert.NoError(t, err) assert.Equal(t, configs, map[string]string{ "section.key": "value", }) - _, err = config.ReadBool("section.true") + _, err = repo.LocalConfig().ReadBool("section.true") assert.Equal(t, ErrNoConfigEntry, err) - err = config.RemoveAll("section.nonexistingkey") + err = repo.LocalConfig().RemoveAll("section.nonexistingkey") assert.Error(t, err) - err = config.RemoveAll("section.key") + err = repo.LocalConfig().RemoveAll("section.key") assert.NoError(t, err) - _, err = config.ReadString("section.key") + _, err = repo.LocalConfig().ReadString("section.key") assert.Equal(t, ErrNoConfigEntry, err) - err = config.RemoveAll("nonexistingsection") + err = repo.LocalConfig().RemoveAll("nonexistingsection") assert.Error(t, err) - err = config.RemoveAll("section") + err = repo.LocalConfig().RemoveAll("section") assert.Error(t, err) - _, err = config.ReadString("section.key") + _, err = repo.LocalConfig().ReadString("section.key") assert.Error(t, err) - err = config.RemoveAll("section.key") + err = repo.LocalConfig().RemoveAll("section.key") assert.Error(t, err) } diff --git a/repository/mock_repo.go b/repository/mock_repo.go index bdf36ac2..26c02ede 100644 --- a/repository/mock_repo.go +++ b/repository/mock_repo.go @@ -3,8 +3,6 @@ package repository import ( "crypto/sha1" "fmt" - "strconv" - "strings" "github.com/MichaelMure/git-bug/util/git" "github.com/MichaelMure/git-bug/util/lamport" @@ -41,10 +39,12 @@ func NewMockRepoForTest() *mockRepoForTest { } } +// LocalConfig give access to the repository scoped configuration func (r *mockRepoForTest) LocalConfig() Config { return newMemConfig(r.config) } +// GlobalConfig give access to the git global configuration func (r *mockRepoForTest) GlobalConfig() Config { return newMemConfig(r.globalConfig) } @@ -75,53 +75,6 @@ func (r *mockRepoForTest) GetRemotes() (map[string]string, error) { }, nil } -func (r *mockRepoForTest) StoreConfig(key string, value string) error { - r.config[key] = value - return nil -} - -func (r *mockRepoForTest) ReadConfigs(keyPrefix string) (map[string]string, error) { - result := make(map[string]string) - - for key, val := range r.config { - if strings.HasPrefix(key, keyPrefix) { - result[key] = val - } - } - - return result, nil -} - -func (r *mockRepoForTest) ReadConfigBool(key string) (bool, error) { - // unlike git, the mock can only store one value for the same key - val, ok := r.config[key] - if !ok { - return false, ErrNoConfigEntry - } - - return strconv.ParseBool(val) -} - -func (r *mockRepoForTest) ReadConfigString(key string) (string, error) { - // unlike git, the mock can only store one value for the same key - val, ok := r.config[key] - if !ok { - return "", ErrNoConfigEntry - } - - return val, nil -} - -// RmConfigs remove all key/value pair matching the key prefix -func (r *mockRepoForTest) RmConfigs(keyPrefix string) error { - for key := range r.config { - if strings.HasPrefix(key, keyPrefix) { - delete(r.config, key) - } - } - return nil -} - // PushRefs push git refs to a remote func (r *mockRepoForTest) PushRefs(remote string, refSpec string) (string, error) { return "", nil diff --git a/repository/repo.go b/repository/repo.go index f17d594b..7d655bde 100644 --- a/repository/repo.go +++ b/repository/repo.go @@ -30,10 +30,10 @@ type RepoCommon interface { // GetRemotes returns the configured remotes repositories. GetRemotes() (map[string]string, error) - // LocalConfig . + // LocalConfig give access to the repository scoped configuration LocalConfig() Config - // GlobalConfig . + // GlobalConfig give access to the git global configuration GlobalConfig() Config } -- cgit From f9f82957a78ea0d3cacddbc6914ce98b94ddf7bd Mon Sep 17 00:00:00 2001 From: amine Date: Fri, 1 Nov 2019 22:51:37 +0100 Subject: repository: fix ineffectual assignment in git test --- repository/git_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/repository/git_test.go b/repository/git_test.go index 88587a15..de442e39 100644 --- a/repository/git_test.go +++ b/repository/git_test.go @@ -15,12 +15,14 @@ func TestConfig(t *testing.T) { assert.NoError(t, err) val, err := repo.LocalConfig().ReadString("section.key") + assert.NoError(t, err) assert.Equal(t, "value", val) err = repo.LocalConfig().StoreString("section.true", "true") assert.NoError(t, err) val2, err := repo.LocalConfig().ReadBool("section.true") + assert.NoError(t, err) assert.Equal(t, true, val2) configs, err := repo.LocalConfig().ReadAll("section") -- cgit