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