Skip to content

Commit 7a7b141

Browse files
author
Gary Gregory
committed
Apply, refactor, clean up
#203 by Andrew Shcheglov (ashcheglov on GitHub).
1 parent 91e2c95 commit 7a7b141

4 files changed

Lines changed: 133 additions & 3 deletions

File tree

src/changes/changes.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ The <action> type attribute can be add,update,fix,remove.
111111
<action issue="IO-705" dev="ggregory" type="fix" due-to="Hao Zhong, Gary Gregory">
112112
Fix infinite loops in ObservableInputStream read(*) when an exception is caught but not re-thrown.
113113
</action>
114+
<action issue="IO-719" dev="ggregory" type="fix" due-to="Andrew Shcheglov, Gary Gregory">
115+
Fixed error of copying directories between different file systems #203.
116+
</action>
114117
<!-- ADD -->
115118
<action dev="ggregory" type="add" due-to="Gary Gregory">
116119
Add FileSystemProviders class.

src/main/java/org/apache/commons/io/file/CopyDirectoryVisitor.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.nio.file.FileVisitResult;
2323
import java.nio.file.Files;
2424
import java.nio.file.Path;
25+
import java.nio.file.ProviderMismatchException;
2526
import java.nio.file.attribute.BasicFileAttributes;
2627
import java.util.Arrays;
2728
import java.util.Objects;
@@ -99,7 +100,7 @@ public boolean equals(final Object obj) {
99100
}
100101
final CopyDirectoryVisitor other = (CopyDirectoryVisitor) obj;
101102
return Arrays.equals(copyOptions, other.copyOptions) && Objects.equals(sourceDirectory, other.sourceDirectory)
102-
&& Objects.equals(targetDirectory, other.targetDirectory);
103+
&& Objects.equals(targetDirectory, other.targetDirectory);
103104
}
104105

105106
/**
@@ -144,16 +145,29 @@ public int hashCode() {
144145
@Override
145146
public FileVisitResult preVisitDirectory(final Path directory, final BasicFileAttributes attributes)
146147
throws IOException {
147-
final Path newTargetDir = targetDirectory.resolve(sourceDirectory.relativize(directory));
148+
final Path newTargetDir = resolveRelativeAsString(directory);
148149
if (Files.notExists(newTargetDir)) {
149150
Files.createDirectory(newTargetDir);
150151
}
151152
return super.preVisitDirectory(directory, attributes);
152153
}
153154

155+
/**
156+
* Relativizes against {@code sourceDirectory}, then resolves against {@code targetDirectory}.
157+
*
158+
* We have to call {@link Path#toString()} relative value because we cannot use paths belonging to different
159+
* FileSystems in the Path methods, usually this leads to {@link ProviderMismatchException}.
160+
*
161+
* @param directory the directory to relativize.
162+
* @return a new path, relativized against sourceDirectory, then resolved against targetDirectory.
163+
*/
164+
private Path resolveRelativeAsString(final Path directory) {
165+
return targetDirectory.resolve(sourceDirectory.relativize(directory).toString());
166+
}
167+
154168
@Override
155169
public FileVisitResult visitFile(final Path sourceFile, final BasicFileAttributes attributes) throws IOException {
156-
final Path targetFile = targetDirectory.resolve(sourceDirectory.relativize(sourceFile));
170+
final Path targetFile = resolveRelativeAsString(sourceFile);
157171
copy(sourceFile, targetFile);
158172
return super.visitFile(targetFile, attributes);
159173
}

src/test/java/org/apache/commons/io/file/PathUtilsTest.java

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,16 @@
2222
import static org.junit.jupiter.api.Assertions.assertTrue;
2323

2424
import java.io.IOException;
25+
import java.net.URI;
2526
import java.nio.file.DirectoryStream;
27+
import java.nio.file.FileSystem;
28+
import java.nio.file.FileSystems;
2629
import java.nio.file.Files;
2730
import java.nio.file.Path;
2831
import java.nio.file.Paths;
32+
import java.util.HashMap;
2933
import java.util.Iterator;
34+
import java.util.Map;
3035

