api/client/build: allow tar as context for docker build -
Docker-DCO-1.1-Signed-off-by: Johan Euphrosine <proppy@google.com> (github: proppy)
This commit is contained in:
parent
3f600c831b
commit
edcb41451a
7 changed files with 96 additions and 13 deletions
|
@ -36,6 +36,10 @@ import (
|
|||
"github.com/dotcloud/docker/utils/filters"
|
||||
)
|
||||
|
||||
const (
|
||||
tarHeaderSize = 512
|
||||
)
|
||||
|
||||
func (cli *DockerCli) CmdHelp(args ...string) error {
|
||||
if len(args) > 0 {
|
||||
method, exists := cli.getMethod(args[0])
|
||||
|
@ -113,13 +117,22 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
|||
_, err = exec.LookPath("git")
|
||||
hasGit := err == nil
|
||||
if cmd.Arg(0) == "-" {
|
||||
// As a special case, 'docker build -' will build from an empty context with the
|
||||
// contents of stdin as a Dockerfile
|
||||
dockerfile, err := ioutil.ReadAll(cli.in)
|
||||
if err != nil {
|
||||
return err
|
||||
// As a special case, 'docker build -' will build from either an empty context with the
|
||||
// contents of stdin as a Dockerfile, or a tar-ed context from stdin.
|
||||
buf := bufio.NewReader(cli.in)
|
||||
magic, err := buf.Peek(tarHeaderSize)
|
||||
if err != nil && err != io.EOF {
|
||||
return fmt.Errorf("failed to peek context header from stdin: %v", err)
|
||||
}
|
||||
if !archive.IsArchive(magic) {
|
||||
dockerfile, err := ioutil.ReadAll(buf)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read Dockerfile from stdin: %v", err)
|
||||
}
|
||||
context, err = archive.Generate("Dockerfile", string(dockerfile))
|
||||
} else {
|
||||
context = ioutil.NopCloser(buf)
|
||||
}
|
||||
context, err = archive.Generate("Dockerfile", string(dockerfile))
|
||||
} else if utils.IsURL(cmd.Arg(0)) && (!utils.IsGIT(cmd.Arg(0)) || !hasGit) {
|
||||
isRemote = true
|
||||
} else {
|
||||
|
|
|
@ -43,6 +43,16 @@ const (
|
|||
Xz
|
||||
)
|
||||
|
||||
func IsArchive(header []byte) bool {
|
||||
compression := DetectCompression(header)
|
||||
if compression != Uncompressed {
|
||||
return true
|
||||
}
|
||||
r := tar.NewReader(bytes.NewBuffer(header))
|
||||
_, err := r.Next()
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func DetectCompression(source []byte) Compression {
|
||||
for compression, m := range map[Compression][]byte{
|
||||
Bzip2: {0x42, 0x5A, 0x68},
|
||||
|
|
|
@ -238,10 +238,15 @@ All new files and directories are created with a uid and gid of 0.
|
|||
In the case where `<src>` is a remote file URL, the destination will have permissions 600.
|
||||
|
||||
> **Note**:
|
||||
> If you build using STDIN (`docker build - < somefile`), there is no
|
||||
> build context, so the Dockerfile can only contain a URL based ADD
|
||||
> statement.
|
||||
> If you build by passing a Dockerfile through STDIN (`docker build - < somefile`),
|
||||
> there is no build context, so the Dockerfile can only contain a URL
|
||||
> based ADD statement.
|
||||
|
||||
> You can also pass a compressed archive through STDIN:
|
||||
> (`docker build - < archive.tar.gz`), the `Dockerfile` at the root of
|
||||
> the archive and the rest of the archive will get used at the context
|
||||
> of the build.
|
||||
>
|
||||
> **Note**:
|
||||
> If your URL files are protected using authentication, you will need to
|
||||
> use `RUN wget` , `RUN curl`
|
||||
|
@ -361,7 +366,7 @@ execute in `/bin/sh -c`:
|
|||
FROM ubuntu
|
||||
ENTRYPOINT wc -l -
|
||||
|
||||
For example, that Dockerfile's image will *always* take stdin as input
|
||||
For example, that Dockerfile's image will *always* take STDIN as input
|
||||
("-") and print the number of lines ("-l"). If you wanted to make this
|
||||
optional but default, you could use a CMD:
|
||||
|
||||
|
|
|
@ -274,12 +274,17 @@ and the tag will be `2.0`
|
|||
|
||||
$ sudo docker build - < Dockerfile
|
||||
|
||||
This will read a Dockerfile from *stdin* without
|
||||
This will read a Dockerfile from STDIN without
|
||||
context. Due to the lack of a context, no contents of any local
|
||||
directory will be sent to the `docker` daemon. Since
|
||||
there is no context, a Dockerfile `ADD`
|
||||
only works if it refers to a remote URL.
|
||||
|
||||
$ sudo docker build - < context.tar.gz
|
||||
|
||||
This will build an image for a compressed context read from STDIN.
|
||||
Supported formats are: bzip2, gzip and xz.
|
||||
|
||||
$ sudo docker build github.com/creack/docker-firefox
|
||||
|
||||
This will clone the GitHub repository and use the cloned repository as
|
||||
|
@ -531,7 +536,7 @@ URLs must start with `http` and point to a single
|
|||
file archive (.tar, .tar.gz, .tgz, .bzip, .tar.xz, or .txz) containing a
|
||||
root filesystem. If you would like to import from a local directory or
|
||||
archive, you can use the `-` parameter to take the
|
||||
data from *stdin*.
|
||||
data from STDIN.
|
||||
|
||||
### Examples
|
||||
|
||||
|
@ -543,7 +548,7 @@ This will create a new untagged image.
|
|||
|
||||
**Import from a local file:**
|
||||
|
||||
Import to docker via pipe and *stdin*.
|
||||
Import to docker via pipe and STDIN.
|
||||
|
||||
$ cat exampleimage.tgz | sudo docker import - exampleimagelocal:new
|
||||
|
||||
|
|
3
integration-cli/build_tests/TestContextTar/Dockerfile
Normal file
3
integration-cli/build_tests/TestContextTar/Dockerfile
Normal file
|
@ -0,0 +1,3 @@
|
|||
FROM busybox
|
||||
ADD foo /foo
|
||||
CMD ["cat", "/foo"]
|
1
integration-cli/build_tests/TestContextTar/foo
Normal file
1
integration-cli/build_tests/TestContextTar/foo
Normal file
|
@ -0,0 +1 @@
|
|||
foo
|
|
@ -9,6 +9,8 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/dotcloud/docker/archive"
|
||||
)
|
||||
|
||||
func TestBuildCacheADD(t *testing.T) {
|
||||
|
@ -1130,6 +1132,50 @@ func TestBuildADDLocalAndRemoteFilesWithCache(t *testing.T) {
|
|||
logDone("build - add local and remote file with cache")
|
||||
}
|
||||
|
||||
func testContextTar(t *testing.T, compression archive.Compression) {
|
||||
contextDirectory := filepath.Join(workingDirectory, "build_tests", "TestContextTar")
|
||||
context, err := archive.Tar(contextDirectory, compression)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("failed to build context tar: %v", err)
|
||||
}
|
||||
buildCmd := exec.Command(dockerBinary, "build", "-t", "contexttar", "-")
|
||||
buildCmd.Stdin = context
|
||||
|
||||
out, exitCode, err := runCommandWithOutput(buildCmd)
|
||||
if err != nil || exitCode != 0 {
|
||||
t.Fatalf("build failed to complete: %v %v", out, err)
|
||||
}
|
||||
deleteImages("contexttar")
|
||||
logDone(fmt.Sprintf("build - build an image with a context tar, compression: %v", compression))
|
||||
}
|
||||
|
||||
func TestContextTarGzip(t *testing.T) {
|
||||
testContextTar(t, archive.Gzip)
|
||||
}
|
||||
|
||||
func TestContextTarNoCompression(t *testing.T) {
|
||||
testContextTar(t, archive.Uncompressed)
|
||||
}
|
||||
|
||||
func TestNoContext(t *testing.T) {
|
||||
buildCmd := exec.Command(dockerBinary, "build", "-t", "nocontext", "-")
|
||||
buildCmd.Stdin = strings.NewReader("FROM busybox\nCMD echo ok\n")
|
||||
|
||||
out, exitCode, err := runCommandWithOutput(buildCmd)
|
||||
if err != nil || exitCode != 0 {
|
||||
t.Fatalf("build failed to complete: %v %v", out, err)
|
||||
}
|
||||
|
||||
out, exitCode, err = cmd(t, "run", "nocontext")
|
||||
if out != "ok\n" {
|
||||
t.Fatalf("run produced invalid output: %q, expected %q", out, "ok")
|
||||
}
|
||||
|
||||
deleteImages("nocontext")
|
||||
logDone("build - build an image with no context")
|
||||
}
|
||||
|
||||
// TODO: TestCaching
|
||||
func TestBuildADDLocalAndRemoteFilesWithoutCache(t *testing.T) {
|
||||
name := "testbuildaddlocalandremotefilewithoutcache"
|
||||
|
|
Loading…
Reference in a new issue