X Tutup
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,9 @@ private void processAddStatement(DockerfileStatement.Add add) throws IOException

add = add.transform(environmentMap);

if (add.isFileResource()) {
for (String resource : add.getFileResources()) {

File dockerFolder = getDockerFolder();
String resource = add.source;

File src = new File(resource);
if (!src.isAbsolute()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.github.dockerjava.api.DockerClientException;
import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import org.apache.commons.lang.StringUtils;

/**
* A statement present in a dockerfile.
Expand Down Expand Up @@ -72,36 +78,42 @@ public String toString() {
*/
public static class Add extends DockerfileStatement<Add> {

private static final Pattern ADD_OR_COPY_PATTERN = Pattern.compile("^(ADD|COPY)\\s+(.*)\\s+(.*)$");
private static final Pattern ARGUMENT_TOKENIZER = Pattern.compile("(?:\"[^\"]+\")|(\\S+)");

public final String source;
public final Collection<String> sources;

public final String destination;

private Add(String source, String destination) {
this.source = source;
private Add(Collection<String> sources, String destination) {
this.sources = sources;
this.destination = destination;
}

private Add(final Matcher matcher) {
source = matcher.group(2);
destination = matcher.group(3);
}

@Override
public Add transform(Map<String, String> env) {
String resource = filterForEnvironmentVars(env, source).trim();
return new Add(resource, destination);
}

public boolean isFileResource() {
URI uri;
try {
uri = new URI(source);
} catch (URISyntaxException e) {
return false;
}
return uri.getScheme() == null || "file".equals(uri.getScheme());
public Add transform(final Map<String, String> env) {
Collection<String> resources = Collections2.transform(sources, new Function<String, String>() {
@Override
public String apply(String source) {
return filterForEnvironmentVars(env, source).trim();
}
});
return new Add(resources, destination);
}

public Iterable<String> getFileResources() {
return Collections2.filter(sources, new Predicate<String>() {

@Override
public boolean apply(String source) {
URI uri;
try {
uri = new URI(source);
} catch (URISyntaxException e) {
return false;
}
return uri.getScheme() == null || "file".equals(uri.getScheme());
}
});
}

/**
Expand All @@ -112,21 +124,37 @@ public boolean isFileResource() {
* @return optional typed item.
*/
public static Optional<Add> create(String statement) {
Matcher matcher = ADD_OR_COPY_PATTERN.matcher(statement.trim());
if (!matcher.find()) {
Matcher argumentMatcher = ARGUMENT_TOKENIZER.matcher(statement.trim());

if (!argumentMatcher.find()) {
return Optional.absent();
}

if (matcher.groupCount() != 3) {
String commandName = argumentMatcher.group();
if (!(StringUtils.equals(commandName, "ADD") || StringUtils.equals(commandName, "COPY"))) {
return Optional.absent();
}

String lastToken = null;
Collection<String> sources = new ArrayList<>();

while (argumentMatcher.find()) {
if (lastToken != null) {
sources.add(lastToken);
}
lastToken = argumentMatcher.group().replaceAll("(^\")|(\"$)", "");
}

if (sources.isEmpty()) {
throw new DockerClientException("Wrong ADD or COPY format");
}

return Optional.of(new Add(matcher));
return Optional.of(new Add(sources, lastToken));
}

@Override
public String toString() {
return Objects.toStringHelper(this).add("source", source).add("destination", destination).toString();
return Objects.toStringHelper(this).add("sources", sources).add("destination", destination).toString();
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.github.dockerjava.core.dockerfile;

import com.google.common.base.Function;
import junit.framework.TestCase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.Test;

import java.io.File;
import java.io.IOException;
import java.util.Collection;

import static com.google.common.collect.Collections2.transform;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;

public class DockerfileAddMultipleFilesTest extends TestCase {

private static final Logger log = LoggerFactory.getLogger(DockerfileAddMultipleFilesTest.class);
private static final Function<File, String> TO_FILE_NAMES = new Function<File, String>() {
@Override
public String apply(File file) {
return file.getName();
}
};

@Test
public void testAddMultipleFiles() throws IOException {
File baseDir = new File(Thread.currentThread().getContextClassLoader().getResource("testAddMultipleFiles").getFile());
Dockerfile dockerfile = new Dockerfile(new File(baseDir, "Dockerfile"));
Dockerfile.ScannedResult result = dockerfile.parse();
Collection<String> filesToAdd = transform(result.filesToAdd, TO_FILE_NAMES);

assertThat(filesToAdd, containsInAnyOrder("Dockerfile", "src1", "src2"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.github.dockerjava.core.dockerfile;

import com.github.dockerjava.api.DockerClientException;
import com.google.common.base.Optional;
import junit.framework.TestCase;
import org.hamcrest.Matcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.is;

public class DockerfileStatementAddTest extends TestCase {

private static final Logger log = LoggerFactory.getLogger(DockerfileStatementAddTest.class);

@DataProvider(name = "valid scenarios")
public Object[][] validScenarios() {
return new Object[][] {
{"ADD src dest", contains("src"), "dest"},
{"ADD \"src file\" \"dest\"", contains("src file"), "dest"},
{"ADD src\"file dest", contains("src\"file"), "dest"},
{"ADD src1 src2 dest", containsInAnyOrder("src1", "src2"), "dest"},
{"COPY src dest", contains("src"), "dest"},
{"COPY \"src file\" \"dest\"", contains("src file"), "dest"},
{"COPY src\"file dest", contains("src\"file"), "dest"},
{"COPY src1 src2 dest", containsInAnyOrder("src1", "src2"), "dest"}
};
}

@Test(dataProvider = "valid scenarios")
public void testAddOrCopyPattern(String command, Matcher matchesExpectation, String expectedDest) {
Optional<DockerfileStatement.Add> optionalAdd = DockerfileStatement.Add.create(command);
assertThat(optionalAdd.isPresent(), is(true));
assertThat(optionalAdd.get().sources, matchesExpectation);
assertThat(optionalAdd.get().destination, is(expectedDest));
}

@Test(expectedExceptions = { DockerClientException.class })
public void shouldThrowExceptionIfDestNotSpecified() {
DockerfileStatement.Add.create("ADD src");
}
}
5 changes: 5 additions & 0 deletions src/test/resources/testAddMultipleFiles/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM ubuntu:latest

# Copy multiple source files into the container

ADD src1 src2 /tmp/
Empty file.
Empty file.
X Tutup