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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# 2.2.0
* Added an explicit option for enabling the Windows NTFS junction fix: ``useWinNTFSJunctionFixIfApplicable`` #155
* Enabling it also requires adding ``--add-exports java.base/sun.nio.fs=ALL-UNNAMED`` or performance will be impacted by ~20x due to non-accessible file attributes cache
* This option is temporary and will be removed once the underlying JDK bug was fixed
* The default logger of ``AdvancedImageFromDockerFile`` now also includes ``dockerImageName`` to make it easier to distinguish between parallel builds

# 2.1.1
* Addresses a JDK bug which results in a crash or "infinite" loop when encountering recursive NTFS junctions on Windows #155

Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>software.xdev</groupId>
<artifactId>testcontainers-advanced-imagebuilder-root</artifactId>
<version>2.1.2-SNAPSHOT</version>
<version>2.2.0-SNAPSHOT</version>
<packaging>pom</packaging>

<organization>
Expand Down
4 changes: 2 additions & 2 deletions testcontainers-advanced-imagebuilder-demo/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
<parent>
<groupId>software.xdev</groupId>
<artifactId>testcontainers-advanced-imagebuilder-root</artifactId>
<version>2.1.2-SNAPSHOT</version>
<version>2.2.0-SNAPSHOT</version>
</parent>

<artifactId>testcontainers-advanced-imagebuilder-demo</artifactId>
<version>2.1.2-SNAPSHOT</version>
<version>2.2.0-SNAPSHOT</version>
<packaging>jar</packaging>

<organization>
Expand Down
2 changes: 1 addition & 1 deletion testcontainers-advanced-imagebuilder-dummy-app/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>software.xdev</groupId>
<artifactId>testcontainers-advanced-imagebuilder-dummy-app</artifactId>
<version>2.1.2-SNAPSHOT</version>
<version>2.2.0-SNAPSHOT</version>
<packaging>jar</packaging>

<organization>
Expand Down
2 changes: 1 addition & 1 deletion testcontainers-advanced-imagebuilder/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>software.xdev</groupId>
<artifactId>testcontainers-advanced-imagebuilder</artifactId>
<version>2.1.2-SNAPSHOT</version>
<version>2.2.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>testcontainers-advanced-imagebuilder</name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ public class AdvancedImageFromDockerFile
StringsTrait<AdvancedImageFromDockerFile>,
DockerfileTrait<AdvancedImageFromDockerFile>
{
protected static final Logger LOGGER = LoggerFactory.getLogger(AdvancedImageFromDockerFile.class);
protected final String dockerImageName;
protected final Logger defaultLogger;

protected final boolean deleteOnExit;
protected final Map<String, Transferable> transferables = new HashMap<>();
Expand All @@ -121,6 +121,7 @@ public class AdvancedImageFromDockerFile
protected Optional<String> target = Optional.empty();
protected final Set<Consumer<BuildImageCmd>> buildImageCmdModifiers = new LinkedHashSet<>();
protected Set<String> externalDependencyImageNames = Collections.emptySet();
protected boolean useWinNTFSJunctionFixIfApplicable;

@SuppressWarnings("checkstyle:MagicNumber")
public AdvancedImageFromDockerFile()
Expand All @@ -134,9 +135,18 @@ public AdvancedImageFromDockerFile(final String dockerImageName)
}

public AdvancedImageFromDockerFile(final String dockerImageName, final boolean deleteOnExit)
{
this(
dockerImageName,
deleteOnExit,
LoggerFactory.getLogger(AdvancedImageFromDockerFile.class.getName() + "." + dockerImageName));
}

public AdvancedImageFromDockerFile(final String dockerImageName, final boolean deleteOnExit, final Logger logger)
{
this.dockerImageName = dockerImageName;
this.deleteOnExit = deleteOnExit;
this.defaultLogger = logger;
}

