Imported Upstream version 2.5.1
[scm/test.git] / git / version.go
1 package git
2
3 import (
4         "regexp"
5         "strconv"
6         "sync"
7
8         "github.com/git-lfs/git-lfs/subprocess"
9         "github.com/rubyist/tracerx"
10 )
11
12 var (
13         gitVersion   *string
14         gitVersionMu sync.Mutex
15 )
16
17 func Version() (string, error) {
18         gitVersionMu.Lock()
19         defer gitVersionMu.Unlock()
20
21         if gitVersion == nil {
22                 v, err := subprocess.SimpleExec("git", "version")
23                 gitVersion = &v
24                 return v, err
25         }
26
27         return *gitVersion, nil
28 }
29
30 // IsVersionAtLeast returns whether the git version is the one specified or higher
31 // argument is plain version string separated by '.' e.g. "2.3.1" but can omit minor/patch
32 func IsGitVersionAtLeast(ver string) bool {
33         gitver, err := Version()
34         if err != nil {
35                 tracerx.Printf("Error getting git version: %v", err)
36                 return false
37         }
38         return IsVersionAtLeast(gitver, ver)
39 }
40
41 // IsVersionAtLeast compares 2 version strings (ok to be prefixed with 'git version', ignores)
42 func IsVersionAtLeast(actualVersion, desiredVersion string) bool {
43         // Capture 1-3 version digits, optionally prefixed with 'git version' and possibly
44         // with suffixes which we'll ignore (e.g. unstable builds, MinGW versions)
45         verregex := regexp.MustCompile(`(?:git version\s+)?(\d+)(?:.(\d+))?(?:.(\d+))?.*`)
46
47         var atleast uint64
48         // Support up to 1000 in major/minor/patch digits
49         const majorscale = 1000 * 1000
50         const minorscale = 1000
51
52         if match := verregex.FindStringSubmatch(desiredVersion); match != nil {
53                 // Ignore errors as regex won't match anything other than digits
54                 major, _ := strconv.Atoi(match[1])
55                 atleast += uint64(major * majorscale)
56                 if len(match) > 2 {
57                         minor, _ := strconv.Atoi(match[2])
58                         atleast += uint64(minor * minorscale)
59                 }
60                 if len(match) > 3 {
61                         patch, _ := strconv.Atoi(match[3])
62                         atleast += uint64(patch)
63                 }
64         }
65
66         var actual uint64
67         if match := verregex.FindStringSubmatch(actualVersion); match != nil {
68                 major, _ := strconv.Atoi(match[1])
69                 actual += uint64(major * majorscale)
70                 if len(match) > 2 {
71                         minor, _ := strconv.Atoi(match[2])
72                         actual += uint64(minor * minorscale)
73                 }
74                 if len(match) > 3 {
75                         patch, _ := strconv.Atoi(match[3])
76                         actual += uint64(patch)
77                 }
78         }
79
80         return actual >= atleast
81 }