github.com/ld86/docker@v1.7.1-rc3/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  }