github.com/git-lfs/git-lfs@v2.5.2+incompatible/git/version.go (about)

     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  }