Pārlūkot izejas kodu

Allow for relative paths on ADD/COPY

Moved Tianon's PR from: https://github.com/docker/docker/pull/7870
on top of the latest code

Closes: #3936

Signed-off-by: Andrew Page <admwiggin@gmail.com>
Signed-off-by: Doug Davis <dug@us.ibm.com>
Doug Davis 10 gadi atpakaļ
vecāks
revīzija
f21f9f856e

+ 4 - 7
builder/dispatchers.go

@@ -172,15 +172,12 @@ func workdir(b *Builder, args []string, attributes map[string]bool, original str
 
 	workdir := args[0]
 
-	if workdir[0] == '/' {
-		b.Config.WorkingDir = workdir
-	} else {
-		if b.Config.WorkingDir == "" {
-			b.Config.WorkingDir = "/"
-		}
-		b.Config.WorkingDir = filepath.Join(b.Config.WorkingDir, workdir)
+	if !filepath.IsAbs(workdir) {
+		workdir = filepath.Join("/", b.Config.WorkingDir, workdir)
 	}
 
+	b.Config.WorkingDir = workdir
+
 	return b.commit("", b.Config.Cmd, fmt.Sprintf("WORKDIR %v", workdir))
 }
 

+ 12 - 0
builder/internals.go

@@ -217,6 +217,18 @@ func calcCopyInfo(b *Builder, cmdName string, cInfos *[]*copyInfo, origPath stri
 	}
 	origPath = strings.TrimPrefix(origPath, "./")
 
+	// Twiddle the destPath when its a relative path - meaning, make it
+	// relative to the WORKINGDIR
+	if !filepath.IsAbs(destPath) {
+		hasSlash := strings.HasSuffix(destPath, "/")
+		destPath = filepath.Join("/", b.Config.WorkingDir, destPath)
+
+		// Make sure we preserve any trailing slash
+		if hasSlash {
+			destPath += "/"
+		}
+	}
+
 	// In the remote/URL case, download it and gen its hashcode
 	if urlutil.IsURL(origPath) {
 		if !allowRemote {

+ 15 - 5
docs/man/Dockerfile.5.md

@@ -132,12 +132,22 @@ or
 
 **ADD**
  --**ADD <src>... <dest>** The ADD instruction copies new files, directories
- or remote file URLs to the filesystem of the container at path <dest>.  
+ or remote file URLs to the filesystem of the container at path <dest>.
  Mutliple <src> resources may be specified but if they are files or directories
- then they must be relative to the source directory that is being built 
- (the context of the build).  <dest> is the absolute path to
- which the source is copied inside the target container.  All new files and
- directories are created with mode 0755, with uid and gid 0.
+ then they must be relative to the source directory that is being built
+ (the context of the build). The <dest> is the absolute path, or path relative
+ to `WORKDIR`, into which the source is copied inside the target container.
+ All new files and directories are created with mode 0755 and with the uid 
+ and gid of 0.
+
+**COPY**
+ --**COPY <src> <dest>** The COPY instruction copies new files from <src> and
+ adds them to the filesystem of the container at path <dest>. The <src> must be
+ the path to a file or directory relative to the source directory that is
+ being built (the context of the build) or a remote file URL. The `<dest>` is an
+ absolute path, or a path relative to `WORKDIR`, into which the source will
+ be copied inside the target container. All new files and directories are
+ created with mode 0755 and with the uid and gid of 0.
 
 **ENTRYPOINT**
  --**ENTRYPOINT** has two forms: ENTRYPOINT ["executable", "param1", "param2"]

+ 6 - 4
docs/man/docker-build.1.md

@@ -65,10 +65,12 @@ directory called httpd may be used to store Dockerfiles for Apache web
 server images.
 
 It is also a good practice to add the files required for the image to the
-sub-directory. These files will then be specified with the `ADD` instruction
-in the Dockerfile. Note: If you include a tar file (a good practice!), then
-Docker will automatically extract the contents of the tar file
-specified within the `ADD` instruction into the specified target.
+sub-directory. These files will then be specified with the `COPY` or `ADD`
+instructions in the `Dockerfile`.
+
+Note: If you include a tar file (a good practice), then Docker will
+automatically extract the contents of the tar file specified within the `ADD`
+instruction into the specified target.
 
 ## Building an image and naming that image
 

+ 8 - 4
docs/sources/reference/builder.md

@@ -397,8 +397,10 @@ For most command line uses this should act as expected, for example:
     ADD hom* /mydir/        # adds all files starting with "hom"
     ADD hom?.txt /mydir/    # ? is replaced with any single character
 
-The `<dest>` is the absolute path to which the source will be copied inside the
-destination container.
+The `<dest>` is an absolute path, or a path relative to `WORKDIR`, into which
+the source will be copied inside the destination container.
+
+    ADD test aDir/          # adds "test" to `WORKDIR`/aDir/
 
 All new files and directories are created with a UID and GID of 0.
 
@@ -494,8 +496,10 @@ For most command line uses this should act as expected, for example:
     COPY hom* /mydir/        # adds all files starting with "hom"
     COPY hom?.txt /mydir/    # ? is replaced with any single character
 
-The `<dest>` is the absolute path to which the source will be copied inside the
-destination container.
+The `<dest>` is an absolute path, or a path relative to `WORKDIR`, into which
+the source will be copied inside the destination container.
+
+    COPY test aDir/          # adds "test" to `WORKDIR`/aDir/
 
 All new files and directories are created with a UID and GID of 0.
 

+ 40 - 0
integration-cli/docker_cli_build_test.go

@@ -1829,6 +1829,46 @@ func TestBuildWorkdirWithEnvVariables(t *testing.T) {
 	logDone("build - workdir with env variables")
 }
 
+func TestBuildRelativeCopy(t *testing.T) {
+	name := "testbuildrelativecopy"
+	defer deleteImages(name)
+	dockerfile := `
+		FROM busybox
+			WORKDIR /test1
+			WORKDIR test2
+			RUN [ "$PWD" = '/test1/test2' ]
+			COPY foo ./
+			RUN [ "$(cat /test1/test2/foo)" = 'hello' ]
+			ADD foo ./bar/baz
+			RUN [ "$(cat /test1/test2/bar/baz)" = 'hello' ]
+			COPY foo ./bar/baz2
+			RUN [ "$(cat /test1/test2/bar/baz2)" = 'hello' ]
+			WORKDIR ..
+			COPY foo ./
+			RUN [ "$(cat /test1/foo)" = 'hello' ]
+			COPY foo /test3/
+			RUN [ "$(cat /test3/foo)" = 'hello' ]
+			WORKDIR /test4
+			COPY . .
+			RUN [ "$(cat /test4/foo)" = 'hello' ]
+			WORKDIR /test5/test6
+			COPY foo ../
+			RUN [ "$(cat /test5/foo)" = 'hello' ]
+			`
+	ctx, err := fakeContext(dockerfile, map[string]string{
+		"foo": "hello",
+	})
+	defer ctx.Close()
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = buildImageFromContext(name, ctx, false)
+	if err != nil {
+		t.Fatal(err)
+	}
+	logDone("build - relative copy/add")
+}
+
 func TestBuildEnv(t *testing.T) {
 	name := "testbuildenv"
 	expected := "[PATH=/test:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PORT=2375]"