github.com/circular-dark/docker@v1.7.0/utils/git.go (about) 1 package utils 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "net/http" 7 "net/url" 8 "os" 9 "os/exec" 10 "path/filepath" 11 "strings" 12 13 "github.com/docker/docker/pkg/symlink" 14 "github.com/docker/docker/pkg/urlutil" 15 ) 16 17 func GitClone(remoteURL string) (string, error) { 18 if !urlutil.IsGitTransport(remoteURL) { 19 remoteURL = "https://" + remoteURL 20 } 21 root, err := ioutil.TempDir("", "docker-build-git") 22 if err != nil { 23 return "", err 24 } 25 26 u, err := url.Parse(remoteURL) 27 if err != nil { 28 return "", err 29 } 30 31 fragment := u.Fragment 32 clone := cloneArgs(u, root) 33 34 if output, err := git(clone...); err != nil { 35 return "", fmt.Errorf("Error trying to use git: %s (%s)", err, output) 36 } 37 38 return checkoutGit(fragment, root) 39 } 40 41 func cloneArgs(remoteURL *url.URL, root string) []string { 42 args := []string{"clone", "--recursive"} 43 shallow := len(remoteURL.Fragment) == 0 44 45 if shallow && strings.HasPrefix(remoteURL.Scheme, "http") { 46 res, err := http.Head(fmt.Sprintf("%s/info/refs?service=git-upload-pack", remoteURL)) 47 if err != nil || res.Header.Get("Content-Type") != "application/x-git-upload-pack-advertisement" { 48 shallow = false 49 } 50 } 51 52 if shallow { 53 args = append(args, "--depth", "1") 54 } 55 56 if remoteURL.Fragment != "" { 57 remoteURL.Fragment = "" 58 } 59 60 return append(args, remoteURL.String(), root) 61 } 62 63 func checkoutGit(fragment, root string) (string, error) { 64 refAndDir := strings.SplitN(fragment, ":", 2) 65 66 if len(refAndDir[0]) != 0 { 67 if output, err := gitWithinDir(root, "checkout", refAndDir[0]); err != nil { 68 return "", fmt.Errorf("Error trying to use git: %s (%s)", err, output) 69 } 70 } 71 72 if len(refAndDir) > 1 && len(refAndDir[1]) != 0 { 73 newCtx, err := symlink.FollowSymlinkInScope(filepath.Join(root, refAndDir[1]), root) 74 if err != nil { 75 return "", fmt.Errorf("Error setting git context, %q not within git root: %s", refAndDir[1], err) 76 } 77 78 fi, err := os.Stat(newCtx) 79 if err != nil { 80 return "", err 81 } 82 if !fi.IsDir() { 83 return "", fmt.Errorf("Error setting git context, not a directory: %s", newCtx) 84 } 85 root = newCtx 86 } 87 88 return root, nil 89 } 90 91 func gitWithinDir(dir string, args ...string) ([]byte, error) { 92 a := []string{"--work-tree", dir, "--git-dir", filepath.Join(dir, ".git")} 93 return git(append(a, args...)...) 94 } 95 96 func git(args ...string) ([]byte, error) { 97 return exec.Command("git", args...).CombinedOutput() 98 }