Skip to content

Commit cae2924

Browse files
committed
Implementations of Copy file to container command
Modification of Copy file from container command to follow 1.20 API
1 parent 520ed0f commit cae2924

15 files changed

+458
-36
lines changed

src/main/java/com/github/dockerjava/api/DockerClient.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import com.github.dockerjava.api.command.WaitContainerCmd;
4444
import com.github.dockerjava.api.model.AuthConfig;
4545
import com.github.dockerjava.api.model.Identifier;
46+
import com.github.dockerjava.core.command.CopyFileToContainerCmd;
4647

4748
// https://godoc.org/github.com/fsouza/go-dockerclient
4849
public interface DockerClient extends Closeable {
@@ -120,6 +121,8 @@ public interface DockerClient extends Closeable {
120121

121122
public CopyFileFromContainerCmd copyFileFromContainerCmd(String containerId, String resource);
122123

124+
public CopyFileToContainerCmd copyFileToContainerCmd(String containerId, String hostResource);
125+
123126
public ContainerDiffCmd containerDiffCmd(String containerId);
124127

125128
public StopContainerCmd stopContainerCmd(String containerId);

src/main/java/com/github/dockerjava/api/command/DockerCmdExecFactory.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.io.IOException;
55

66
import com.github.dockerjava.core.DockerClientConfig;
7+
import com.github.dockerjava.core.command.CopyFileToContainerCmd;
78

89
public interface DockerCmdExecFactory extends Closeable {
910

@@ -57,6 +58,8 @@ public interface DockerCmdExecFactory extends Closeable {
5758

5859
public CopyFileFromContainerCmd.Exec createCopyFileFromContainerCmdExec();
5960

61+
public CopyFileToContainerCmd.Exec createCopyFileToContainerCmdExec();
62+
6063
public StopContainerCmd.Exec createStopContainerCmdExec();
6164

6265
public ContainerDiffCmd.Exec createContainerDiffCmdExec();
@@ -83,5 +86,4 @@ public interface DockerCmdExecFactory extends Closeable {
8386

8487
@Override
8588
public void close() throws IOException;
86-
8789
}

src/main/java/com/github/dockerjava/core/CompressArchiveUtil.java

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,77 @@
22

33
import static com.github.dockerjava.core.FilePathUtil.relativize;
44

5+
import java.io.BufferedInputStream;
56
import java.io.BufferedOutputStream;
67
import java.io.File;
8+
import java.io.FileNotFoundException;
79
import java.io.FileOutputStream;
810
import java.io.IOException;
11+
import java.io.InputStream;
12+
import java.io.OutputStream;
13+
import java.nio.file.Files;
14+
import java.nio.file.Path;
915
import java.util.zip.GZIPOutputStream;
1016

1117
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
1218
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
19+
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
1320
import org.apache.commons.io.FileUtils;
1421

22+
import com.google.common.io.ByteStreams;
23+
import com.google.common.io.Closeables;
24+
1525
public class CompressArchiveUtil {
1626

27+
static void putTarEntry(TarArchiveOutputStream tarOutputStream, TarArchiveEntry tarEntry, Path file) throws IOException {
28+
tarEntry.setSize(Files.size(file));
29+
tarOutputStream.putArchiveEntry(tarEntry);
30+
InputStream input = new BufferedInputStream(Files.newInputStream(file));
31+
try {
32+
ByteStreams.copy(input, tarOutputStream);
33+
tarOutputStream.closeArchiveEntry();
34+
} finally {
35+
input.close();
36+
}
37+
}
38+
39+
/**
40+
* Recursively tar file
41+
*
42+
* @param inputPath file path can be directory
43+
* @param outputPath where to put the archived file
44+
* @param childrenOnly if inputPath is directory and if childrenOnly is true, the archive will contain all of its children, else the archive contains unique
45+
* entry which is the inputPath itself
46+
* @param gZipped compress with gzip algorithm
47+
*/
48+
public static void tar(Path inputPath, Path outputPath, boolean gZipped, boolean childrenOnly) throws IOException {
49+
if (!Files.exists(inputPath)) {
50+
throw new FileNotFoundException("File not found " + inputPath);
51+
}
52+
FileUtils.touch(outputPath.toFile());
53+
OutputStream outputStream = new BufferedOutputStream(Files.newOutputStream(outputPath));
54+
if (gZipped) {
55+
outputStream = new GzipCompressorOutputStream(outputStream);
56+
}
57+
TarArchiveOutputStream tarArchiveOutputStream = new TarArchiveOutputStream(outputStream);
58+
tarArchiveOutputStream.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);
59+
try {
60+
if (!Files.isDirectory(inputPath)) {
61+
putTarEntry(tarArchiveOutputStream, new TarArchiveEntry(inputPath.getFileName().toString()), inputPath);
62+
} else {
63+
Path sourcePath = inputPath;
64+
if (!childrenOnly) {
65+
// In order to have the dossier as the root entry
66+
sourcePath = inputPath.getParent();
67+
}
68+
Files.walkFileTree(inputPath, new TarDirWalker(sourcePath, tarArchiveOutputStream));
69+
}
70+
tarArchiveOutputStream.flush();
71+
} finally {
72+
Closeables.close(tarArchiveOutputStream, true);
73+
}
74+
}
75+
1776
public static File archiveTARFiles(File base, Iterable<File> files, String archiveNameWithOutExtension)
1877
throws IOException {
1978
File tarFile = new File(FileUtils.getTempDirectoryPath(), archiveNameWithOutExtension + ".tar");

src/main/java/com/github/dockerjava/core/DockerClientImpl.java

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
package com.github.dockerjava.core;
22

3+
import static com.google.common.base.Preconditions.checkNotNull;
4+
5+
import java.io.Closeable;
6+
import java.io.File;
7+
import java.io.IOException;
8+
import java.io.InputStream;
9+
310
import com.github.dockerjava.api.DockerClient;
411
import com.github.dockerjava.api.command.AttachContainerCmd;
512
import com.github.dockerjava.api.command.AuthCmd;
@@ -46,6 +53,8 @@
4653
import com.github.dockerjava.core.command.CommitCmdImpl;
4754
import com.github.dockerjava.core.command.ContainerDiffCmdImpl;
4855
import com.github.dockerjava.core.command.CopyFileFromContainerCmdImpl;
56+
import com.github.dockerjava.core.command.CopyFileToContainerCmd;
57+
import com.github.dockerjava.core.command.CopyFileToContainerCmdImpl;
4958
import com.github.dockerjava.core.command.CreateContainerCmdImpl;
5059
import com.github.dockerjava.core.command.CreateImageCmdImpl;
5160
import com.github.dockerjava.core.command.EventsCmdImpl;
@@ -77,16 +86,8 @@
7786
import com.github.dockerjava.core.command.VersionCmdImpl;
7887
import com.github.dockerjava.core.command.WaitContainerCmdImpl;
7988

80-
import java.io.Closeable;
81-
import java.io.File;
82-
import java.io.IOException;
83-
import java.io.InputStream;
84-
85-
import static com.google.common.base.Preconditions.checkNotNull;
86-
8789
/**
8890
* @author Konstantin Pelykh (kpelykh@gmail.com)
89-
*
9091
* @see "https://github.com/docker/docker/blob/master/api/client/commands.go"
9192
*/
9293
public class DockerClientImpl implements Closeable, DockerClient {
@@ -304,6 +305,12 @@ public CopyFileFromContainerCmd copyFileFromContainerCmd(String containerId, Str
304305
containerId, resource);
305306
}
306307

308+
@Override
309+
public CopyFileToContainerCmd copyFileToContainerCmd(String containerId, String hostResource) {
310+
return new CopyFileToContainerCmdImpl(getDockerCmdExecFactory().createCopyFileToContainerCmdExec(),
311+
containerId, hostResource);
312+
}
313+
307314
@Override
308315
public ContainerDiffCmd containerDiffCmd(String containerId) {
309316
return new ContainerDiffCmdImpl(getDockerCmdExecFactory().createContainerDiffCmdExec(), containerId);

src/main/java/com/github/dockerjava/core/FilePathUtil.java

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,17 @@
22

33
import java.io.File;
44
import java.io.IOException;
5+
import java.nio.file.Path;
56

67
import com.github.dockerjava.api.DockerClientException;
78

89
public class FilePathUtil {
910

1011
/**
1112
* Return the relative path. Path elements are separated with / char.
12-
*
13-
* @param baseDir
14-
* a parent directory of {@code file}
15-
* @param file
16-
* the file to get the relative path
13+
*
14+
* @param baseDir a parent directory of {@code file}
15+
* @param file the file to get the relative path
1716
* @return the relative path
1817
*/
1918
public static String relativize(File baseDir, File file) {
@@ -26,4 +25,21 @@ public static String relativize(File baseDir, File file) {
2625
throw new DockerClientException(e.getMessage(), e);
2726
}
2827
}
28+
29+
/**
30+
* Return the relative path. Path elements are separated with / char.
31+
*
32+
* @param baseDir a parent directory of {@code file}
33+
* @param file the file to get the relative path
34+
* @return the relative path
35+
*/
36+
public static String relativize(Path baseDir, Path file) {
37+
String path = baseDir.toUri().relativize(file.toUri()).getPath();
38+
if (!"/".equals(baseDir.getFileSystem().getSeparator())) {
39+
// For windows
40+
return path.replace(baseDir.getFileSystem().getSeparator(), "/");
41+
} else {
42+
return path;
43+
}
44+
}
2945
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.github.dockerjava.core;
2+
3+
import static com.github.dockerjava.core.FilePathUtil.relativize;
4+
5+
import java.io.IOException;
6+
import java.nio.file.FileVisitResult;
7+
import java.nio.file.Path;
8+
import java.nio.file.SimpleFileVisitor;
9+
import java.nio.file.attribute.BasicFileAttributes;
10+
11+
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
12+
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
13+
14+
import com.google.common.io.Closeables;
15+
16+
public class TarDirWalker extends SimpleFileVisitor<Path> {
17+
18+
private Path basePath;
19+
20+
private TarArchiveOutputStream tarArchiveOutputStream;
21+
22+
public TarDirWalker(Path basePath, TarArchiveOutputStream tarArchiveOutputStream) {
23+
this.basePath = basePath;
24+
this.tarArchiveOutputStream = tarArchiveOutputStream;
25+
}
26+
27+
@Override
28+
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
29+
if (!dir.equals(basePath)) {
30+
tarArchiveOutputStream.putArchiveEntry(new TarArchiveEntry(relativize(basePath, dir)));
31+
}
32+
return FileVisitResult.CONTINUE;
33+
}
34+
35+
@Override
36+
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
37+
CompressArchiveUtil.putTarEntry(tarArchiveOutputStream, new TarArchiveEntry(relativize(basePath, file)), file);
38+
return FileVisitResult.CONTINUE;
39+
}
40+
41+
@Override
42+
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
43+
Closeables.close(tarArchiveOutputStream, true);
44+
throw exc;
45+
}
46+
}

src/main/java/com/github/dockerjava/core/command/CopyFileFromContainerCmdImpl.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,19 @@
66

77
import org.apache.commons.lang.builder.ToStringBuilder;
88

9-
import com.fasterxml.jackson.annotation.JsonProperty;
109
import com.github.dockerjava.api.NotFoundException;
1110
import com.github.dockerjava.api.command.CopyFileFromContainerCmd;
1211

1312
/**
14-
*
1513
* Copy files or folders from a container.
16-
*
1714
*/
1815
public class CopyFileFromContainerCmdImpl extends AbstrDockerCmd<CopyFileFromContainerCmd, InputStream> implements
1916
CopyFileFromContainerCmd {
2017

2118
private String containerId;
2219

23-
@JsonProperty("HostPath")
2420
private String hostPath = ".";
2521

26-
@JsonProperty("Resource")
2722
private String resource;
2823

2924
public CopyFileFromContainerCmdImpl(CopyFileFromContainerCmd.Exec exec, String containerId, String resource) {
@@ -70,12 +65,11 @@ public CopyFileFromContainerCmdImpl withHostPath(String hostPath) {
7065

7166
@Override
7267
public String toString() {
73-
return new ToStringBuilder(this).append("cp ").append(containerId).append(":").append(resource).toString();
68+
return new ToStringBuilder(this).append("cp ").append(hostPath).append(" ").append(containerId).append(":").append(resource).toString();
7469
}
7570

7671
/**
77-
* @throws NotFoundException
78-
* No such container
72+
* @throws NotFoundException No such container
7973
*/
8074
@Override
8175
public InputStream exec() throws NotFoundException {
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package com.github.dockerjava.core.command;
2+
3+
import com.github.dockerjava.api.NotFoundException;
4+
import com.github.dockerjava.api.command.DockerCmdSyncExec;
5+
import com.github.dockerjava.api.command.SyncDockerCmd;
6+
7+
public interface CopyFileToContainerCmd extends SyncDockerCmd<Void> {
8+
9+
public String getContainerId();
10+
11+
public String getHostResource();
12+
13+
public boolean isNoOverwriteDirNonDir();
14+
15+
public boolean isDirChildrenOnly();
16+
17+
/**
18+
* Set container's id
19+
*
20+
* @param containerId id of the container to copy file to
21+
* @return this
22+
*/
23+
public CopyFileToContainerCmd withContainerId(String containerId);
24+
25+
/**
26+
* Set path to the resource on the host machine
27+
*
28+
* @param resource path to the resource on the host machine
29+
* @return this
30+
*/
31+
public CopyFileToContainerCmd withHostResource(String resource);
32+
33+
/**
34+
* If set to true then it will be an error if unpacking the given content would cause an existing directory to be replaced with a non-directory and vice versa
35+
*
36+
* @param noOverwriteDirNonDir flag to know if non directory can be overwritten
37+
* @return this
38+
*/
39+
public CopyFileToContainerCmd withNoOverwriteDirNonDir(boolean noOverwriteDirNonDir);
40+
41+
/**
42+
* If this flag is set to true, all children of the local directory will be copied to the remote without the root directory.
43+
* For ex: if I have root/titi and root/tata and the remote path is /var/data.
44+
* dirChildrenOnly = true will create /var/data/titi and /var/data/tata
45+
* dirChildrenOnly = false will create /var/data/root/titi and /var/data/root/tata
46+
*
47+
* @param dirChildrenOnly if root directory is ignored
48+
* @return this
49+
*/
50+
public CopyFileToContainerCmd withDirChildrenOnly(boolean dirChildrenOnly);
51+
52+
public String getRemotePath();
53+
54+
public CopyFileToContainerCmd withRemotePath(String remotePath);
55+
56+
@Override
57+
public Void exec() throws NotFoundException;
58+
59+
public static interface Exec extends DockerCmdSyncExec<CopyFileToContainerCmd, Void> {
60+
}
61+
62+
}

0 commit comments

Comments
 (0)