Skip to content

Commit 415977d

Browse files
authored
Merge pull request #160 from xdev-software/develop
Release
2 parents d484918 + a068010 commit 415977d

File tree

10 files changed

+89
-29
lines changed

10 files changed

+89
-29
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# 2.2.0
2+
* Added an explicit option for enabling the Windows NTFS junction fix: ``useWinNTFSJunctionFixIfApplicable`` #155
3+
* 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
4+
* This option is temporary and will be removed once the underlying JDK bug was fixed
5+
* The default logger of ``AdvancedImageFromDockerFile`` now also includes ``dockerImageName`` to make it easier to distinguish between parallel builds
6+
17
# 2.1.1
28
* Addresses a JDK bug which results in a crash or "infinite" loop when encountering recursive NTFS junctions on Windows #155
39

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>software.xdev</groupId>
88
<artifactId>testcontainers-advanced-imagebuilder-root</artifactId>
9-
<version>2.1.2-SNAPSHOT</version>
9+
<version>2.2.0-SNAPSHOT</version>
1010
<packaging>pom</packaging>
1111

1212
<organization>

testcontainers-advanced-imagebuilder-demo/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
<parent>
88
<groupId>software.xdev</groupId>
99
<artifactId>testcontainers-advanced-imagebuilder-root</artifactId>
10-
<version>2.1.2-SNAPSHOT</version>
10+
<version>2.2.0-SNAPSHOT</version>
1111
</parent>
1212

1313
<artifactId>testcontainers-advanced-imagebuilder-demo</artifactId>
14-
<version>2.1.2-SNAPSHOT</version>
14+
<version>2.2.0-SNAPSHOT</version>
1515
<packaging>jar</packaging>
1616

1717
<organization>

testcontainers-advanced-imagebuilder-dummy-app/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>software.xdev</groupId>
88
<artifactId>testcontainers-advanced-imagebuilder-dummy-app</artifactId>
9-
<version>2.1.2-SNAPSHOT</version>
9+
<version>2.2.0-SNAPSHOT</version>
1010
<packaging>jar</packaging>
1111

1212
<organization>

testcontainers-advanced-imagebuilder/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>software.xdev</groupId>
88
<artifactId>testcontainers-advanced-imagebuilder</artifactId>
9-
<version>2.1.2-SNAPSHOT</version>
9+
<version>2.2.0-SNAPSHOT</version>
1010
<packaging>jar</packaging>
1111

1212
<name>testcontainers-advanced-imagebuilder</name>

testcontainers-advanced-imagebuilder/src/main/java/software/xdev/testcontainers/imagebuilder/AdvancedImageFromDockerFile.java

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ public class AdvancedImageFromDockerFile
9696
StringsTrait<AdvancedImageFromDockerFile>,
9797
DockerfileTrait<AdvancedImageFromDockerFile>
9898
{
99-
protected static final Logger LOGGER = LoggerFactory.getLogger(AdvancedImageFromDockerFile.class);
10099
protected final String dockerImageName;
100+
protected final Logger defaultLogger;
101101

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

125126
@SuppressWarnings("checkstyle:MagicNumber")
126127
public AdvancedImageFromDockerFile()
@@ -134,9 +135,18 @@ public AdvancedImageFromDockerFile(final String dockerImageName)
134135
}
135136

136137
public AdvancedImageFromDockerFile(final String dockerImageName, final boolean deleteOnExit)
138+
{
139+
this(
140+
dockerImageName,
141+
deleteOnExit,
142+
LoggerFactory.getLogger(AdvancedImageFromDockerFile.class.getName() + "." + dockerImageName));
143+
}
144+
145+
public AdvancedImageFromDockerFile(final String dockerImageName, final boolean deleteOnExit, final Logger logger)
137146
{
138147
this.dockerImageName = dockerImageName;
139148
this.deleteOnExit = deleteOnExit;
149+
this.defaultLogger = logger;
140150
}
141151

142152
@Override
@@ -355,7 +365,8 @@ protected void configure(final BuildImageCmd buildImageCmd)
355365
this.preGitIgnoreLines,
356366
this.ignoreFileLineFilter,
357367
this.postGitIgnoreLines,
358-
alwaysIncludePaths);
368+
alwaysIncludePaths,
369+
this.useWinNTFSJunctionFixIfApplicable);
359370

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

490501
protected Logger log()
491502
{
492-
return LOGGER;
503+
return this.defaultLogger;
493504
}
494505