3136
import org.apache.commons.io.filefilter.NameFileFilter;
3237
import org.junit.jupiter.api.Test;
@@ -37,6 +42,10 @@
3742
*/
3843
public class PathUtilsTest extends TestArguments {
3944

45+
private static final String TEST_JAR_NAME = "test.jar";
46+
47+
private static final String TEST_JAR_PATH = "src/test/resources/org/apache/commons/io/test.jar";
48+
4049
private static final String PATH_FIXTURE = "NOTICE.txt";
4150

4251
/**
@@ -45,6 +54,110 @@ public class PathUtilsTest extends TestArguments {
4554
@TempDir
4655
public Path tempDir;
4756

57+
private FileSystem openArchive(final Path p, final boolean createNew) throws IOException {
58+
final FileSystem archive;
59+
if (createNew) {
60+
final Map<String, String> env = new HashMap<>();
61+
env.put("create", "true");
62+
final URI fileUri = p.toAbsolutePath().toUri();
63+
final URI uri = URI.create("jar:" + fileUri.toASCIIString());
64+
archive = FileSystems.newFileSystem(uri, env, null);
65+
} else {
66+
archive = FileSystems.newFileSystem(p, (ClassLoader) null);
67+
}
68+
return archive;
69+
}
70+
71+
@Test
72+
public void testCopyDirectoryForDifferentFilesystemsWithAbsolutePath() throws IOException {
73+
final Path tempDir = Files.createTempDirectory(getClass().getCanonicalName()).toAbsolutePath();
74+
try {
75+
final Path archivePath = Paths.get(TEST_JAR_PATH);
76+
try (final FileSystem archive = openArchive(archivePath, false)) {
77+
// relative jar -> absolute dir
78+
Path sourceDir = archive.getPath("dir1");
79+
PathUtils.copyDirectory(sourceDir, tempDir);
80+
assertTrue(Files.exists(tempDir.resolve("f1")));
81+
82+
// absolute jar -> absolute dir
83+
sourceDir = archive.getPath("/next");
84+
PathUtils.copyDirectory(sourceDir, tempDir);
85+
assertTrue(Files.exists(tempDir.resolve("dir")));
86+
}
87+
} finally {
88+
PathUtils.deleteDirectory(tempDir);
89+
}
90+
}
91+
92+
@Test
93+
public void testCopyDirectoryForDifferentFilesystemsWithAbsolutePathReverse() throws IOException {
94+
final Path tempDir = Files.createTempDirectory(getClass().getCanonicalName());
95+
try {
96+
try (final FileSystem archive = openArchive(tempDir.resolve(TEST_JAR_NAME), true)) {
97+
// absolute dir -> relative jar
98+
Path targetDir = archive.getPath("target");
99+
Files.createDirectory(targetDir);
100+
final Path sourceDir = Paths.get("src/test/resources/org/apache/commons/io/dirs-2-file-size-2")
101+
.toAbsolutePath();
102+
PathUtils.copyDirectory(sourceDir, targetDir);
103+
assertTrue(Files.exists(targetDir.resolve("dirs-a-file-size-1")));
104+
105+
// absolute dir -> absolute jar
106+
targetDir = archive.getPath("/");
107+
PathUtils.copyDirectory(sourceDir, targetDir);
108+
assertTrue(Files.exists(targetDir.resolve("dirs-a-file-size-1")));
109+
}
110+
} finally {
111+
PathUtils.deleteDirectory(tempDir);
112+
}
113+
}
114+
115+
@Test
116+
public void testCopyDirectoryForDifferentFilesystemsWithRelativePath() throws IOException {
117+
final Path tempDir = Files.createTempDirectory(getClass().getCanonicalName());
118+
try {
119+
final Path archivePath = Paths.get(TEST_JAR_PATH);
120+
try (final FileSystem archive = openArchive(archivePath, false);
121+
final FileSystem targetArchive = openArchive(tempDir.resolve(TEST_JAR_NAME), true)) {
122+
final Path targetDir = targetArchive.getPath("targetDir");
123+
Files.createDirectory(targetDir);
124+
// relative jar -> relative dir
125+
Path sourceDir = archive.getPath("next");
126+
PathUtils.copyDirectory(sourceDir, targetDir);
127+
assertTrue(Files.exists(targetDir.resolve("dir")));
128+
129+
// absolute jar -> relative dir
130+
sourceDir = archive.getPath("/dir1");
131+
PathUtils.copyDirectory(sourceDir, targetDir);
132+
assertTrue(Files.exists(targetDir.resolve("f1")));
133+
}
134+
} finally {
135+
PathUtils.deleteDirectory(tempDir);
136+
}
137+
}
138+
139+
@Test
140+
public void testCopyDirectoryForDifferentFilesystemsWithRelativePathReverse() throws IOException {
141+
final Path tempDir = Files.createTempDirectory(getClass().getCanonicalName());
142+
try {
143+
try (final FileSystem archive = openArchive(tempDir.resolve(TEST_JAR_NAME), true)) {
144+
// relative dir -> relative jar
145+
Path targetDir = archive.getPath("target");
146+
Files.createDirectory(targetDir);
147+
final Path sourceDir = Paths.get("src/test/resources/org/apache/commons/io/dirs-2-file-size-2");
148+
PathUtils.copyDirectory(sourceDir, targetDir);
149+
assertTrue(Files.exists(targetDir.resolve("dirs-a-file-size-1")));
150+
151+
// relative dir -> absolute jar
152+
targetDir = archive.getPath("/");
153+
PathUtils.copyDirectory(sourceDir, targetDir);
154+
assertTrue(Files.exists(targetDir.resolve("dirs-a-file-size-1")));
155+
}
156+
} finally {
157+
PathUtils.deleteDirectory(tempDir);
158+
}
159+
}
160+
48161
@Test
49162
public void testCopyFile() throws IOException {
50163
final Path tempDir = Files.createTempDirectory(getClass().getCanonicalName());
1.08 KB
Binary file not shown.

0 commit comments

Comments
 (0)