From f215929a6ed0883b584ff798bfadf4d679dadf9e Mon Sep 17 00:00:00 2001 From: Marcus Linke Date: Wed, 19 Aug 2015 23:09:13 +0200 Subject: [PATCH 1/3] Fix issue #286 --- .../dockerjava/core/GoLangFileMatch.java | 19 ++++-- .../core/GoLangMatchFileFilter.java | 3 +- .../core/dockerfile/Dockerfile.java | 68 ++++++++++++++++--- .../core/dockerfile/DockerfileStatement.java | 2 +- .../core/command/BuildImageCmdImplTest.java | 8 +++ .../testDockerfileNotIgnored/.dockerignore | 2 + .../testDockerfileNotIgnored/Dockerfile | 9 +++ 7 files changed, 93 insertions(+), 18 deletions(-) create mode 100644 src/test/resources/testDockerfileNotIgnored/.dockerignore create mode 100644 src/test/resources/testDockerfileNotIgnored/Dockerfile diff --git a/src/main/java/com/github/dockerjava/core/GoLangFileMatch.java b/src/main/java/com/github/dockerjava/core/GoLangFileMatch.java index 469beb40b..3e2d57485 100644 --- a/src/main/java/com/github/dockerjava/core/GoLangFileMatch.java +++ b/src/main/java/com/github/dockerjava/core/GoLangFileMatch.java @@ -4,6 +4,7 @@ package com.github.dockerjava.core; import java.io.File; +import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.StringUtils; @@ -23,16 +24,16 @@ * character class (must be non-empty) * c matches character c (c != '*', '?', '\\', '[') * '\\' c matches character c - * + * * character-range: * c matches character c (c != '\\', '-', ']') * '\\' c matches character c * lo '-' hi matches character c for lo <= c <= hi - * + * * Match requires pattern to match all of name, not just a substring. * The only possible returned error is ErrBadPattern, when pattern * is malformed. - * + * * On Windows, escaping is disabled. Instead, '\\' is treated as * path separator. * @@ -45,20 +46,24 @@ public class GoLangFileMatch { public static final boolean IS_WINDOWS = File.separatorChar == '\\'; public static boolean match(List patterns, File file) { - return match(patterns, file.getPath()); + return !match(patterns, file.getPath()).isEmpty(); } public static boolean match(String pattern, File file) { return match(pattern, file.getPath()); } - public static boolean match(List patterns, String name) { + /** + * Returns the matching patterns for the given string + */ + public static List match(List patterns, String name) { + List matches = new ArrayList(); for (String pattern : patterns) { if (match(pattern, name)) { - return true; + matches.add(pattern); } } - return false; + return matches; } public static boolean match(String pattern, String name) { diff --git a/src/main/java/com/github/dockerjava/core/GoLangMatchFileFilter.java b/src/main/java/com/github/dockerjava/core/GoLangMatchFileFilter.java index c8d8e1044..371c30fed 100644 --- a/src/main/java/com/github/dockerjava/core/GoLangMatchFileFilter.java +++ b/src/main/java/com/github/dockerjava/core/GoLangMatchFileFilter.java @@ -24,8 +24,7 @@ public GoLangMatchFileFilter(File base, List patterns) { public boolean accept(File file) { String relativePath = FilePathUtil.relativize(base, file); - boolean match = GoLangFileMatch.match(patterns, relativePath); - return !match; + return GoLangFileMatch.match(patterns, relativePath).isEmpty(); } } diff --git a/src/main/java/com/github/dockerjava/core/dockerfile/Dockerfile.java b/src/main/java/com/github/dockerjava/core/dockerfile/Dockerfile.java index 9513678d7..4fe5ed466 100644 --- a/src/main/java/com/github/dockerjava/core/dockerfile/Dockerfile.java +++ b/src/main/java/com/github/dockerjava/core/dockerfile/Dockerfile.java @@ -10,6 +10,7 @@ import com.google.common.base.Objects; import com.google.common.base.Optional; import com.google.common.collect.Collections2; + import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; @@ -89,12 +90,6 @@ public List getIgnores() throws IOException { } pattern = FilenameUtils.normalize(pattern); try { - // validate pattern and make sure we aren't excluding Dockerfile - if (GoLangFileMatch.match(pattern, "Dockerfile")) { - throw new DockerClientException(String.format( - "Dockerfile is excluded by pattern '%s' on line %s in .dockerignore file", pattern, - lineNumber)); - } ignores.add(pattern); } catch (GoLangFileMatchException e) { throw new DockerClientException(String.format( @@ -169,7 +164,15 @@ public String toString() { public ScannedResult() throws IOException { ignores = getIgnores(); - filesToAdd.add(dockerFile); + + String matchingIgnorePattern = effectiveMatchingIgnorePattern(dockerFile); + + if (matchingIgnorePattern == null) { + filesToAdd.add(dockerFile); + } else { + throw new DockerClientException(String.format( + "Dockerfile is excluded by pattern '%s' in .dockerignore file", matchingIgnorePattern)); + } for (DockerfileStatement statement : getStatements()) { if (statement instanceof DockerfileStatement.Env) { @@ -180,6 +183,55 @@ public ScannedResult() throws IOException { } } + /** + * Returns all matching ignore patterns for the given file name. + */ + private List matchingIgnorePatterns(String fileName) { + List matches = new ArrayList(); + int lineNumber = 0; + for (String pattern : ignores) { + lineNumber++; + try { + if (GoLangFileMatch.match(pattern, fileName)) { + matches.add(pattern); + } + } catch (GoLangFileMatchException e) { + throw new DockerClientException(String.format( + "Invalid pattern '%s' on line %s in .dockerignore file", pattern, lineNumber)); + } + + } + return matches; + } + + /** + * Returns the matching ignore pattern for the given file or null if it should NOT be ignored. + * Exception rules like "!Dockerfile" will be respected. + */ + private String effectiveMatchingIgnorePattern(File file) { + String relativeFilename = FilePathUtil.relativize(getDockerFolder(), file); + + List matchingPattern = matchingIgnorePatterns(relativeFilename); + + if (matchingPattern.isEmpty()) + return null; + + String lastMatchingPattern = matchingPattern.get(matchingPattern.size() - 1); + + int lastMatchingPatternIndex = ignores.lastIndexOf(lastMatchingPattern); + + if(lastMatchingPatternIndex == ignores.size() - 1) return lastMatchingPattern; + + List remainingIgnorePattern = ignores.subList(lastMatchingPatternIndex + 1, ignores.size()); + + for (String ignorePattern : remainingIgnorePattern) { + if (ignorePattern.equals("!" + relativeFilename)) + return null; + } + + return lastMatchingPattern; + } + private void processAddStatement(DockerfileStatement.Add add) throws IOException { add = add.transform(environmentMap); @@ -202,7 +254,7 @@ private void processAddStatement(DockerfileStatement.Add add) throws IOException Collection files = FileUtils.listFiles(src, new GoLangMatchFileFilter(src, ignores), TrueFileFilter.INSTANCE); filesToAdd.addAll(files); - } else if (!GoLangFileMatch.match(ignores, FilePathUtil.relativize(dockerFolder, src))) { + } else if (effectiveMatchingIgnorePattern(src) == null) { filesToAdd.add(src); } else { throw new DockerClientException(String.format( diff --git a/src/main/java/com/github/dockerjava/core/dockerfile/DockerfileStatement.java b/src/main/java/com/github/dockerjava/core/dockerfile/DockerfileStatement.java index b37f5b4f7..2c06312a1 100644 --- a/src/main/java/com/github/dockerjava/core/dockerfile/DockerfileStatement.java +++ b/src/main/java/com/github/dockerjava/core/dockerfile/DockerfileStatement.java @@ -19,7 +19,7 @@ /** * A statement present in a dockerfile. */ -public abstract class DockerfileStatement { +public abstract class DockerfileStatement> { private DockerfileStatement() { } diff --git a/src/test/java/com/github/dockerjava/core/command/BuildImageCmdImplTest.java b/src/test/java/com/github/dockerjava/core/command/BuildImageCmdImplTest.java index 2fb1c545b..22030cc9f 100644 --- a/src/test/java/com/github/dockerjava/core/command/BuildImageCmdImplTest.java +++ b/src/test/java/com/github/dockerjava/core/command/BuildImageCmdImplTest.java @@ -171,6 +171,14 @@ public void testDockerfileIgnored() throws Exception { dockerClient.buildImageCmd(baseDir).withNoCache().exec(new BuildImageResultCallback()).awaitImageId(); } + @Test + public void testDockerfileNotIgnored() throws Exception { + File baseDir = new File(Thread.currentThread().getContextClassLoader().getResource("testDockerfileNotIgnored") + .getFile()); + + dockerClient.buildImageCmd(baseDir).withNoCache().exec(new BuildImageResultCallback()).awaitImageId(); + } + @Test(expectedExceptions = { DockerClientException.class }) public void testInvalidDockerIgnorePattern() throws Exception { File baseDir = new File(Thread.currentThread().getContextClassLoader() diff --git a/src/test/resources/testDockerfileNotIgnored/.dockerignore b/src/test/resources/testDockerfileNotIgnored/.dockerignore new file mode 100644 index 000000000..5c10f6256 --- /dev/null +++ b/src/test/resources/testDockerfileNotIgnored/.dockerignore @@ -0,0 +1,2 @@ +* +!Dockerfile \ No newline at end of file diff --git a/src/test/resources/testDockerfileNotIgnored/Dockerfile b/src/test/resources/testDockerfileNotIgnored/Dockerfile new file mode 100644 index 000000000..a50dffdd6 --- /dev/null +++ b/src/test/resources/testDockerfileNotIgnored/Dockerfile @@ -0,0 +1,9 @@ +FROM ubuntu:latest + +# Copy testrun.sh files into the container + +RUN echo "Successful executed testrun.sh" > /tmp/testrun.sh + +RUN cp /tmp/testrun.sh /usr/local/bin/ && chmod +x /usr/local/bin/testrun.sh + +CMD ["testrun.sh"] From b27aac38a2f4a780f2da96e49d64d358a33f5b21 Mon Sep 17 00:00:00 2001 From: Marcus Linke Date: Wed, 19 Aug 2015 23:42:07 +0200 Subject: [PATCH 2/3] Fix Dockerfile --- src/test/resources/testDockerfileNotIgnored/Dockerfile | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/test/resources/testDockerfileNotIgnored/Dockerfile b/src/test/resources/testDockerfileNotIgnored/Dockerfile index a50dffdd6..6a8106b86 100644 --- a/src/test/resources/testDockerfileNotIgnored/Dockerfile +++ b/src/test/resources/testDockerfileNotIgnored/Dockerfile @@ -1,9 +1,3 @@ FROM ubuntu:latest -# Copy testrun.sh files into the container - -RUN echo "Successful executed testrun.sh" > /tmp/testrun.sh - -RUN cp /tmp/testrun.sh /usr/local/bin/ && chmod +x /usr/local/bin/testrun.sh - -CMD ["testrun.sh"] +CMD ["echo", "Success"] From 389a25ea7de0e2726db771ecc4ea1f1340134e39 Mon Sep 17 00:00:00 2001 From: Marcus Linke Date: Wed, 19 Aug 2015 23:42:47 +0200 Subject: [PATCH 3/3] Beautify source --- .../com/github/dockerjava/core/dockerfile/Dockerfile.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/github/dockerjava/core/dockerfile/Dockerfile.java b/src/main/java/com/github/dockerjava/core/dockerfile/Dockerfile.java index 4fe5ed466..2e8ee8397 100644 --- a/src/main/java/com/github/dockerjava/core/dockerfile/Dockerfile.java +++ b/src/main/java/com/github/dockerjava/core/dockerfile/Dockerfile.java @@ -188,6 +188,7 @@ public ScannedResult() throws IOException { */ private List matchingIgnorePatterns(String fileName) { List matches = new ArrayList(); + int lineNumber = 0; for (String pattern : ignores) { lineNumber++; @@ -199,8 +200,8 @@ private List matchingIgnorePatterns(String fileName) { throw new DockerClientException(String.format( "Invalid pattern '%s' on line %s in .dockerignore file", pattern, lineNumber)); } - } + return matches; } @@ -286,10 +287,7 @@ private Collection resolveWildcards(File file, List ignores) { } private void processEnvStatement(DockerfileStatement.Env env) { - environmentMap.put(env.variable, env.value); } - } - }