Skip to content

Commit 85f75cd

Browse files
authored
Merge pull request #158 from xdev-software/develop
Release
2 parents eee169c + abdc864 commit 85f75cd

File tree

11 files changed

+1003
-8
lines changed

11 files changed

+1003
-8
lines changed

.github/workflows/check-build.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,15 @@ env:
2525

2626
jobs:
2727
build:
28-
runs-on: ubuntu-latest
2928
timeout-minutes: 30
3029

3130
strategy:
3231
matrix:
3332
java: [17, 21]
3433
distribution: [temurin]
35-
34+
os: [ubuntu-latest, windows-latest] # Windows is needed for recursive NTFS junctions
35+
36+
runs-on: ${{ matrix.os }}
3637
steps:
3738
- uses: actions/checkout@v4
3839

@@ -44,9 +45,10 @@ jobs:
4445
cache: 'maven'
4546

4647
- name: Build with Maven
47-
run: ./mvnw -B clean package -P run-integration-tests
48+
run: ./mvnw -B clean package -P run-integration-tests -T2C
4849

4950
- name: Check for uncommited changes
51+
shell: bash
5052
run: |
5153
if [[ "$(git status --porcelain)" != "" ]]; then
5254
echo ----------------------------------------

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# 2.1.1
2+
* Addresses a JDK bug which results in a crash or "infinite" loop when encountering recursive NTFS junctions on Windows #155
3+
14
# 2.1.0
25
* Add customizer for ``TransferArchiveTARCompressor``
36
* Create more predefined FileContentModifiers

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,12 @@
8383
<dependency>
8484
<groupId>net.sourceforge.pmd</groupId>
8585
<artifactId>pmd-core</artifactId>
86-
<version>7.15.0</version>
86+
<version>7.16.0</version>
8787
</dependency>
8888
<dependency>
8989
<groupId>net.sourceforge.pmd</groupId>
9090
<artifactId>pmd-java</artifactId>
91-
<version>7.15.0</version>
91+
<version>7.16.0</version>
9292
</dependency>
9393
</dependencies>
9494
</plugin>

testcontainers-advanced-imagebuilder/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,12 +310,12 @@
310310
<dependency>
311311
<groupId>net.sourceforge.pmd</groupId>
312312
<artifactId>pmd-core</artifactId>
313-
<version>7.15.0</version>
313+
<version>7.16.0</version>
314314
</dependency>
315315
<dependency>
316316
<groupId>net.sourceforge.pmd</groupId>
317317
<artifactId>pmd-java</artifactId>
318-
<version>7.15.0</version>
318+
<version>7.16.0</version>
319319
</dependency>
320320
</dependencies>
321321
</plugin>

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020
import java.io.IOException;
2121
import java.io.InputStream;
2222
import java.io.UncheckedIOException;
23+
import java.nio.file.FileVisitOption;
2324
import java.nio.file.Files;
2425
import java.nio.file.Path;
26+
import java.nio.file.attribute.BasicFileAttributes;
2527
import java.util.ArrayList;
2628
import java.util.LinkedHashMap;
2729
import java.util.LinkedHashSet;
@@ -32,6 +34,7 @@
3234
import java.util.Set;
3335
import java.util.UUID;
3436
import java.util.concurrent.ConcurrentHashMap;
37+
import java.util.function.BiPredicate;
3538
import java.util.function.Predicate;
3639
import java.util.stream.Collectors;
3740
import java.util.stream.Stream;
@@ -43,6 +46,7 @@
4346

4447
import software.xdev.testcontainers.imagebuilder.jgit.ignore.FastIgnoreRule;
4548
import software.xdev.testcontainers.imagebuilder.jgit.ignore.IgnoreNode;
49+
import software.xdev.testcontainers.imagebuilder.transfer.java.nio.file.winntfs.WinNTFSJunctionFiles;
4650

4751

