Skip to content

Commit

Permalink
Introduce an abstraction over files and classpath resources.
Browse files Browse the repository at this point in the history
This encapsulates all the complexity of generating a path that the Docker daemon is about to create a volume mount for.

This should resolve a general problem with spaces in paths, which was seen in one particular form as #263.

Use recursive copy for docker context TAR to allow contents of directories to be used in Dockerfiles and Docker Compose contexts
  • Loading branch information
rnorth committed Apr 14, 2017
1 parent 4a4ff3d commit 6351b1f
Show file tree
Hide file tree
Showing 19 changed files with 312 additions and 119 deletions.
14 changes: 14 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@
</exclusions>
</dependency>

<!-- Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest -->
<dependency>
<groupId>fakejar</groupId>
<artifactId>fakejar</artifactId>
<version>0</version>
<scope>test</scope>
</dependency>
</dependencies>

<!-- Prevent netty version conflicts with redisson, used for testing -->
Expand Down Expand Up @@ -232,4 +239,11 @@
</plugin>
</plugins>
</build>

<repositories>
<repository>
<id>testlib</id>
<url>file://${project.basedir}/testlib/repo</url>
</repository>
</repositories>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import com.google.common.base.Splitter;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.Uninterruptibles;
import org.apache.commons.lang.SystemUtils;
import org.junit.runner.Description;
import org.rnorth.ducttape.ratelimits.RateLimiter;
import org.rnorth.ducttape.ratelimits.RateLimiterBuilder;
Expand All @@ -32,6 +31,7 @@

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.stream.Collectors.toList;
import static org.testcontainers.containers.BindMode.READ_ONLY;
import static org.testcontainers.containers.BindMode.READ_WRITE;

Expand Down Expand Up @@ -196,7 +196,7 @@ private List<Container> listChildContainers() {
.exec().stream()
.filter(container -> Arrays.stream(container.getNames()).anyMatch(name ->
name.startsWith("/" + identifier)))
.collect(Collectors.toList());
.collect(toList());
}

