diff --git a/engine/build.gradle.kts b/engine/build.gradle.kts index 10220720..8d9c6e87 100644 --- a/engine/build.gradle.kts +++ b/engine/build.gradle.kts @@ -77,6 +77,7 @@ dependencies { testImplementation("com.squareup.okhttp3:mockwebserver") implementation("org.apache.commons:commons-compress:1.20") + testImplementation("org.apache.commons:commons-lang3:3.12.0") implementation("de.gesellix:docker-filesocket:2021-06-06T17-29-35") testImplementation("de.gesellix:testutil:2021-04-21T23-29-14") diff --git a/engine/src/main/java/de/gesellix/docker/builder/BuildContextBuilder.java b/engine/src/main/java/de/gesellix/docker/builder/BuildContextBuilder.java new file mode 100644 index 00000000..bcf4662c --- /dev/null +++ b/engine/src/main/java/de/gesellix/docker/builder/BuildContextBuilder.java @@ -0,0 +1,86 @@ +package de.gesellix.docker.builder; + +import de.gesellix.util.IOUtils; +import okio.Okio; +import okio.Source; +import org.apache.commons.compress.archivers.tar.TarArchiveEntry; +import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.zip.GZIPOutputStream; + +public class BuildContextBuilder { + + private static final Logger log = LoggerFactory.getLogger(BuildContextBuilder.class); + + public static void archiveTarFilesRecursively(File base, File targetFile) throws IOException { + List filenames = new DockerignoreFileFilter(base, new ArrayList<>(Collections.singletonList(targetFile.getAbsolutePath()))).collectFiles(base); + log.debug("found {} files in buildContext.", filenames.size()); + archiveTarFiles(base, filenames.stream().map(File::getAbsolutePath).collect(Collectors.toList()), targetFile); + } + + public static void archiveTarFilesRecursively(File base, OutputStream target) throws IOException { + List filenames = new DockerignoreFileFilter(base, new ArrayList<>()).collectFiles(base); + log.debug("found {} files in buildContext.", filenames.size()); + archiveTarFiles(base, filenames.stream().map(File::getAbsolutePath).collect(Collectors.toList()), target); + } + + public static void archiveTarFiles(File base, List filenames, File targetFile) throws IOException { + archiveTarFiles(base, filenames, new FileOutputStream(targetFile)); + } + + public static void archiveTarFiles(File base, List filenames, OutputStream target) throws IOException { + try (TarArchiveOutputStream tos = new TarArchiveOutputStream(new GZIPOutputStream(target))) { + tos.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU); + for (String filename : filenames) { + String relativeFileName = relativize(base, new File(filename)); + log.debug("adding {} as {}", filename, relativeFileName); + addAsTarEntry(new File(filename), relativeFileName, tos); + } + } + } + + public static void addAsTarEntry(File file, String relativeFileName, TarArchiveOutputStream tos) throws IOException { + TarArchiveEntry tarEntry = new TarArchiveEntry(file); + tarEntry.setName(relativeFileName); + + if (!file.isDirectory()) { + if (Files.isExecutable(file.toPath())) { + tarEntry.setMode(tarEntry.getMode() | 0755); + } + } + + tos.putArchiveEntry(tarEntry); + + if (!file.isDirectory()) { + copyFile(file, tos); + } + + tos.closeArchiveEntry(); + } + + public static String relativize(File base, File absolute) { + return base.toPath().relativize(absolute.toPath()).toString(); + } + + public static long copyFile(File input, OutputStream output) throws IOException { + Source source = null; + try { + source = Okio.source(input); + return IOUtils.copy(source, Okio.sink(output)); + } + finally { + IOUtils.closeQuietly(source); + } + } +} diff --git a/engine/src/main/java/de/gesellix/docker/builder/DockerignoreFileFilter.java b/engine/src/main/java/de/gesellix/docker/builder/DockerignoreFileFilter.java new file mode 100644 index 00000000..c5b52271 --- /dev/null +++ b/engine/src/main/java/de/gesellix/docker/builder/DockerignoreFileFilter.java @@ -0,0 +1,101 @@ +package de.gesellix.docker.builder; + +import de.gesellix.util.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +public class DockerignoreFileFilter { + + private static final Logger log = LoggerFactory.getLogger(DockerignoreFileFilter.class); + + private final GlobsMatcher globsMatcher; + + public DockerignoreFileFilter(File base) { + this(base, Collections.emptyList()); + } + + public DockerignoreFileFilter(File base, List additionalExcludes) { + List dockerignore = getDockerignorePatterns(base); + dockerignore.add(".dockerignore"); + dockerignore.addAll(additionalExcludes); + try { + dockerignore = relativize(dockerignore, base); + } + catch (IllegalArgumentException e) { + log.error(String.format("base: %1$s, dockerignore: %2$s", base.getAbsolutePath(), dockerignore), e); + throw e; + } + + log.debug("base: {}", base.getAbsolutePath()); + log.debug("dockerignore: {}", dockerignore); + globsMatcher = new GlobsMatcher(base, dockerignore); + } + + public List getDockerignorePatterns(final File base) { + List result = new ArrayList<>(); + File[] files = base.listFiles(); + if (files == null || files.length == 0) { + return result; + } + Optional dockerignoreFile = Arrays.stream(files).filter((file -> { + String relativeFileName = relativize(base, file); + return ".dockerignore".equals(relativeFileName); + })).findFirst(); + if (!dockerignoreFile.isPresent()) { + return result; + } + try { + Collections.addAll(result, IOUtils.toString(new FileInputStream(dockerignoreFile.get())).split("[\r\n]+")); + return result; + } + catch (IOException e) { + log.error("Couldn't read {}", dockerignoreFile.get()); + throw new RuntimeException(e); + } + } + + public List relativize(Collection dockerignores, final File base) { + return dockerignores.stream() + .map((String dockerignore) -> new File(dockerignore).isAbsolute() ? relativize(base, new File(dockerignore)) : dockerignore) + .collect(Collectors.toList()); + } + + public String relativize(File base, File absolute) { + Path basePath = base.getAbsoluteFile().toPath(); + Path otherPath = absolute.getAbsoluteFile().toPath(); + if (!basePath.getRoot().equals(otherPath.getRoot())) { + // Can occur on Windows, when + // - java temp directory is under C:/ + // - project directory is under D:/ + return otherPath.toString(); + } + + return basePath.relativize(otherPath).toString(); + } + + public List collectFiles(File base) throws IOException { + final List files = new ArrayList<>(); + Files.walk(base.toPath()) + .filter(p -> Files.isRegularFile(p) && !getGlobsMatcher().matches(p.toFile())) + .forEach(p -> files.add(p.toFile())); + log.debug("filtered list of files: {}", files); + return files; + } + + public GlobsMatcher getGlobsMatcher() { + return globsMatcher; + } +} diff --git a/engine/src/main/java/de/gesellix/docker/builder/GlobsMatcher.java b/engine/src/main/java/de/gesellix/docker/builder/GlobsMatcher.java new file mode 100644 index 00000000..3b4026de --- /dev/null +++ b/engine/src/main/java/de/gesellix/docker/builder/GlobsMatcher.java @@ -0,0 +1,117 @@ +package de.gesellix.docker.builder; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.PathMatcher; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class GlobsMatcher { + + private static final Logger log = LoggerFactory.getLogger(GlobsMatcher.class); + + private final File base; + private final List globs; + private List matchers; + + public GlobsMatcher(File base, List globs) { + this.base = base; + this.globs = globs; + } + + public void initMatchers() { + if (this.matchers == null) { + final FileSystem fileSystem = FileSystems.getDefault(); + this.matchers = new ArrayList<>(); + globs.stream() + .flatMap(glob -> { + if (glob.endsWith("/")) { + return Stream.of( + new Matcher(fileSystem, glob.replaceAll("/$", "")), + new Matcher(fileSystem, glob.replaceAll("/$", "/**"))); + } + else { + return Stream.of(new Matcher(fileSystem, glob)); + } + }) + .collect(Collectors.toCollection(ArrayDeque::new)) + .descendingIterator() // reverse the stream + .forEachRemaining(matchers::add); + if (log.isDebugEnabled()) { + matchers.forEach((m) -> log.debug("pattern: " + m.getPattern())); + } + } + } + + public boolean matches(File path) { + initMatchers(); + + final Path relativePath = base.getAbsoluteFile().toPath().relativize(path.getAbsoluteFile().toPath()); + Optional matcher = matchers.stream().filter((m) -> m.matches(relativePath)).findFirst(); + if (!matcher.isPresent() && relativePath.getParent() != null) { + matcher = matchers.stream().filter((m) -> m.matches(relativePath.getParent())).findFirst(); + } + + return matcher.isPresent() && !matcher.get().getNegate(); + } + + public List getMatchers() { + return matchers; + } + + public static class Matcher implements PathMatcher { + + private final String pattern; + private final PathMatcher matcher; + private final boolean negate; + + public Matcher(FileSystem fileSystem, String pattern) { + // According to https://docs.docker.com/engine/reference/builder/#dockerignore-file + // and https://golang.org/pkg/path/filepath/#Clean we clean paths + // by removing trailing slashes and also by replacing slashes with the path separator. + String replacement = File.separatorChar == '\\' ? "\\\\" : File.separatorChar + ""; + this.pattern = String.join(replacement, pattern.replaceAll("/", replacement).split(replacement)); + + String negation = "!"; + this.negate = pattern.startsWith(negation); + if (this.negate) { + String invertedPattern = this.pattern.substring(negation.length()); + this.matcher = createGlob(fileSystem, invertedPattern); + } + else { + this.matcher = createGlob(fileSystem, this.pattern); + } + } + + public static PathMatcher createGlob(FileSystem fileSystem, final String glob) { + return fileSystem.getPathMatcher("glob:" + glob); + } + + @Override + public boolean matches(Path path) { + return matcher.matches(path); + } + + public String getPattern() { + return pattern; + } + + public boolean getNegate() { + return negate; + } + + @Override + public String toString() { + return "matching " + (negate ? "!" : "") + pattern; + } + } +} diff --git a/engine/src/test/groovy/de/gesellix/docker/builder/BuildContextBuilderSpec.groovy b/engine/src/test/groovy/de/gesellix/docker/builder/BuildContextBuilderSpec.groovy new file mode 100644 index 00000000..e87261c9 --- /dev/null +++ b/engine/src/test/groovy/de/gesellix/docker/builder/BuildContextBuilderSpec.groovy @@ -0,0 +1,100 @@ +package de.gesellix.docker.builder + +import de.gesellix.util.IOUtils +import org.apache.commons.compress.archivers.tar.TarArchiveInputStream +import spock.lang.Specification + +import java.util.zip.GZIPInputStream + +class BuildContextBuilderSpec extends Specification { + + def "test archiveTarFilesRecursively"() { + given: + def inputDirectory = new File(getClass().getResource("/docker/Dockerfile").toURI()).parentFile + def targetFile = File.createTempFile("buildContext", ".tar") + targetFile.deleteOnExit() + + when: + BuildContextBuilder.archiveTarFilesRecursively(inputDirectory, targetFile) + + then: + def collectedEntryNames = collectEntryNames(targetFile) + collectedEntryNames.sort() == ["subdirectory/payload.txt", "Dockerfile", "script.sh"].sort() + } + + def "test archiveTarFilesRecursively keeps executable flag"() { + given: + def inputDirectory = new File(getClass().getResource("/docker/Dockerfile").toURI()).parentFile + def targetFile = File.createTempFile("buildContext", ".tar") + targetFile.deleteOnExit() + + when: + BuildContextBuilder.archiveTarFilesRecursively(inputDirectory, targetFile) + + then: + getFileMode(targetFile, "script.sh") == 0100755 + } + + def "test archiveTarFilesRecursively excludes targetFile when in same baseDir"() { + given: + def inputDirectory = new File(getClass().getResource("/docker/Dockerfile").toURI()).parentFile + def targetFile = new File(inputDirectory, "buildContext.tar") + targetFile.createNewFile() + targetFile.deleteOnExit() + + when: + BuildContextBuilder.archiveTarFilesRecursively(inputDirectory, targetFile) + + then: + def collectedEntryNames = collectEntryNames(targetFile) + collectedEntryNames.sort() == ["subdirectory/payload.txt", "Dockerfile", "script.sh"].sort() + + // TODO cannot be deleted while the Gradle daemon is running? +// cleanup: +// Files.delete(targetFile.toPath()) +// println targetFile.delete() + } + + def collectEntryNames(File tarArchive) { + def collectedEntryNames = [] + def tarArchiveInputStream = new TarArchiveInputStream(new GZIPInputStream(new FileInputStream(tarArchive))) + + def entry + while (entry = tarArchiveInputStream.nextTarEntry) { + collectedEntryNames << entry.name + } + collectedEntryNames + } + + def getFileMode(File tarArchive, String filename) { + def tarArchiveInputStream = new TarArchiveInputStream(new GZIPInputStream(new FileInputStream(tarArchive))) + + def entry + while (entry = tarArchiveInputStream.nextTarEntry) { + if (entry.name == filename) { + return entry.getMode() + } + } + throw new FileNotFoundException(filename) + } + + def "test relativize"() { + when: + def relativized = BuildContextBuilder.relativize(new File("./base/dir"), new File("./base/dir/with/sub/dir")) + + then: + relativized == new File("with/sub/dir").toPath().toString() + } + + def "test copyFile"() { + given: + def inputFile = new File(getClass().getResource("/docker/subdirectory/payload.txt").toURI()) + def outputStream = new ByteArrayOutputStream() + + when: + BuildContextBuilder.copyFile(inputFile, outputStream) + + then: + new String(outputStream.toByteArray()) == IOUtils.toString(new FileInputStream(inputFile)) + } +} diff --git a/engine/src/test/groovy/de/gesellix/docker/builder/DockerignoreFileFilterSpec.groovy b/engine/src/test/groovy/de/gesellix/docker/builder/DockerignoreFileFilterSpec.groovy new file mode 100644 index 00000000..74d5c262 --- /dev/null +++ b/engine/src/test/groovy/de/gesellix/docker/builder/DockerignoreFileFilterSpec.groovy @@ -0,0 +1,53 @@ +package de.gesellix.docker.builder + +import org.apache.commons.lang3.SystemUtils +import spock.lang.Requires +import spock.lang.Specification + +class DockerignoreFileFilterSpec extends Specification { + + def "collects desired files"() { + given: + def baseDir = getClass().getResource("/dockerignore").file + def base = new File(baseDir) + when: + def collectedFiles = new DockerignoreFileFilter(base, []).collectFiles(base) + then: + collectedFiles.sort() == [new File("${baseDir}/ignorefolder/keepme.txt"), + new File("${baseDir}/subfolder/content.txt"), + new File("${baseDir}/subfolder/subsubfolder/content.txt")].sort() + } + + def "collects all non-dockerignored files"() { + given: + def baseDir = getClass().getResource("/dockerignore-all-but-some").file + def base = new File(baseDir) + when: + def collectedFiles = new DockerignoreFileFilter(base, []).collectFiles(base) + then: + collectedFiles.sort() == [new File("${baseDir}/Dockerfile"), + new File("${baseDir}/content.txt")].sort() + } + + def "handles trailing slashes in exclude patterns"() { + given: + def baseDir = getClass().getResource("/dockerignore_subdirs").file + def base = new File(baseDir) + when: + def collectedFiles = new DockerignoreFileFilter(base, []).collectFiles(base) + then: + collectedFiles.sort() == [new File("${baseDir}/keepme/a-file-to-be-kept.txt"), + new File("${baseDir}/keepme/subdir/keep-me.txt")].sort() + } + + @Requires({ SystemUtils.IS_OS_WINDOWS }) + def "handles trailing backslashes in patterns (windows only)"() { + given: + def baseDir = getClass().getResource("/dockerignore_windows").file + def base = new File(baseDir) + when: + def collectedFiles = new DockerignoreFileFilter(base, []).collectFiles(base) + then: + collectedFiles == [new File("${baseDir}/keepme/to-be-kept.txt")] + } +} diff --git a/engine/src/test/groovy/de/gesellix/docker/builder/GlobsMatcherSpec.groovy b/engine/src/test/groovy/de/gesellix/docker/builder/GlobsMatcherSpec.groovy new file mode 100644 index 00000000..5891a3ad --- /dev/null +++ b/engine/src/test/groovy/de/gesellix/docker/builder/GlobsMatcherSpec.groovy @@ -0,0 +1,164 @@ +package de.gesellix.docker.builder + +import org.apache.commons.lang3.SystemUtils +import spock.lang.Requires +import spock.lang.Specification +import spock.lang.Unroll + +import java.util.regex.PatternSyntaxException + +class GlobsMatcherSpec extends Specification { + + def "matches all patterns"() { + given: + def matcher = new GlobsMatcher(new File(""), ["abc", "cde"]) + matcher.initMatchers() + + expect: + matcher.matchers.size() == 2 + and: + matcher.matches(new File("cde")) + and: + matcher.matches(new File("abc")) + } + + @Unroll + "#pattern should match #path"(String pattern, File base, File path) { + expect: + new GlobsMatcher(base, [pattern]).matches(path) + + where: + pattern | base | path + "abc" | new File(".") | new File("./abc") + "abc" | new File("") | new File("abc") + "*" | new File("") | new File("abc") + "*c" | new File("") | new File("abc") + "a*" | new File("") | new File("a/bc") + "a*/b" | new File("") | new File("a/b/c") + "a*" | new File("") | new File("a") + "a*/b" | new File("") | new File("abc/b") + "a*b*c*d*e*/f" | new File("") | new File("axbxcxdxe/f") + "a*b*c*d*e*/f" | new File("") | new File("axbxcxdxexx/f") + "a*b?c*x" | new File("") | new File("abxbbxdbxebxczzx") + "ab[c]" | new File("") | new File("abc") + "ab[b-d]" | new File("") | new File("abc") + "ab[!c]" | new File("") | new File("abd") + "ab[!e-g]" | new File("") | new File("abc") + "a?c" | new File("") | new File("a§c") + "[a-ζ]*" | new File("") | new File("α") + "[-]" | new File("") | new File("-") + } + + @Requires({ SystemUtils.IS_OS_LINUX || SystemUtils.IS_OS_MAC }) + @Unroll + "#pattern should match #path on unix systems"(String pattern, File base, File path) { + expect: + new GlobsMatcher(base, [pattern]).matches(path) + + where: + pattern | base | path + "[\\-]" | new File("") | new File("-") + "[x\\-]" | new File("") | new File("-") + "[x\\-]" | new File("") | new File("x") + "[\\-x]" | new File("") | new File("x") +// "[\\]a]" | new File("") | new File("]") + } + + @Requires({ SystemUtils.IS_OS_WINDOWS }) + @Unroll + "#pattern should match #path on windows systems"(String pattern, File base, File path) { + expect: + new GlobsMatcher(base, [pattern]).matches(path) + + where: + pattern | base | path + "bin\\" | new File("") | new File("bin\\foo") + } + + @Unroll + "#pattern should not match #path"(String pattern, File path) { + expect: + !new GlobsMatcher(new File(""), [pattern]).matches(path) + + where: + pattern | path + "a*/b" | new File("a/c/b") + "a*b*c*d*e*/f" | new File("axbxcxdxe/xx/f") + "a*b*c*d*e*/f" | new File("axbxcxdxexx/ff") + "a*b?c*x" | new File("abxbbxdbxebxczzy") + "ab[e-g]" | new File("abc") + "ab[!c]" | new File("abc") + "ab[!b-d]" | new File("abc") + "a??c" | new File("abc") + "!a*b" | new File("ab") + "a?b" | new File("a/b") + "a*b" | new File("a/b") + } + + @Requires({ SystemUtils.IS_OS_LINUX || SystemUtils.IS_OS_MAC }) + @Unroll + "#pattern should not match #path on unix systems"(String pattern, File base, File path) { + expect: + !new GlobsMatcher(base, [pattern]).matches(path) + + where: + pattern | base | path + "[a-ζ]*" | new File("") | new File("A") + "[x\\-]" | new File("") | new File("z") + "[\\-x]" | new File("") | new File("z") + } + + @Unroll + "#pattern should throw exception"(String pattern, File base, File path) { + when: + new GlobsMatcher(base, [pattern]).matches(path) + + then: + thrown(PatternSyntaxException) + + where: + pattern | base | path + "[]a]" | new File("") | new File("]") + } + + @Requires({ SystemUtils.IS_OS_LINUX || SystemUtils.IS_OS_MAC }) + @Unroll + "#pattern should throw exception on unix systems"(String pattern, File base, File path) { + when: + new GlobsMatcher(base, [pattern]).matches(path) + + then: + thrown(PatternSyntaxException) + + where: + pattern | base | path + // On *nix, the backslash is the escape character, so it's invalid to be used at the end of a pattern + // A trailing backslash is only valid on Windows. + // We actually differ from the official client's behaviour, which silently ignores invalid patterns. + "bin\\" | new File("") | new File("bin/foo") + } + + def "allows pattern exclusions"() { + expect: + new GlobsMatcher(new File(""), patterns).matches(path) == shouldMatch + + where: + patterns | path | shouldMatch + ["!ab.c", "*.c"] | new File("ab.c") | true + ["dir", "!dir/ab.c"] | new File("dir/ab.c") | false + ["dir/", "!dir/ab.c"] | new File("dir/ab.c") | false + ["dir/*", "!dir/ab.c"] | new File("dir/ab.c") | false + ["dir/*.c"] | new File("dir/ab.c") | true + ["dir/*.c", "!dir/ab.c"] | new File("dir/ab.c") | false + } + + def "allows pattern exclusions in subdirectories"() { + expect: + new GlobsMatcher(new File(""), patterns).matches(path) == shouldMatch + + where: + patterns | path | shouldMatch + ["ignorefolder", "!ignorefolder/keepme.txt", "**/ignore.txt"] | new File("ignorefolder/keepme.txt") | false + ["ignorefolder", "!ignorefolder/keepme.txt", "**/ignore.txt"] | new File("ignorefolder/dropme.txt") | true + } +} diff --git a/engine/src/test/resources/docker/.dockerignore b/engine/src/test/resources/docker/.dockerignore new file mode 100644 index 00000000..514d05a2 --- /dev/null +++ b/engine/src/test/resources/docker/.dockerignore @@ -0,0 +1,3 @@ +i-should-be-ignored.txt +**/ignore-me.txt +subdirectory/i-should-be-ignored-too.txt diff --git a/engine/src/test/resources/docker/Dockerfile b/engine/src/test/resources/docker/Dockerfile new file mode 100644 index 00000000..2df7d103 --- /dev/null +++ b/engine/src/test/resources/docker/Dockerfile @@ -0,0 +1,4 @@ +FROM alpine:edge +MAINTAINER Tobias Gesellchen + +ADD ./subdirectory/payload.txt /payload.txt diff --git a/engine/src/test/resources/docker/i-should-be-ignored.txt b/engine/src/test/resources/docker/i-should-be-ignored.txt new file mode 100644 index 00000000..e69de29b diff --git a/engine/src/test/resources/docker/script.sh b/engine/src/test/resources/docker/script.sh new file mode 100755 index 00000000..aa6cfe19 --- /dev/null +++ b/engine/src/test/resources/docker/script.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +echo "hello world" diff --git a/engine/src/test/resources/docker/subdirectory/i-should-be-ignored-too.txt b/engine/src/test/resources/docker/subdirectory/i-should-be-ignored-too.txt new file mode 100644 index 00000000..e69de29b diff --git a/engine/src/test/resources/docker/subdirectory/ignore-me.txt b/engine/src/test/resources/docker/subdirectory/ignore-me.txt new file mode 100644 index 00000000..e69de29b diff --git a/engine/src/test/resources/docker/subdirectory/payload.txt b/engine/src/test/resources/docker/subdirectory/payload.txt new file mode 100644 index 00000000..f0eec86f --- /dev/null +++ b/engine/src/test/resources/docker/subdirectory/payload.txt @@ -0,0 +1 @@ +some content \ No newline at end of file diff --git a/engine/src/test/resources/dockerignore-all-but-some/.dockerignore b/engine/src/test/resources/dockerignore-all-but-some/.dockerignore new file mode 100644 index 00000000..73632db7 --- /dev/null +++ b/engine/src/test/resources/dockerignore-all-but-some/.dockerignore @@ -0,0 +1,3 @@ +* +!Dockerfile +!content.txt diff --git a/engine/src/test/resources/dockerignore-all-but-some/.hidden-dir/.gitkeep b/engine/src/test/resources/dockerignore-all-but-some/.hidden-dir/.gitkeep new file mode 100644 index 00000000..3857d287 --- /dev/null +++ b/engine/src/test/resources/dockerignore-all-but-some/.hidden-dir/.gitkeep @@ -0,0 +1 @@ +this one is hidden, similar to a .git folder with its contents diff --git a/engine/src/test/resources/dockerignore-all-but-some/Dockerfile b/engine/src/test/resources/dockerignore-all-but-some/Dockerfile new file mode 100644 index 00000000..9eb15be5 --- /dev/null +++ b/engine/src/test/resources/dockerignore-all-but-some/Dockerfile @@ -0,0 +1,3 @@ +FROM alpine:edge +COPY . /tmp +CMD [ "ls", "-h", "/tmp" ] diff --git a/engine/src/test/resources/dockerignore-all-but-some/content.txt b/engine/src/test/resources/dockerignore-all-but-some/content.txt new file mode 100644 index 00000000..e69de29b diff --git a/engine/src/test/resources/dockerignore-all-but-some/ignore-me.txt b/engine/src/test/resources/dockerignore-all-but-some/ignore-me.txt new file mode 100644 index 00000000..e69de29b diff --git a/engine/src/test/resources/dockerignore/.dockerignore b/engine/src/test/resources/dockerignore/.dockerignore new file mode 100644 index 00000000..7bb1daa5 --- /dev/null +++ b/engine/src/test/resources/dockerignore/.dockerignore @@ -0,0 +1,3 @@ +ignorefolder +!ignorefolder/keepme.txt +**/ignore.txt diff --git a/engine/src/test/resources/dockerignore/ignorefolder/content.txt b/engine/src/test/resources/dockerignore/ignorefolder/content.txt new file mode 100644 index 00000000..e69de29b diff --git a/engine/src/test/resources/dockerignore/ignorefolder/keepme.txt b/engine/src/test/resources/dockerignore/ignorefolder/keepme.txt new file mode 100644 index 00000000..e69de29b diff --git a/engine/src/test/resources/dockerignore/subfolder/content.txt b/engine/src/test/resources/dockerignore/subfolder/content.txt new file mode 100644 index 00000000..e69de29b diff --git a/engine/src/test/resources/dockerignore/subfolder/ignore.txt b/engine/src/test/resources/dockerignore/subfolder/ignore.txt new file mode 100644 index 00000000..e69de29b diff --git a/engine/src/test/resources/dockerignore/subfolder/subsubfolder/content.txt b/engine/src/test/resources/dockerignore/subfolder/subsubfolder/content.txt new file mode 100644 index 00000000..e69de29b diff --git a/engine/src/test/resources/dockerignore_subdirs/.dockerignore b/engine/src/test/resources/dockerignore_subdirs/.dockerignore new file mode 100644 index 00000000..c2658d7d --- /dev/null +++ b/engine/src/test/resources/dockerignore_subdirs/.dockerignore @@ -0,0 +1 @@ +node_modules/ diff --git a/engine/src/test/resources/dockerignore_subdirs/keepme/a-file-to-be-kept.txt b/engine/src/test/resources/dockerignore_subdirs/keepme/a-file-to-be-kept.txt new file mode 100644 index 00000000..e69de29b diff --git a/engine/src/test/resources/dockerignore_subdirs/keepme/subdir/keep-me.txt b/engine/src/test/resources/dockerignore_subdirs/keepme/subdir/keep-me.txt new file mode 100644 index 00000000..e69de29b diff --git a/engine/src/test/resources/dockerignore_subdirs/node_modules/a-file-to-be-excluded.txt b/engine/src/test/resources/dockerignore_subdirs/node_modules/a-file-to-be-excluded.txt new file mode 100644 index 00000000..e69de29b diff --git a/engine/src/test/resources/dockerignore_subdirs/node_modules/ignored_subdir/another-file-to-be-excluded.txt b/engine/src/test/resources/dockerignore_subdirs/node_modules/ignored_subdir/another-file-to-be-excluded.txt new file mode 100644 index 00000000..e69de29b diff --git a/engine/src/test/resources/dockerignore_windows/.dockerignore b/engine/src/test/resources/dockerignore_windows/.dockerignore new file mode 100644 index 00000000..49445af8 --- /dev/null +++ b/engine/src/test/resources/dockerignore_windows/.dockerignore @@ -0,0 +1,2 @@ +bin\ +Dockerfile diff --git a/engine/src/test/resources/dockerignore_windows/Dockerfile b/engine/src/test/resources/dockerignore_windows/Dockerfile new file mode 100644 index 00000000..7a00da37 --- /dev/null +++ b/engine/src/test/resources/dockerignore_windows/Dockerfile @@ -0,0 +1,3 @@ +FROM microsoft/aspnetcore:2.0 +COPY . /example +RUN ls -lisah /example diff --git a/engine/src/test/resources/dockerignore_windows/bin/to-be-excluded.txt b/engine/src/test/resources/dockerignore_windows/bin/to-be-excluded.txt new file mode 100644 index 00000000..e69de29b diff --git a/engine/src/test/resources/dockerignore_windows/keepme/to-be-kept.txt b/engine/src/test/resources/dockerignore_windows/keepme/to-be-kept.txt new file mode 100644 index 00000000..e69de29b diff --git a/integrationtest/src/test/groovy/de/gesellix/docker/engine/TestConstants.groovy b/integrationtest/src/test/groovy/de/gesellix/docker/engine/TestConstants.groovy index 337ea4c1..ff74c545 100644 --- a/integrationtest/src/test/groovy/de/gesellix/docker/engine/TestConstants.groovy +++ b/integrationtest/src/test/groovy/de/gesellix/docker/engine/TestConstants.groovy @@ -31,8 +31,8 @@ class TestConstants { versionDetails = [ ApiVersion : { it == "1.41" }, Arch : { it == "amd64" }, - BuildTime : { it =~ "04/12/2021 \\w+" }, - GitCommit : { it == "b24528647a" }, + BuildTime : { it =~ "06/29/2021 \\w+" }, + GitCommit : { it == "a3dc69e6b9" }, GoVersion : { it == "go1.13.15" }, KernelVersion: { it =~ "\\d.\\d{1,2}.\\d{1,2}\\w*" }, MinAPIVersion: { it == "1.24" },