@Override
Expand Down Expand Up @@ -355,7 +365,8 @@ protected void configure(final BuildImageCmd buildImageCmd)
this.preGitIgnoreLines,
this.ignoreFileLineFilter,
this.postGitIgnoreLines,
alwaysIncludePaths);
alwaysIncludePaths,
this.useWinNTFSJunctionFixIfApplicable);

this.log().info(
"{}x files will be transferred (determination took {}ms)",
Expand Down Expand Up @@ -489,7 +500,7 @@ protected boolean canImageNameBePulled(final String imageName)

protected Logger log()
{
return LOGGER;
return this.defaultLogger;
}

public AdvancedImageFromDockerFile withBuildArg(final String key, final String value)
Expand Down Expand Up @@ -599,4 +610,17 @@ public AdvancedImageFromDockerFile withBuildImageCmdModifier(final Consumer<Buil
this.buildImageCmdModifiers.add(modifier);
return this;
}

/**
* Should the fix for a crash when encountering Windows NTFS Junctions be applied if applicable?
* <p>
* See {@link software.xdev.testcontainers.imagebuilder.transfer.java.nio.file.winntfs} for details
* </p>
*/
public AdvancedImageFromDockerFile withUseWinNTFSJunctionFixIfApplicable(
final boolean useWinNTFSJunctionFixIfApplicable)
{
this.useWinNTFSJunctionFixIfApplicable = useWinNTFSJunctionFixIfApplicable;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ public Map<Path, String> determineFilesToTransfer(
final Set<String> preGitIgnoreLines,
final Predicate<String> ignoreFileLineFilter,
final Set<String> postGitIgnoreLines,
final Set<String> alwaysIncludedRelativePaths)
final Set<String> alwaysIncludedRelativePaths,
final boolean useWinNTFSJunctionFixIfApplicable)
{
try
{
Expand All @@ -100,7 +101,8 @@ public Map<Path, String> determineFilesToTransfer(

return this.walkFilesAndDetermineTransfer(
ignoreNode,
alwaysIncludedRelativePaths);
alwaysIncludedRelativePaths,
useWinNTFSJunctionFixIfApplicable);
}
catch(final IOException ioe)
{
Expand Down Expand Up @@ -133,9 +135,11 @@ protected IgnoreNode createIgnoreNode(final Set<String> ignoreLines)

protected Map<Path, String> walkFilesAndDetermineTransfer(
final IgnoreNode ignoreNode,
final Set<String> alwaysIncludedRelativePaths) throws IOException
final Set<String> alwaysIncludedRelativePaths,
final boolean useWinNTFSJunctionFixIfApplicable) throws IOException
{
try(final Stream<Path> walk = findFiles(
useWinNTFSJunctionFixIfApplicable,
this.baseDir,
Integer.MAX_VALUE,
// Ignore directories
Expand All @@ -161,13 +165,14 @@ protected Map<Path, String> walkFilesAndDetermineTransfer(
}

protected static Stream<Path> findFiles(
final boolean useWinNTFSJunctionFixIfApplicable,
final Path start,
final int maxDepth,
final BiPredicate<Path, BasicFileAttributes> matcher,
final FileVisitOption... options)
throws IOException
{
return WinNTFSJunctionFiles.shouldBeApplied(start)
return useWinNTFSJunctionFixIfApplicable && WinNTFSJunctionFiles.shouldBeApplied(start)
? WinNTFSJunctionFiles.find(start, maxDepth, matcher, options)
: Files.find(start, maxDepth, matcher, options);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ Map<Path, String> determineFilesToTransfer(
Set<String> preGitIgnoreLines,
Predicate<String> ignoreFileLineFilter,
Set<String> postGitIgnoreLines,
Set<String> alwaysIncludedRelativePaths);
Set<String> alwaysIncludedRelativePaths,
boolean useWinNTFSJunctionFixIfApplicable);

InputStream getAllFilesToTransferAsTarInputStream(
Map<Path, String> filesToTransfer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@
import java.util.Collection;
import java.util.Iterator;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
* Walks a file tree, generating a sequence of events corresponding to the files in the tree.
Expand Down Expand Up @@ -240,43 +243,59 @@ IOException ioeException()
}

// region Reflect access BasicFileAttributesHolder
private boolean initializedBasicFileAttributesHolderClazz;
private Class<?> basicFileAttributesHolderClazz;
private Method mBasicFileAttributesHolderGet;
private static boolean initializedBasicFileAttributesHolderClazz;
private static Class<?> basicFileAttributesHolderClazz;
private static Method mBasicFileAttributesHolderGet;
private static boolean wasBasicFileAttributesHolderGetAccessSuccess;

private void initBasicFileAttributesHolderClazz()
private static void initBasicFileAttributesHolderClazz()
{
if(!this.initializedBasicFileAttributesHolderClazz)
if(!initializedBasicFileAttributesHolderClazz)
{
try
{
this.basicFileAttributesHolderClazz = Class.forName("sun.nio.fs.BasicFileAttributesHolder");
this.mBasicFileAttributesHolderGet = this.basicFileAttributesHolderClazz.getMethod("get");
this.mBasicFileAttributesHolderGet.setAccessible(true);
basicFileAttributesHolderClazz = Class.forName("sun.nio.fs.BasicFileAttributesHolder");
mBasicFileAttributesHolderGet = basicFileAttributesHolderClazz.getMethod("get");
mBasicFileAttributesHolderGet.setAccessible(true);
}
catch(final Exception ignored)
{
// Ignored
}
this.initializedBasicFileAttributesHolderClazz = true;
initializedBasicFileAttributesHolderClazz = true;
}
}

private boolean isBasicFileAttributesHolder(final Path file)
private static boolean isBasicFileAttributesHolder(final Path file)
{
this.initBasicFileAttributesHolderClazz();
initBasicFileAttributesHolderClazz();

return this.basicFileAttributesHolderClazz != null
&& this.basicFileAttributesHolderClazz.isInstance(file);
return basicFileAttributesHolderClazz != null
&& basicFileAttributesHolderClazz.isInstance(file);
}

private BasicFileAttributes extractFromBasicFileAttributesHolder(final Path file)
private static BasicFileAttributes extractFromBasicFileAttributesHolder(final Path file)
{
try
{
return (BasicFileAttributes)this.mBasicFileAttributesHolderGet.invoke(file);
final BasicFileAttributes attrs = (BasicFileAttributes)mBasicFileAttributesHolderGet.invoke(file);
wasBasicFileAttributesHolderGetAccessSuccess = true;
return attrs;
}
catch(final IllegalAccessException ex)
{
// Did we ever access it successfully?
if(!wasBasicFileAttributesHolderGetAccessSuccess)
{
basicFileAttributesHolderClazz = null;
mBasicFileAttributesHolderGet = null;
final Logger logger = LoggerFactory.getLogger(FileTreeWalker.class);
logger.warn("Failed to access BasicFileAttributesHolder", ex);
logger.warn("To fix this add '--add-exports java.base/sun.nio.fs=ALL-UNNAMED' as VM options");
}
return null;
}
catch(final IllegalAccessException | InvocationTargetException ignored)
catch(final InvocationTargetException ignored)
{
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
* <a href="https://github.com/xdev-software/testcontainers-advanced-imagebuilder/issues/155">
* recursive NTFS junctions on Windows
* </a>.
* <p>
* <b>Please note:</b>
* Enabling it also requires adding ``--add-exports java.base/sun.nio.fs=ALL-UNNAMED`` or performance will be
* impacted by ~20x due non-accessible file attributes cache
* </p>
*
* @see <a href="https://en.wikipedia.org/wiki/NTFS_links#Junction_points">NTFS junction</a>
*/
Expand Down