4852
/**
@@ -131,7 +135,7 @@ protected Map<Path, String> walkFilesAndDetermineTransfer(
131135
final IgnoreNode ignoreNode,
132136
final Set<String> alwaysIncludedRelativePaths) throws IOException
133137
{
134-
try(final Stream<Path> walk = Files.find(
138+
try(final Stream<Path> walk = findFiles(
135139
this.baseDir,
136140
Integer.MAX_VALUE,
137141
// Ignore directories
@@ -156,6 +160,18 @@ protected Map<Path, String> walkFilesAndDetermineTransfer(
156160
}
157161
}
158162

163+
protected static Stream<Path> findFiles(
164+
final Path start,
165+
final int maxDepth,
166+
final BiPredicate<Path, BasicFileAttributes> matcher,
167+
final FileVisitOption... options)
168+
throws IOException
169+
{
170+
return WinNTFSJunctionFiles.shouldBeApplied(start)
171+
? WinNTFSJunctionFiles.find(start, maxDepth, matcher, options)
172+
: Files.find(start, maxDepth, matcher, options);
173+
}
174+
159175
@SuppressWarnings("java:S2789")
160176
protected Map.Entry<Path, String> determineFileForTransfer(
161177
final IgnoreNode ignoreNode,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*
2+
* Copyright © 2024 XDEV Software (https://xdev.software)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
/*
17+
* Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved.
18+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
19+
*
20+
* This code is free software; you can redistribute it and/or modify it
21+
* under the terms of the GNU General Public License version 2 only, as
22+
* published by the Free Software Foundation. Oracle designates this
23+
* particular file as subject to the "Classpath" exception as provided
24+
* by Oracle in the LICENSE file that accompanied this code.
25+
*
26+
* This code is distributed in the hope that it will be useful, but WITHOUT
27+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
28+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
29+
* version 2 for more details (a copy is included in the LICENSE file that
30+
* accompanied this code).
31+
*
32+
* You should have received a copy of the GNU General Public License version
33+
* 2 along with this work; if not, write to the Free Software Foundation,
34+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
35+
*
36+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
37+
* or visit www.oracle.com if you need additional information or have any
38+
* questions.
39+
*/
40+
package software.xdev.testcontainers.imagebuilder.transfer.java.nio.file.winntfs;
41+
42+
import java.io.Closeable;
43+
import java.io.IOException;
44+
import java.io.UncheckedIOException;
45+
import java.nio.file.FileVisitOption;
46+
import java.nio.file.Path;
47+
import java.util.Iterator;
48+
import java.util.List;
49+
import java.util.NoSuchElementException;
50+
51+
import software.xdev.testcontainers.imagebuilder.transfer.java.nio.file.winntfs.FileTreeWalker.Event;
52+
53+
54+
/**
55+
* An {@code Iterator} to iterate over the nodes of a file tree.
56+
* <p>
57+
* {@snippet lang = java:
58+
* try (FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options)) {
59+
* while (iterator.hasNext()) {
60+
* Event ev = iterator.next();
61+
* Path path = ev.file();
62+
* BasicFileAttributes attrs = ev.attributes();
63+
* }
64+
* }
65+
*}
66+
*/
67+
public class FileTreeIterator implements Iterator<Event>, Closeable
68+
{
69+
private final FileTreeWalker walker;
70+
private Event next;
71+
72+
/**
73+
* Creates a new iterator to walk the file tree starting at the given file.
74+
*
75+
* @throws IllegalArgumentException if {@code maxDepth} is negative
76+
* @throws IOException if an I/O errors occurs opening the starting file
77+
* @throws SecurityException if the security manager denies access to the starting file
78+
* @throws NullPointerException if {@code start} or {@code options} is {@code null} or the options array
79+
* contains a {@code null} element
80+
*/
81+
FileTreeIterator(final Path start, final int maxDepth, final FileVisitOption... options)
82+
throws IOException
83+
{
84+
this.walker = new FileTreeWalker(List.of(options), maxDepth);
85+
this.next = this.walker.walk(start);
86+
assert this.next.type() == FileTreeWalker.EventType.ENTRY
87+
|| this.next.type() == FileTreeWalker.EventType.START_DIRECTORY;
88+
89+
// IOException if there a problem accessing the starting file
90+
final IOException ioe = this.next.ioeException();
91+
if(ioe != null)
92+
{
93+
throw ioe;
94+
}
95+
}
96+
97+
private void fetchNextIfNeeded()
98+
{
99+
if(this.next == null)
100+
{
101+
FileTreeWalker.Event ev = this.walker.next();
102+
while(ev != null)
103+
{
104+
final IOException ioe = ev.ioeException();
105+
if(ioe != null)
106+
{
107+
throw new UncheckedIOException(ioe);
108+
}
109+
110+
// END_DIRECTORY events are ignored
111+
if(ev.type() != FileTreeWalker.EventType.END_DIRECTORY)
112+
{
113+
this.next = ev;
114+
return;
115+
}
116+
ev = this.walker.next();
117+
}
118+
}
119+
}
120+
121+
@Override
122+
public boolean hasNext()
123+
{
124+
if(!this.walker.isOpen())
125+
{
126+
throw new IllegalStateException();
127+
}
128+
this.fetchNextIfNeeded();
129+
return this.next != null;
130+
}
131+
132+
@Override
133+
public Event next()
134+
{
135+
if(!this.walker.isOpen())
136+
{
137+
throw new IllegalStateException();
138+
}
139+
this.fetchNextIfNeeded();
140+
if(this.next == null)
141+
{
142+
throw new NoSuchElementException();
143+
}
144+
final Event result = this.next;
145+
this.next = null;
146+
return result;
147+
}
148+
149+
@Override
150+
public void close()
151+
{
152+
this.walker.close();
153+
}
154+
}

0 commit comments

Comments
 (0)