private void startAmbassadorContainers(Profiler profiler) {
Expand Down Expand Up @@ -394,15 +394,13 @@ public ContainerisedDockerCompose(List<File> composeFiles, String identifier) {
// Map the docker compose file into the container
final File dockerComposeBaseFile = composeFiles.get(0);
final String pwd = dockerComposeBaseFile.getAbsoluteFile().getParentFile().getAbsolutePath();
final String containerPwd;
if (SystemUtils.IS_OS_WINDOWS) {
containerPwd = PathUtils.createMinGWPath(pwd).substring(1);
} else {
containerPwd = pwd;
}
final String containerPwd = MountableFile.forHostPath(pwd).getResolvedPath();

final List<String> absoluteDockerComposeFiles = composeFiles.stream().map(
file -> containerPwd + "/" + file.getAbsoluteFile().getName()).collect(Collectors.toList());
final List<String> absoluteDockerComposeFiles = composeFiles.stream()
.map(File::getAbsolutePath)
.map(MountableFile::forHostPath)
.map(MountableFile::getResolvedPath)
.collect(toList());
final String composeFileEnvVariableValue = Joiner.on(File.pathSeparator).join(absoluteDockerComposeFiles);
logger().debug("Set env COMPOSE_FILE={}", composeFileEnvVariableValue);
addEnv(ENV_COMPOSE_FILE, composeFileEnvVariableValue);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import lombok.Cleanup;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
Expand Down Expand Up @@ -128,16 +127,12 @@ public void onNext(BuildResponseItem item) {
profiler.start("Send context as TAR");

try (TarArchiveOutputStream tarArchive = new TarArchiveOutputStream(new GZIPOutputStream(out))) {
tarArchive.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);

for (Map.Entry<String, Transferable> entry : transferables.entrySet()) {
TarArchiveEntry tarEntry = new TarArchiveEntry(entry.getKey());
Transferable transferable = entry.getValue();
tarEntry.setSize(transferable.getSize());
tarEntry.setMode(transferable.getFileMode());

tarArchive.putArchiveEntry(tarEntry);
transferable.transferTo(tarArchive);
tarArchive.closeArchiveEntry();

final String destination = entry.getKey();
transferable.transferTo(tarArchive, destination);
}
tarArchive.finish();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
package org.testcontainers.images.builder;

import java.io.OutputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.io.IOUtils;

import java.io.IOException;

public interface Transferable {

int DEFAULT_FILE_MODE = 0100644;
int DEFAULT_DIR_MODE = 040755;

/**
* Get file mode. Default is 0100644.
* @see Transferable#DEFAULT_FILE_MODE
*
* @return file mode
* @see Transferable#DEFAULT_FILE_MODE
*/
default int getFileMode() {
return DEFAULT_FILE_MODE;
Expand All @@ -26,7 +31,26 @@ default int getFileMode() {
/**
* transfer content of this Transferable to the output stream. <b>Must not</b> close the stream.
*
* @param outputStream stream to output
* @param tarArchiveOutputStream stream to output
* @param destination
*/
void transferTo(OutputStream outputStream);
default void transferTo(TarArchiveOutputStream tarArchiveOutputStream, final String destination) {
TarArchiveEntry tarEntry = new TarArchiveEntry(destination);
tarEntry.setSize(getSize());
tarEntry.setMode(getFileMode());

try {
tarArchiveOutputStream.putArchiveEntry(tarEntry);
IOUtils.write(getBytes(), tarArchiveOutputStream);
tarArchiveOutputStream.closeArchiveEntry();
} catch (IOException e) {
throw new RuntimeException("Can't transfer " + getDescription(), e);
}
}

default byte[] getBytes() {
return new byte[0];
}

String getDescription();
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package org.testcontainers.images.builder.traits;

import lombok.Getter;
import org.apache.commons.io.IOUtils;
import org.testcontainers.images.builder.Transferable;
import org.testcontainers.images.builder.dockerfile.DockerfileBuilder;

import java.io.IOException;
import java.io.OutputStream;
import java.util.function.Consumer;

/**
Expand All @@ -33,12 +30,8 @@ public long getSize() {
}

@Override
public void transferTo(OutputStream outputStream) {
try {
IOUtils.write(getBytes(), outputStream);
} catch (IOException e) {
throw new RuntimeException("Can't transfer Dockerfile", e);
}
public String getDescription() {
return "Dockerfile: " + builder;
}
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
package org.testcontainers.images.builder.traits;

import org.testcontainers.images.builder.Transferable;
import org.testcontainers.utility.MountableFile;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;

/**
Expand All @@ -19,31 +16,7 @@ default SELF withFileFromFile(String path, File file) {
}

default SELF withFileFromPath(String path, Path filePath) {
return ((SELF) this).withFileFromTransferable(path, new Transferable() {

@Override
public long getSize() {
try {
return Files.size(filePath);
} catch (IOException e) {
throw new RuntimeException("Can't get size from " + filePath, e);
}
}

@Override
public int getFileMode() {
return DEFAULT_FILE_MODE | (Files.isExecutable(filePath) ? 0755 : 0);
}

@Override
public void transferTo(OutputStream outputStream) {
try {
Files.copy(filePath, outputStream);
} catch (IOException e) {
throw new RuntimeException("Can't transfer file " + filePath, e);
}
}

});
final MountableFile mountableFile = MountableFile.forHostPath(filePath);
return ((SELF) this).withFileFromTransferable(path, mountableFile);
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package org.testcontainers.images.builder.traits;

import org.apache.commons.io.IOUtils;
import lombok.Getter;
import org.apache.commons.lang.StringUtils;
import org.testcontainers.images.builder.Transferable;

import java.io.IOException;
import java.io.OutputStream;

/**
* BuildContextBuilder's trait for String-based manipulations.
*
Expand All @@ -16,6 +13,7 @@ public interface StringsTrait<SELF extends StringsTrait<SELF> & BuildContextBuil
default SELF withFileFromString(String path, String content) {
return ((SELF) this).withFileFromTransferable(path, new Transferable() {

@Getter
byte[] bytes = content.getBytes();

@Override
Expand All @@ -24,14 +22,9 @@ public long getSize() {
}

@Override
public void transferTo(OutputStream outputStream) {
try {
IOUtils.write(bytes, outputStream);
} catch (IOException e) {
throw new RuntimeException("Can't transfer string " + StringUtils.abbreviate(content, 100), e);
}
public String getDescription() {
return "String: " + StringUtils.abbreviate(content, 100);
}

});
}
}
Loading

0 comments on commit 6351b1f

Please sign in to comment.