github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/vndr/godl/get.go (about)

     1  // Copyright 2011 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package godl
     6  
     7  import (
     8  	"fmt"
     9  	"os"
    10  	"path/filepath"
    11  	"regexp"
    12  	"strconv"
    13  	"strings"
    14  )
    15  
    16  // VCS represents package vcs root.
    17  type VCS struct {
    18  	Root       string
    19  	ImportPath string
    20  	Type       string
    21  }
    22  
    23  // Download downloads package by its import path. It can be a subpackage,
    24  // whole repo will be downloaded anyway.
    25  // if repoPath is not empty string, it will be uses for vcs.
    26  // target is top directory for download. i.e. if target is vendor/ and
    27  // importPath is github.com/LK4D4/vndr, package will be downloaded to
    28  // vendor/github.com/LK4D4/vndr.
    29  // rev is desired revision of package.
    30  func Download(importPath, repoPath, target, rev string) (*VCS, error) {
    31  	security := secure
    32  	// Analyze the import path to determine the version control system,
    33  	// repository, and the import path for the root of the repository.
    34  	rr, err := repoRootForImportPath(importPath, security)
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  	root := filepath.Join(target, rr.root)
    39  	if repoPath != "" {
    40  		rr.repo = repoPath
    41  	}
    42  
    43  	if err := os.RemoveAll(root); err != nil {
    44  		return nil, fmt.Errorf("remove package root: %v", err)
    45  	}
    46  	// Some version control tools require the parent of the target to exist.
    47  	parent, _ := filepath.Split(root)
    48  	if err = os.MkdirAll(parent, 0777); err != nil {
    49  		return nil, err
    50  	}
    51  	if rev == "" {
    52  		if err = rr.vcs.create(root, rr.repo); err != nil {
    53  			return nil, err
    54  		}
    55  	} else {
    56  		if err = rr.vcs.createRev(root, rr.repo, rev); err != nil {
    57  			return nil, err
    58  		}
    59  	}
    60  	return &VCS{Root: root, ImportPath: importPath, Type: rr.vcs.cmd}, nil
    61  }
    62  
    63  // goTag matches go release tags such as go1 and go1.2.3.
    64  // The numbers involved must be small (at most 4 digits),
    65  // have no unnecessary leading zeros, and the version cannot
    66  // end in .0 - it is go1, not go1.0 or go1.0.0.
    67  var goTag = regexp.MustCompile(
    68  	`^go((0|[1-9][0-9]{0,3})\.)*([1-9][0-9]{0,3})$`,
    69  )
    70  
    71  // selectTag returns the closest matching tag for a given version.
    72  // Closest means the latest one that is not after the current release.
    73  // Version "goX" (or "goX.Y" or "goX.Y.Z") matches tags of the same form.
    74  // Version "release.rN" matches tags of the form "go.rN" (N being a floating-point number).
    75  // Version "weekly.YYYY-MM-DD" matches tags like "go.weekly.YYYY-MM-DD".
    76  //
    77  // NOTE(rsc): Eventually we will need to decide on some logic here.
    78  // For now, there is only "go1".  This matches the docs in go help get.
    79  func selectTag(goVersion string, tags []string) (match string) {
    80  	for _, t := range tags {
    81  		if t == "go1" {
    82  			return "go1"
    83  		}
    84  	}
    85  	return ""
    86  
    87  	/*
    88  		if goTag.MatchString(goVersion) {
    89  			v := goVersion
    90  			for _, t := range tags {
    91  				if !goTag.MatchString(t) {
    92  					continue
    93  				}
    94  				if cmpGoVersion(match, t) < 0 && cmpGoVersion(t, v) <= 0 {
    95  					match = t
    96  				}
    97  			}
    98  		}
    99  
   100  		return match
   101  	*/
   102  }
   103  
   104  // cmpGoVersion returns -1, 0, +1 reporting whether
   105  // x < y, x == y, or x > y.
   106  func cmpGoVersion(x, y string) int {
   107  	// Malformed strings compare less than well-formed strings.
   108  	if !goTag.MatchString(x) {
   109  		return -1
   110  	}
   111  	if !goTag.MatchString(y) {
   112  		return +1
   113  	}
   114  
   115  	// Compare numbers in sequence.
   116  	xx := strings.Split(x[len("go"):], ".")
   117  	yy := strings.Split(y[len("go"):], ".")
   118  
   119  	for i := 0; i < len(xx) && i < len(yy); i++ {
   120  		// The Atoi are guaranteed to succeed
   121  		// because the versions match goTag.
   122  		xi, _ := strconv.Atoi(xx[i])
   123  		yi, _ := strconv.Atoi(yy[i])
   124  		if xi < yi {
   125  			return -1
   126  		} else if xi > yi {
   127  			return +1
   128  		}
   129  	}
   130  
   131  	if len(xx) < len(yy) {
   132  		return -1
   133  	}
   134  	if len(xx) > len(yy) {
   135  		return +1
   136  	}
   137  	return 0
   138  }