git: remove static Config, keep Version() static

This commit is contained in:
rick olson 2017-10-25 20:23:43 -06:00
parent 7d003a17c6
commit e807aa3192
11 changed files with 115 additions and 109 deletions

@ -23,7 +23,7 @@ var (
func cloneCommand(cmd *cobra.Command, args []string) {
requireGitVersion()
if cfg.IsGitVersionAtLeast("2.15.0") {
if git.IsGitVersionAtLeast("2.15.0") {
msg := []string{
"WARNING: 'git lfs clone' is deprecated and will not be updated",
" with new flags from 'git clone'",
@ -110,7 +110,7 @@ func cloneCommand(cmd *cobra.Command, args []string) {
func postCloneSubmodules(args []string) error {
// In git 2.9+ the filter option will have been passed through to submodules
// So we need to lfs pull inside each
if !cfg.IsGitVersionAtLeast("2.9.0") {
if !git.IsGitVersionAtLeast("2.9.0") {
// In earlier versions submodules would have used smudge filter
return nil
}

@ -2,6 +2,7 @@ package commands
import (
"github.com/git-lfs/git-lfs/config"
"github.com/git-lfs/git-lfs/git"
"github.com/git-lfs/git-lfs/lfs"
"github.com/spf13/cobra"
)
@ -10,7 +11,7 @@ func envCommand(cmd *cobra.Command, args []string) {
config.ShowConfigWarnings = true
endpoint := getAPIClient().Endpoints.Endpoint("download", cfg.CurrentRemote)
gitV, err := cfg.GitVersion()
gitV, err := git.Version()
if err != nil {
gitV = "Error getting git version: " + err.Error()
}

@ -271,7 +271,7 @@ func fetchAndReportToChan(allpointers []*lfs.WrappedPointer, filter *filepathfil
// Lazily initialize the current remote.
if len(cfg.CurrentRemote) == 0 {
// Actively find the default remote, don't just assume origin
defaultRemote, err := git.DefaultRemote()
defaultRemote, err := cfg.GitConfig().DefaultRemote()
if err != nil {
Exit("No default remote")
}

@ -27,7 +27,7 @@ func pullCommand(cmd *cobra.Command, args []string) {
remote = args[0]
} else {
// Actively find the default remote, don't just assume origin
defaultRemote, err := git.DefaultRemote()
defaultRemote, err := cfg.GitConfig().DefaultRemote()
if err != nil {
Panic(err, "No default remote")
}

@ -210,7 +210,7 @@ func statusScanRefRange(ref *git.Ref) {
Print("On branch %s", ref.Name)
remoteRef, err := git.CurrentRemoteRef()
remoteRef, err := cfg.GitConfig().CurrentRemoteRef()
if err != nil {
return
}

@ -16,6 +16,7 @@ import (
"github.com/git-lfs/git-lfs/config"
"github.com/git-lfs/git-lfs/errors"
"github.com/git-lfs/git-lfs/filepathfilter"
"github.com/git-lfs/git-lfs/git"
"github.com/git-lfs/git-lfs/lfs"
"github.com/git-lfs/git-lfs/lfsapi"
"github.com/git-lfs/git-lfs/locking"
@ -378,7 +379,7 @@ func ipAddresses() []string {
func logPanicToWriter(w io.Writer, loggedError error, le string) {
// log the version
gitV, err := cfg.GitVersion()
gitV, err := git.Version()
if err != nil {
gitV = "Error getting git version: " + err.Error()
}
@ -445,8 +446,8 @@ func buildProgressMeter(dryRun bool) *progress.ProgressMeter {
func requireGitVersion() {
minimumGit := "1.8.2"
if !cfg.IsGitVersionAtLeast(minimumGit) {
gitver, err := cfg.GitVersion()
if !git.IsGitVersionAtLeast(minimumGit) {
gitver, err := git.Version()
if err != nil {
Exit("Error getting git version: %s", err)
}

@ -108,7 +108,7 @@ func NewFrom(v Values) *Configuration {
c := &Configuration{
CurrentRemote: defaultRemote,
Os: EnvironmentOf(mapFetcher(v.Os)),
gitConfig: git.Config,
gitConfig: git.NewConfig("", ""),
}
c.Git = &delayedEnvironment{
callback: func() Environment {
@ -175,7 +175,7 @@ func (c *Configuration) SetLockableFilesReadOnly() bool {
}
func (c *Configuration) HookDir() string {
if c.gitConfig.IsGitVersionAtLeast("2.9.0") {
if git.IsGitVersionAtLeast("2.9.0") {
hp, ok := c.Git.Get("core.hooksPath")
if ok {
return hp
@ -284,14 +284,6 @@ func (c *Configuration) GitConfig() *git.Configuration {
return c.gitConfig
}
func (c *Configuration) GitVersion() (string, error) {
return c.gitConfig.Version()
}
func (c *Configuration) IsGitVersionAtLeast(ver string) bool {
return c.gitConfig.IsGitVersionAtLeast(ver)
}
func (c *Configuration) FindGitGlobalKey(key string) string {
return c.gitConfig.FindGlobal(key)
}

@ -7,11 +7,8 @@ import (
"sync"
"github.com/git-lfs/git-lfs/subprocess"
"github.com/rubyist/tracerx"
)
var Config = &Configuration{}
// Configuration can fetch or modify the current Git config and track the Git
// version.
type Configuration struct {
@ -138,33 +135,6 @@ func (c *Configuration) Source() (*ConfigurationSource, error) {
return ParseConfigLines(out, false), nil
}
// Version returns the git version
func (c *Configuration) Version() (string, error) {
c.mu.Lock()
defer c.mu.Unlock()
if c.version == nil {
v, err := gitSimple("version")
c.version = &v
if err != nil {
return v, err
}
}
return *c.version, nil
}
// IsVersionAtLeast returns whether the git version is the one specified or higher
// argument is plain version string separated by '.' e.g. "2.3.1" but can omit minor/patch
func (c *Configuration) IsGitVersionAtLeast(ver string) bool {
gitver, err := c.Version()
if err != nil {
tracerx.Printf("Error getting git version: %v", err)
return false
}
return IsVersionAtLeast(gitver, ver)
}
func (c *Configuration) gitConfig(args ...string) (string, error) {
args = append([]string{"config"}, args...)
subprocess.Trace("git", args...)

@ -94,7 +94,7 @@ func gitConfigNoLFS(args ...string) []string {
// causes difficult issues with passing through Stdin for login prompts
// This way is simpler & more practical.
filterOverride := ""
if !Config.IsGitVersionAtLeast("2.8.0") {
if !IsGitVersionAtLeast("2.8.0") {
filterOverride = "cat"
}
@ -233,8 +233,8 @@ func CurrentRef() (*Ref, error) {
return ResolveRef("HEAD")
}
func CurrentRemoteRef() (*Ref, error) {
remoteref, err := RemoteRefNameForCurrentBranch()
func (c *Configuration) CurrentRemoteRef() (*Ref, error) {
remoteref, err := c.RemoteRefNameForCurrentBranch()
if err != nil {
return nil, err
}
@ -243,12 +243,12 @@ func CurrentRemoteRef() (*Ref, error) {
}
// RemoteForCurrentBranch returns the name of the remote that the current branch is tracking
func RemoteForCurrentBranch() (string, error) {
func (c *Configuration) RemoteForCurrentBranch() (string, error) {
ref, err := CurrentRef()
if err != nil {
return "", err
}
remote := RemoteForBranch(ref.Name)
remote := c.RemoteForBranch(ref.Name)
if remote == "" {
return "", fmt.Errorf("remote not found for branch %q", ref.Name)
}
@ -257,7 +257,7 @@ func RemoteForCurrentBranch() (string, error) {
// RemoteRefForCurrentBranch returns the full remote ref (refs/remotes/{remote}/{remotebranch})
// that the current branch is tracking.
func RemoteRefNameForCurrentBranch() (string, error) {
func (c *Configuration) RemoteRefNameForCurrentBranch() (string, error) {
ref, err := CurrentRef()
if err != nil {
return "", err
@ -267,26 +267,26 @@ func RemoteRefNameForCurrentBranch() (string, error) {
return "", errors.New("not on a branch")
}
remote := RemoteForBranch(ref.Name)
remote := c.RemoteForBranch(ref.Name)
if remote == "" {
return "", fmt.Errorf("remote not found for branch %q", ref.Name)
}
remotebranch := RemoteBranchForLocalBranch(ref.Name)
remotebranch := c.RemoteBranchForLocalBranch(ref.Name)
return fmt.Sprintf("refs/remotes/%s/%s", remote, remotebranch), nil
}
// RemoteForBranch returns the remote name that a given local branch is tracking (blank if none)
func RemoteForBranch(localBranch string) string {
return Config.Find(fmt.Sprintf("branch.%s.remote", localBranch))
func (c *Configuration) RemoteForBranch(localBranch string) string {
return c.Find(fmt.Sprintf("branch.%s.remote", localBranch))
}
// RemoteBranchForLocalBranch returns the name (only) of the remote branch that the local branch is tracking
// If no specific branch is configured, returns local branch name
func RemoteBranchForLocalBranch(localBranch string) string {
func (c *Configuration) RemoteBranchForLocalBranch(localBranch string) string {
// get remote ref to track, may not be same name
merge := Config.Find(fmt.Sprintf("branch.%s.merge", localBranch))
merge := c.Find(fmt.Sprintf("branch.%s.merge", localBranch))
if strings.HasPrefix(merge, "refs/heads/") {
return merge[11:]
} else {
@ -429,8 +429,8 @@ func ValidateRemoteURL(remote string) error {
// 3. Any other SINGLE remote defined in .git/config
// Returns an error if all of these fail, i.e. no tracked remote branch, no
// "origin", and either no remotes defined or 2+ non-"origin" remotes
func DefaultRemote() (string, error) {
tracked, err := RemoteForCurrentBranch()
func (c *Configuration) DefaultRemote() (string, error) {
tracked, err := c.RemoteForCurrentBranch()
if err == nil {
return tracked, nil
}
@ -730,48 +730,6 @@ func parseRefFile(filename string) (*Ref, error) {
return ResolveRef(contents)
}
// IsVersionAtLeast compares 2 version strings (ok to be prefixed with 'git version', ignores)
func IsVersionAtLeast(actualVersion, desiredVersion string) bool {
// Capture 1-3 version digits, optionally prefixed with 'git version' and possibly
// with suffixes which we'll ignore (e.g. unstable builds, MinGW versions)
verregex := regexp.MustCompile(`(?:git version\s+)?(\d+)(?:.(\d+))?(?:.(\d+))?.*`)
var atleast uint64
// Support up to 1000 in major/minor/patch digits
const majorscale = 1000 * 1000
const minorscale = 1000
if match := verregex.FindStringSubmatch(desiredVersion); match != nil {
// Ignore errors as regex won't match anything other than digits
major, _ := strconv.Atoi(match[1])
atleast += uint64(major * majorscale)
if len(match) > 2 {
minor, _ := strconv.Atoi(match[2])
atleast += uint64(minor * minorscale)
}
if len(match) > 3 {
patch, _ := strconv.Atoi(match[3])
atleast += uint64(patch)
}
}
var actual uint64
if match := verregex.FindStringSubmatch(actualVersion); match != nil {
major, _ := strconv.Atoi(match[1])
actual += uint64(major * majorscale)
if len(match) > 2 {
minor, _ := strconv.Atoi(match[2])
actual += uint64(minor * minorscale)
}
if len(match) > 3 {
patch, _ := strconv.Atoi(match[3])
actual += uint64(patch)
}
}
return actual >= atleast
}
// IsBare returns whether or not a repository is bare. It requires that the
// current working directory is a repository.
//

@ -48,8 +48,11 @@ func TestCurrentRefAndCurrentRemoteRef(t *testing.T) {
},
},
}
outputs := repo.AddCommits(inputs)
// last commit was on branch3
gitConf := repo.GitConfig()
ref, err := CurrentRef()
assert.Nil(t, err)
assert.Equal(t, &Ref{"branch3", RefTypeLocalBranch, outputs[3].Sha}, ref)
@ -60,15 +63,15 @@ func TestCurrentRefAndCurrentRemoteRef(t *testing.T) {
// Check remote
repo.AddRemote("origin")
test.RunGitCommand(t, true, "push", "-u", "origin", "master:someremotebranch")
ref, err = CurrentRemoteRef()
ref, err = gitConf.CurrentRemoteRef()
assert.Nil(t, err)
assert.Equal(t, &Ref{"origin/someremotebranch", RefTypeRemoteBranch, outputs[2].Sha}, ref)
refname, err := RemoteRefNameForCurrentBranch()
refname, err := gitConf.RemoteRefNameForCurrentBranch()
assert.Nil(t, err)
assert.Equal(t, "refs/remotes/origin/someremotebranch", refname)
remote, err := RemoteForCurrentBranch()
remote, err := gitConf.RemoteForCurrentBranch()
assert.Nil(t, err)
assert.Equal(t, "origin", remote)
@ -201,7 +204,7 @@ func TestResolveEmptyCurrentRef(t *testing.T) {
func TestWorkTrees(t *testing.T) {
// Only git 2.5+
if !Config.IsGitVersionAtLeast("2.5.0") {
if !IsGitVersionAtLeast("2.5.0") {
return
}

81
git/version.go Normal file

@ -0,0 +1,81 @@
package git
import (
"regexp"
"strconv"
"sync"
"github.com/git-lfs/git-lfs/subprocess"
"github.com/rubyist/tracerx"
)
var (
gitVersion *string
gitVersionMu sync.Mutex
)
func Version() (string, error) {
gitVersionMu.Lock()
defer gitVersionMu.Unlock()
if gitVersion == nil {
v, err := subprocess.SimpleExec("git", "version")
gitVersion = &v
return v, err
}
return *gitVersion, nil
}
// IsVersionAtLeast returns whether the git version is the one specified or higher
// argument is plain version string separated by '.' e.g. "2.3.1" but can omit minor/patch
func IsGitVersionAtLeast(ver string) bool {
gitver, err := Version()
if err != nil {
tracerx.Printf("Error getting git version: %v", err)
return false
}
return IsVersionAtLeast(gitver, ver)
}
// IsVersionAtLeast compares 2 version strings (ok to be prefixed with 'git version', ignores)
func IsVersionAtLeast(actualVersion, desiredVersion string) bool {
// Capture 1-3 version digits, optionally prefixed with 'git version' and possibly
// with suffixes which we'll ignore (e.g. unstable builds, MinGW versions)
verregex := regexp.MustCompile(`(?:git version\s+)?(\d+)(?:.(\d+))?(?:.(\d+))?.*`)
var atleast uint64
// Support up to 1000 in major/minor/patch digits
const majorscale = 1000 * 1000
const minorscale = 1000
if match := verregex.FindStringSubmatch(desiredVersion); match != nil {
// Ignore errors as regex won't match anything other than digits
major, _ := strconv.Atoi(match[1])
atleast += uint64(major * majorscale)
if len(match) > 2 {
minor, _ := strconv.Atoi(match[2])
atleast += uint64(minor * minorscale)
}
if len(match) > 3 {
patch, _ := strconv.Atoi(match[3])
atleast += uint64(patch)
}
}
var actual uint64
if match := verregex.FindStringSubmatch(actualVersion); match != nil {
major, _ := strconv.Atoi(match[1])
actual += uint64(major * majorscale)
if len(match) > 2 {
minor, _ := strconv.Atoi(match[2])
actual += uint64(minor * minorscale)
}
if len(match) > 3 {
patch, _ := strconv.Atoi(match[3])
actual += uint64(patch)
}
}
return actual >= atleast
}