mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
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"
|
"github.com/dotcloud/docker/utils/filters"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
tarHeaderSize = 512
|
||||||
|
)
|
||||||
|
|
||||||
func (cli *DockerCli) CmdHelp(args ...string) error {
|
func (cli *DockerCli) CmdHelp(args ...string) error {
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
method, exists := cli.getMethod(args[0])
|
method, exists := cli.getMethod(args[0])
|
||||||
|
@ -113,13 +117,22 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
||||||
_, err = exec.LookPath("git")
|
_, err = exec.LookPath("git")
|
||||||
hasGit := err == nil
|
hasGit := err == nil
|
||||||
if cmd.Arg(0) == "-" {
|
if cmd.Arg(0) == "-" {
|
||||||
// As a special case, 'docker build -' will build from an empty context with the
|
// As a special case, 'docker build -' will build from either an empty context with the
|
||||||
// contents of stdin as a Dockerfile
|
// contents of stdin as a Dockerfile, or a tar-ed context from stdin.
|
||||||
dockerfile, err := ioutil.ReadAll(cli.in)
|
buf := bufio.NewReader(cli.in)
|
||||||
if err != nil {
|
magic, err := buf.Peek(tarHeaderSize)
|
||||||
return err
|
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) {
|
} else if utils.IsURL(cmd.Arg(0)) && (!utils.IsGIT(cmd.Arg(0)) || !hasGit) {
|
||||||
isRemote = true
|
isRemote = true
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -43,6 +43,16 @@ const (
|
||||||
Xz
|
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 {
|
func DetectCompression(source []byte) Compression {
|
||||||
for compression, m := range map[Compression][]byte{
|
for compression, m := range map[Compression][]byte{
|
||||||
Bzip2: {0x42, 0x5A, 0x68},
|
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.
|
In the case where `<src>` is a remote file URL, the destination will have permissions 600.
|
||||||
|
|
||||||
> **Note**:
|
> **Note**:
|
||||||
> If you build using STDIN (`docker build - < somefile`), there is no
|
> If you build by passing a Dockerfile through STDIN (`docker build - < somefile`),
|
||||||
> build context, so the Dockerfile can only contain a URL based ADD
|
> there is no build context, so the Dockerfile can only contain a URL
|
||||||
> statement.
|
> 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**:
|
> **Note**:
|
||||||
> If your URL files are protected using authentication, you will need to
|
> If your URL files are protected using authentication, you will need to
|
||||||
> use `RUN wget` , `RUN curl`
|
> use `RUN wget` , `RUN curl`
|
||||||
|
@ -361,7 +366,7 @@ execute in `/bin/sh -c`:
|
||||||
FROM ubuntu
|
FROM ubuntu
|
||||||
ENTRYPOINT wc -l -
|
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
|
("-") and print the number of lines ("-l"). If you wanted to make this
|
||||||
optional but default, you could use a CMD:
|
optional but default, you could use a CMD:
|
||||||
|
|
||||||
|
|
|
@ -274,12 +274,17 @@ and the tag will be `2.0`
|
||||||
|
|
||||||
$ sudo docker build - < Dockerfile
|
$ 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
|
context. Due to the lack of a context, no contents of any local
|
||||||
directory will be sent to the `docker` daemon. Since
|
directory will be sent to the `docker` daemon. Since
|
||||||
there is no context, a Dockerfile `ADD`
|
there is no context, a Dockerfile `ADD`
|
||||||
only works if it refers to a remote URL.
|
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
|
$ sudo docker build github.com/creack/docker-firefox
|
||||||
|
|
||||||
This will clone the GitHub repository and use the cloned repository as
|
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
|
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
|
root filesystem. If you would like to import from a local directory or
|
||||||
archive, you can use the `-` parameter to take the
|
archive, you can use the `-` parameter to take the
|
||||||
data from *stdin*.
|
data from STDIN.
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
|
@ -543,7 +548,7 @@ This will create a new untagged image.
|
||||||
|
|
||||||
**Import from a local file:**
|
**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
|
$ 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"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/dotcloud/docker/archive"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBuildCacheADD(t *testing.T) {
|
func TestBuildCacheADD(t *testing.T) {
|
||||||
|
@ -1130,6 +1132,50 @@ func TestBuildADDLocalAndRemoteFilesWithCache(t *testing.T) {
|
||||||
logDone("build - add local and remote file with cache")
|
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
|
// TODO: TestCaching
|
||||||
func TestBuildADDLocalAndRemoteFilesWithoutCache(t *testing.T) {
|
func TestBuildADDLocalAndRemoteFilesWithoutCache(t *testing.T) {
|
||||||
name := "testbuildaddlocalandremotefilewithoutcache"
|
name := "testbuildaddlocalandremotefilewithoutcache"
|
||||||
|
|
Loading…
Add table
Reference in a new issue