495506
public AdvancedImageFromDockerFile withBuildArg(final String key, final String value)
@@ -599,4 +610,17 @@ public AdvancedImageFromDockerFile withBuildImageCmdModifier(final Consumer<Buil
599610
this.buildImageCmdModifiers.add(modifier);
600611
return this;
601612
}
613+
614+
/**
615+
* Should the fix for a crash when encountering Windows NTFS Junctions be applied if applicable?
616+
* <p>
617+
* See {@link software.xdev.testcontainers.imagebuilder.transfer.java.nio.file.winntfs} for details
618+
* </p>
619+
*/
620+
public AdvancedImageFromDockerFile withUseWinNTFSJunctionFixIfApplicable(
621+
final boolean useWinNTFSJunctionFixIfApplicable)
622+
{
623+
this.useWinNTFSJunctionFixIfApplicable = useWinNTFSJunctionFixIfApplicable;
624+
return this;
625+
}
602626
}

testcontainers-advanced-imagebuilder/src/main/java/software/xdev/testcontainers/imagebuilder/transfer/DefaultTransferFilesCreator.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ public Map<Path, String> determineFilesToTransfer(
8282
final Set<String> preGitIgnoreLines,
8383
final Predicate<String> ignoreFileLineFilter,
8484
final Set<String> postGitIgnoreLines,
85-
final Set<String> alwaysIncludedRelativePaths)
85+
final Set<String> alwaysIncludedRelativePaths,
86+
final boolean useWinNTFSJunctionFixIfApplicable)
8687
{
8788
try
8889
{
@@ -100,7 +101,8 @@ public Map<Path, String> determineFilesToTransfer(
100101

101102
return this.walkFilesAndDetermineTransfer(
102103
ignoreNode,
103-
alwaysIncludedRelativePaths);
104+
alwaysIncludedRelativePaths,
105+
useWinNTFSJunctionFixIfApplicable);
104106
}
105107
catch(final IOException ioe)
106108
{
@@ -133,9 +135,11 @@ protected IgnoreNode createIgnoreNode(final Set<String> ignoreLines)
133135

134136
protected Map<Path, String> walkFilesAndDetermineTransfer(
135137
final IgnoreNode ignoreNode,
136-
final Set<String> alwaysIncludedRelativePaths) throws IOException
138+
final Set<String> alwaysIncludedRelativePaths,
139+
final boolean useWinNTFSJunctionFixIfApplicable) throws IOException
137140
{
138141
try(final Stream<Path> walk = findFiles(
142+
useWinNTFSJunctionFixIfApplicable,
139143
this.baseDir,
140144
Integer.MAX_VALUE,
141145
// Ignore directories
@@ -161,13 +165,14 @@ protected Map<Path, String> walkFilesAndDetermineTransfer(
161165
}
162166

163167
protected static Stream<Path> findFiles(
168+
final boolean useWinNTFSJunctionFixIfApplicable,
164169
final Path start,
165170
final int maxDepth,
166171
final BiPredicate<Path, BasicFileAttributes> matcher,
167172
final FileVisitOption... options)
168173
throws IOException
169174
{
170-
return WinNTFSJunctionFiles.shouldBeApplied(start)
175+
return useWinNTFSJunctionFixIfApplicable && WinNTFSJunctionFiles.shouldBeApplied(start)
171176
? WinNTFSJunctionFiles.find(start, maxDepth, matcher, options)
172177
: Files.find(start, maxDepth, matcher, options);
173178
}

testcontainers-advanced-imagebuilder/src/main/java/software/xdev/testcontainers/imagebuilder/transfer/TransferFilesCreator.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ Map<Path, String> determineFilesToTransfer(
2828
Set<String> preGitIgnoreLines,
2929
Predicate<String> ignoreFileLineFilter,
3030
Set<String> postGitIgnoreLines,
31-
Set<String> alwaysIncludedRelativePaths);
31+
Set<String> alwaysIncludedRelativePaths,
32+
boolean useWinNTFSJunctionFixIfApplicable);
3233

3334
InputStream getAllFilesToTransferAsTarInputStream(
3435
Map<Path, String> filesToTransfer,

testcontainers-advanced-imagebuilder/src/main/java/software/xdev/testcontainers/imagebuilder/transfer/java/nio/file/winntfs/FileTreeWalker.java

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@
5555
import java.util.Collection;
5656
import java.util.Iterator;
5757

58+
import org.slf4j.Logger;
59+
import org.slf4j.LoggerFactory;
60+
5861

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

242245
// region Reflect access BasicFileAttributesHolder
243-
private boolean initializedBasicFileAttributesHolderClazz;
244-
private Class<?> basicFileAttributesHolderClazz;
245-
private Method mBasicFileAttributesHolderGet;
246+
private static boolean initializedBasicFileAttributesHolderClazz;
247+
private static Class<?> basicFileAttributesHolderClazz;
248+
private static Method mBasicFileAttributesHolderGet;
249+
private static boolean wasBasicFileAttributesHolderGetAccessSuccess;
246250

247-
private void initBasicFileAttributesHolderClazz()
251+
private static void initBasicFileAttributesHolderClazz()
248252
{
249-
if(!this.initializedBasicFileAttributesHolderClazz)
253+
if(!initializedBasicFileAttributesHolderClazz)
250254
{
251255
try
252256
{
253-
this.basicFileAttributesHolderClazz = Class.forName("sun.nio.fs.BasicFileAttributesHolder");
254-
this.mBasicFileAttributesHolderGet = this.basicFileAttributesHolderClazz.getMethod("get");
255-
this.mBasicFileAttributesHolderGet.setAccessible(true);
257+
basicFileAttributesHolderClazz = Class.forName("sun.nio.fs.BasicFileAttributesHolder");
258+
mBasicFileAttributesHolderGet = basicFileAttributesHolderClazz.getMethod("get");
259+
mBasicFileAttributesHolderGet.setAccessible(true);
256260
}
257261
catch(final Exception ignored)
258262
{
259263
// Ignored
260264
}
261-
this.initializedBasicFileAttributesHolderClazz = true;
265+
initializedBasicFileAttributesHolderClazz = true;
262266
}
263267
}
264268

265-
private boolean isBasicFileAttributesHolder(final Path file)
269+
private static boolean isBasicFileAttributesHolder(final Path file)
266270
{
267-
this.initBasicFileAttributesHolderClazz();
271+
initBasicFileAttributesHolderClazz();
268272

269-
return this.basicFileAttributesHolderClazz != null
270-
&& this.basicFileAttributesHolderClazz.isInstance(file);
273+
return basicFileAttributesHolderClazz != null
274+
&& basicFileAttributesHolderClazz.isInstance(file);
271275
}
272276

273-
private BasicFileAttributes extractFromBasicFileAttributesHolder(final Path file)
277+
private static BasicFileAttributes extractFromBasicFileAttributesHolder(final Path file)
274278
{
275279
try
276280
{
277-
return (BasicFileAttributes)this.mBasicFileAttributesHolderGet.invoke(file);
281+
final BasicFileAttributes attrs = (BasicFileAttributes)mBasicFileAttributesHolderGet.invoke(file);
282+
wasBasicFileAttributesHolderGetAccessSuccess = true;
283+
return attrs;
284+
}
285+
catch(final IllegalAccessException ex)
286+
{
287+
// Did we ever access it successfully?
288+
if(!wasBasicFileAttributesHolderGetAccessSuccess)
289+
{
290+
basicFileAttributesHolderClazz = null;
291+
mBasicFileAttributesHolderGet = null;
292+
final Logger logger = LoggerFactory.getLogger(FileTreeWalker.class);
293+
logger.warn("Failed to access BasicFileAttributesHolder", ex);
294+
logger.warn("To fix this add '--add-exports java.base/sun.nio.fs=ALL-UNNAMED' as VM options");
295+
}
296+
return null;
278297
}
279-
catch(final IllegalAccessException | InvocationTargetException ignored)
298+
catch(final InvocationTargetException ignored)
280299
{
281300
return null;
282301
}

testcontainers-advanced-imagebuilder/src/main/java/software/xdev/testcontainers/imagebuilder/transfer/java/nio/file/winntfs/package-info.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@
1818
* <a href="https://github.com/xdev-software/testcontainers-advanced-imagebuilder/issues/155">
1919
* recursive NTFS junctions on Windows
2020
* </a>.
21+
* <p>
22+
* <b>Please note:</b>
23+
* Enabling it also requires adding ``--add-exports java.base/sun.nio.fs=ALL-UNNAMED`` or performance will be
24+
* impacted by ~20x due non-accessible file attributes cache
25+
* </p>
2126
*
2227
* @see <a href="https://en.wikipedia.org/wiki/NTFS_links#Junction_points">NTFS junction</a>
2328
*/

0 commit comments

Comments
 (0)