From 3f64b76d4c66127466ce5b2ee0e8827eea7440b3 Mon Sep 17 00:00:00 2001 From: Gildas Cuisinier Date: Sun, 29 Mar 2015 19:42:11 +0200 Subject: [PATCH] work on #11094 allow import from local file Signed-off-by: Gildas Cuisinier --- api/client/import.go | 19 ++++++-- docs/reference/commandline/cli.md | 18 ++++++-- integration-cli/docker_cli_import_test.go | 56 +++++++++++++++++++++++ man/docker-import.1.md | 7 ++- 4 files changed, 90 insertions(+), 10 deletions(-) diff --git a/api/client/import.go b/api/client/import.go index 102578eaf..d1f4ea0cc 100644 --- a/api/client/import.go +++ b/api/client/import.go @@ -4,20 +4,22 @@ import ( "fmt" "io" "net/url" + "os" "github.com/docker/docker/opts" flag "github.com/docker/docker/pkg/mflag" "github.com/docker/docker/pkg/parsers" + "github.com/docker/docker/pkg/urlutil" "github.com/docker/docker/registry" ) // CmdImport creates an empty filesystem image, imports the contents of the tarball into the image, and optionally tags the image. // -// The URL argument is the address of a tarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) file. If the URL is '-', then the tar file is read from STDIN. +// The URL argument is the address of a tarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) file or a path to local file relative to docker client. If the URL is '-', then the tar file is read from STDIN. // -// Usage: docker import [OPTIONS] URL [REPOSITORY[:TAG]] +// Usage: docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]] func (cli *DockerCli) CmdImport(args ...string) error { - cmd := cli.Subcmd("import", []string{"URL|- [REPOSITORY[:TAG]]"}, "Create an empty filesystem image and import the contents of the\ntarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then\noptionally tag it.", true) + cmd := cli.Subcmd("import", []string{"file|URL|- [REPOSITORY[:TAG]]"}, "Create an empty filesystem image and import the contents of the\ntarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then\noptionally tag it.", true) flChanges := opts.NewListOpts(nil) cmd.Var(&flChanges, []string{"c", "-change"}, "Apply Dockerfile instruction to the created image") cmd.Require(flag.Min, 1) @@ -36,7 +38,7 @@ func (cli *DockerCli) CmdImport(args ...string) error { v.Add("changes", change) } if cmd.NArg() == 3 { - fmt.Fprintf(cli.err, "[DEPRECATED] The format 'URL|- [REPOSITORY [TAG]]' has been deprecated. Please use URL|- [REPOSITORY[:TAG]]\n") + fmt.Fprintf(cli.err, "[DEPRECATED] The format 'file|URL|- [REPOSITORY [TAG]]' has been deprecated. Please use file|URL|- [REPOSITORY[:TAG]]\n") v.Set("tag", cmd.Arg(2)) } @@ -52,6 +54,15 @@ func (cli *DockerCli) CmdImport(args ...string) error { if src == "-" { in = cli.in + } else if !urlutil.IsURL(src) { + v.Set("fromSrc", "-") + file, err := os.Open(src) + if err != nil { + return err + } + defer file.Close() + in = file + } sopts := &streamOpts{ diff --git a/docs/reference/commandline/cli.md b/docs/reference/commandline/cli.md index 89d0c90a9..59a89e315 100644 --- a/docs/reference/commandline/cli.md +++ b/docs/reference/commandline/cli.md @@ -1455,7 +1455,7 @@ NOTE: Docker will warn you if any containers exist that are using these untagged ## import - Usage: docker import URL|- [REPOSITORY[:TAG]] + Usage: docker import file|URL|- [REPOSITORY[:TAG]] Create an empty filesystem image and import the contents of the tarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then @@ -1463,10 +1463,14 @@ NOTE: Docker will warn you if any containers exist that are using these untagged -c, --change=[] Apply specified Dockerfile instructions while importing the image -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`. +You can specify a `URL` or `-` (dash) to take data directly from `STDIN`. The +`URL` can point to an archive (.tar, .tar.gz, .tgz, .bzip, .tar.xz, or .txz) +containing a fileystem or to an individual file on the Docker host. If you +specify an archive, Docker untars it in the container relative to the `/` +(root). If you specify an individual file, you must specify the full path within +the host. To import from a remote location, specify a `URI` that begins with the +`http://` or `https://` protocol. + The `--change` option will apply `Dockerfile` instructions to the image that is created. @@ -1475,6 +1479,10 @@ Supported `Dockerfile` instructions: #### Examples +**Import from a local file archive:** + + $ sudo docker import /local/path/to/exampleimage.tgz exampleimagedir + **Import from a remote location:** This will create a new untagged image. diff --git a/integration-cli/docker_cli_import_test.go b/integration-cli/docker_cli_import_test.go index f4bd08521..50e64072f 100644 --- a/integration-cli/docker_cli_import_test.go +++ b/integration-cli/docker_cli_import_test.go @@ -1,6 +1,9 @@ package main import ( + "bufio" + "io/ioutil" + "os" "os/exec" "strings" @@ -50,3 +53,56 @@ func (s *DockerSuite) TestImportBadURL(c *check.C) { c.Fatalf("expected an error msg but didn't get one:\n%s", out) } } + +func (s *DockerSuite) TestImportFile(c *check.C) { + runCmd := exec.Command(dockerBinary, "run", "--name", "test-import", "busybox", "true") + out, _, err := runCommandWithOutput(runCmd) + if err != nil { + c.Fatal("failed to create a container", out, err) + } + + temporaryFile, err := ioutil.TempFile("", "exportImportTest") + if err != nil { + c.Fatal("failed to create temporary file", "", err) + } + defer os.Remove(temporaryFile.Name()) + + runCmd = exec.Command(dockerBinary, "export", "test-import") + runCmd.Stdout = bufio.NewWriter(temporaryFile) + + _, err = runCommand(runCmd) + if err != nil { + c.Fatal("failed to export a container", out, err) + } + + runCmd = exec.Command(dockerBinary, "import", temporaryFile.Name()) + out, _, err = runCommandWithOutput(runCmd) + if err != nil { + c.Fatal("failed to import a container", out, err) + } + + if n := strings.Count(out, "\n"); n != 1 { + c.Fatalf("display is messed up: %d '\\n' instead of 1:\n%s", n, out) + } + image := strings.TrimSpace(out) + + runCmd = exec.Command(dockerBinary, "run", "--rm", image, "true") + out, _, err = runCommandWithOutput(runCmd) + if err != nil { + c.Fatal("failed to create a container", out, err) + } + + if out != "" { + c.Fatalf("command output should've been nothing, was %q", out) + } + +} + +func (s *DockerSuite) TestImportFileNonExistentFile(c *check.C) { + runCmd := exec.Command(dockerBinary, "import", "example.com/myImage.tar") + _, exitCode, err := runCommandWithOutput(runCmd) + if exitCode == 0 || err == nil { + c.Fatalf("import non-existing file must failed") + } + +} diff --git a/man/docker-import.1.md b/man/docker-import.1.md index b45bf5d4c..5ac686677 100644 --- a/man/docker-import.1.md +++ b/man/docker-import.1.md @@ -8,7 +8,7 @@ docker-import - Create an empty filesystem image and import the contents of the **docker import** [**-c**|**--change**[= []**]] [**--help**] -URL|- [REPOSITORY[:TAG]] +file|URL|- [REPOSITORY[:TAG]] # OPTIONS **-c**, **--change**=[] @@ -35,6 +35,11 @@ Import to docker via pipe and stdin: # cat exampleimage.tgz | docker import - example/imagelocal +Import to a Docker image from a local file. + + # docker import /path/to/exampleimage.tgz + + ## Import from a local file and tag Import to docker via pipe and stdin: