Merge pull request #12502 from calavera/shallow_git_history
Shallow clone using git to build images.
This commit is contained in:
commit
790c63a5ef
5 changed files with 113 additions and 25 deletions
|
@ -96,20 +96,11 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
|||
} else {
|
||||
root := cmd.Arg(0)
|
||||
if urlutil.IsGitURL(root) {
|
||||
remoteURL := cmd.Arg(0)
|
||||
if !urlutil.IsGitTransport(remoteURL) {
|
||||
remoteURL = "https://" + remoteURL
|
||||
}
|
||||
|
||||
root, err = ioutil.TempDir("", "docker-build-git")
|
||||
root, err = utils.GitClone(root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.RemoveAll(root)
|
||||
|
||||
if output, err := exec.Command("git", "clone", "--recursive", remoteURL, root).CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("Error trying to use git: %s (%s)", err, output)
|
||||
}
|
||||
}
|
||||
if _, err := os.Stat(root); err != nil {
|
||||
return err
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
|
@ -22,6 +21,7 @@ import (
|
|||
"github.com/docker/docker/pkg/urlutil"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/docker/docker/runconfig"
|
||||
"github.com/docker/docker/utils"
|
||||
)
|
||||
|
||||
// whitelist of commands allowed for a commit/import
|
||||
|
@ -106,19 +106,12 @@ func Build(d *daemon.Daemon, buildConfig *Config) error {
|
|||
if buildConfig.RemoteURL == "" {
|
||||
context = ioutil.NopCloser(buildConfig.Context)
|
||||
} else if urlutil.IsGitURL(buildConfig.RemoteURL) {
|
||||
if !urlutil.IsGitTransport(buildConfig.RemoteURL) {
|
||||
buildConfig.RemoteURL = "https://" + buildConfig.RemoteURL
|
||||
}
|
||||
root, err := ioutil.TempDir("", "docker-build-git")
|
||||
root, err := utils.GitClone(buildConfig.RemoteURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.RemoveAll(root)
|
||||
|
||||
if output, err := exec.Command("git", "clone", "--recursive", buildConfig.RemoteURL, root).CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("Error trying to use git: %s (%s)", err, output)
|
||||
}
|
||||
|
||||
c, err := archive.Tar(root, archive.Uncompressed)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -636,12 +636,13 @@ refer to any of the files in the context. For example, your build can use
|
|||
an [*ADD*](/reference/builder/#add) instruction to reference a file in the
|
||||
context.
|
||||
|
||||
The `URL` parameter can specify the location of a Git repository; in this
|
||||
case, the repository is the context. The Git repository is recursively
|
||||
cloned with its submodules. The system does a fresh `git clone -recursive`
|
||||
in a temporary directory on your local host. Then, this clone is sent to
|
||||
the Docker daemon as the context. Local clones give you the ability to
|
||||
access private repositories using local user credentials, VPN's, and so forth.
|
||||
The `URL` parameter can specify the location of a Git repository;
|
||||
the repository acts as the build context. The system recursively clones the repository
|
||||
and its submodules using a `git clone --depth 1 --recursive` command.
|
||||
This command runs in a temporary directory on your local host.
|
||||
After the command succeeds, the directory is sent to the Docker daemon as the context.
|
||||
Local clones give you the ability to access private repositories using
|
||||
local user credentials, VPN's, and so forth.
|
||||
|
||||
Instead of specifying a context, you can pass a single Dockerfile in the
|
||||
`URL` or pipe the file in via `STDIN`. To pipe a Dockerfile from `STDIN`:
|
||||
|
|
47
utils/git.go
Normal file
47
utils/git.go
Normal file
|
@ -0,0 +1,47 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/pkg/urlutil"
|
||||
)
|
||||
|
||||
func GitClone(remoteURL string) (string, error) {
|
||||
if !urlutil.IsGitTransport(remoteURL) {
|
||||
remoteURL = "https://" + remoteURL
|
||||
}
|
||||
root, err := ioutil.TempDir("", "docker-build-git")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
clone := cloneArgs(remoteURL, root)
|
||||
|
||||
if output, err := exec.Command("git", clone...).CombinedOutput(); err != nil {
|
||||
return "", fmt.Errorf("Error trying to use git: %s (%s)", err, output)
|
||||
}
|
||||
|
||||
return root, nil
|
||||
}
|
||||
|
||||
func cloneArgs(remoteURL, root string) []string {
|
||||
args := []string{"clone", "--recursive"}
|
||||
shallow := true
|
||||
|
||||
if strings.HasPrefix(remoteURL, "http") {
|
||||
res, err := http.Head(fmt.Sprintf("%s/info/refs?service=git-upload-pack", remoteURL))
|
||||
if err != nil || res.Header.Get("Content-Type") != "application/x-git-upload-pack-advertisement" {
|
||||
shallow = false
|
||||
}
|
||||
}
|
||||
|
||||
if shallow {
|
||||
args = append(args, "--depth", "1")
|
||||
}
|
||||
|
||||
return append(args, remoteURL, root)
|
||||
}
|
56
utils/git_test.go
Normal file
56
utils/git_test.go
Normal file
|
@ -0,0 +1,56 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCloneArgsSmartHttp(t *testing.T) {
|
||||
mux := http.NewServeMux()
|
||||
server := httptest.NewServer(mux)
|
||||
serverURL, _ := url.Parse(server.URL)
|
||||
|
||||
serverURL.Path = "/repo.git"
|
||||
gitURL := serverURL.String()
|
||||
|
||||
mux.HandleFunc("/repo.git/info/refs", func(w http.ResponseWriter, r *http.Request) {
|
||||
q := r.URL.Query().Get("service")
|
||||
w.Header().Set("Content-Type", fmt.Sprintf("application/x-%s-advertisement", q))
|
||||
})
|
||||
|
||||
args := cloneArgs(gitURL, "/tmp")
|
||||
exp := []string{"clone", "--recursive", "--depth", "1", gitURL, "/tmp"}
|
||||
if !reflect.DeepEqual(args, exp) {
|
||||
t.Fatalf("Expected %v, got %v", exp, args)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloneArgsDumbHttp(t *testing.T) {
|
||||
mux := http.NewServeMux()
|
||||
server := httptest.NewServer(mux)
|
||||
serverURL, _ := url.Parse(server.URL)
|
||||
|
||||
serverURL.Path = "/repo.git"
|
||||
gitURL := serverURL.String()
|
||||
|
||||
mux.HandleFunc("/repo.git/info/refs", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
})
|
||||
|
||||
args := cloneArgs(gitURL, "/tmp")
|
||||
exp := []string{"clone", "--recursive", gitURL, "/tmp"}
|
||||
if !reflect.DeepEqual(args, exp) {
|
||||
t.Fatalf("Expected %v, got %v", exp, args)
|
||||
}
|
||||
}
|
||||
func TestCloneArgsGit(t *testing.T) {
|
||||
args := cloneArgs("git://github.com/docker/docker", "/tmp")
|
||||
exp := []string{"clone", "--recursive", "--depth", "1", "git://github.com/docker/docker", "/tmp"}
|
||||
if !reflect.DeepEqual(args, exp) {
|
||||
t.Fatalf("Expected %v, got %v", exp, args)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue