Skip to content

Commit a9fd211

Browse files
jean-philippe-martinchingor13
authored andcommitted
NIO: walkFiles consistently relative or absolute (#3773)
* walkFiles consistently relative or absolute The expected behavior from Files.walkFileTree is that if the starting path is absolute, then all the visited paths are absolute. If the starting path is relative, then all the visited paths are relative. This PR adds a test for this behavior, and shows that our current code fails for an absolute path: it returns a mix of relative and absolute paths. This PR also adds a code change to fix the problem, so the actual behavior matches what is expected. This should fix issue #3772 * address issues found by linter * rename PostTraversalWalker * apply reviewer feedback
1 parent ab77568 commit a9fd211

File tree

2 files changed

+84
-3
lines changed

2 files changed

+84
-3
lines changed

java-storage-nio/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemProvider.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,15 +102,19 @@ private static class LazyPathIterator extends AbstractIterator<Path> {
102102
private final Filter<? super Path> filter;
103103
private final CloudStorageFileSystem fileSystem;
104104
private final String prefix;
105+
// whether to make the paths absolute before returning them.
106+
private final boolean absolutePaths;
105107

106108
LazyPathIterator(CloudStorageFileSystem fileSystem,
107109
String prefix,
108110
Iterator<Blob> blobIterator,
109-
Filter<? super Path> filter) {
111+
Filter<? super Path> filter,
112+
boolean absolutePaths) {
110113
this.prefix = prefix;
111114
this.blobIterator = blobIterator;
112115
this.filter = filter;
113116
this.fileSystem = fileSystem;
117+
this.absolutePaths = absolutePaths;
114118
}
115119

116120
@Override
@@ -123,6 +127,9 @@ protected Path computeNext() {
123127
continue;
124128
}
125129
if (filter.accept(path)) {
130+
if (absolutePaths) {
131+
return path.toAbsolutePath();
132+
}
126133
return path;
127134
}
128135
} catch (IOException ex) {
@@ -769,7 +776,7 @@ public void createDirectory(Path dir, FileAttribute<?>... attrs) {
769776
}
770777

771778
@Override
772-
public DirectoryStream<Path> newDirectoryStream(Path dir, final Filter<? super Path> filter) {
779+
public DirectoryStream<Path> newDirectoryStream(final Path dir, final Filter<? super Path> filter) {
773780
final CloudStoragePath cloudPath = CloudStorageUtil.checkPath(dir);
774781
checkNotNull(filter);
775782
initStorage();
@@ -793,7 +800,7 @@ public DirectoryStream<Path> newDirectoryStream(Path dir, final Filter<? super P
793800
return new DirectoryStream<Path>() {
794801
@Override
795802
public Iterator<Path> iterator() {
796-
return new LazyPathIterator(cloudPath.getFileSystem(), prefix, blobIterator, filter);
803+
return new LazyPathIterator(cloudPath.getFileSystem(), prefix, blobIterator, filter, dir.isAbsolute());
797804
}
798805

799806
@Override

java-storage-nio/google-cloud-nio/src/test/java/com/google/cloud/storage/contrib/nio/it/ITGcsNio.java

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.google.cloud.storage.contrib.nio.it;
1818

1919
import static com.google.common.truth.Truth.assertThat;
20+
import static com.google.common.truth.Truth.assertWithMessage;
2021
import static java.nio.charset.StandardCharsets.UTF_8;
2122

2223
import com.google.api.client.http.HttpResponseException;
@@ -538,6 +539,53 @@ public void testListFiles() throws IOException {
538539
}
539540
}
540541

542+
@Test
543+
public void testRelativityOfResolve() throws IOException {
544+
try (FileSystem fs = getTestBucket()) {
545+
Path abs1 = fs.getPath("/dir");
546+
Path abs2 = abs1.resolve("subdir/");
547+
Path rel1 = fs.getPath("dir");
548+
Path rel2 = rel1.resolve("subdir/");
549+
// children of absolute paths are absolute,
550+
// children of relative paths are relative.
551+
assertThat(abs1.isAbsolute()).isTrue();
552+
assertThat(abs2.isAbsolute()).isTrue();
553+
assertThat(rel1.isAbsolute()).isFalse();
554+
assertThat(rel2.isAbsolute()).isFalse();
555+
}
556+
}
557+
558+
@Test
559+
public void testWalkFiles() throws IOException {
560+
try (FileSystem fs = getTestBucket()) {
561+
List<Path> goodPaths = new ArrayList<>();
562+
List<Path> paths = new ArrayList<>();
563+
goodPaths.add(fs.getPath("dir/angel"));
564+
goodPaths.add(fs.getPath("dir/alone"));
565+
paths.add(fs.getPath("dir/dir2/another_angel"));
566+
paths.add(fs.getPath("atroot"));
567+
paths.addAll(goodPaths);
568+
for (Path path : paths) {
569+
fillFile(storage, BUCKET, path.toString(), SML_SIZE);
570+
}
571+
// Given a relative path as starting point, walkFileTree must return only relative paths.
572+
List<Path> relativePaths = PostTraversalWalker.walkFileTree(fs.getPath("dir/"));
573+
for (Path p : relativePaths) {
574+
assertWithMessage("Should have been relative: " + p.toString()).that(p.isAbsolute()).isFalse();
575+
}
576+
// The 5 paths are:
577+
// dir/, dir/angel, dir/alone, dir/dir2/, dir/dir2/another_angel.
578+
assertThat(relativePaths.size()).isEqualTo(5);
579+
580+
// Given an absolute path as starting point, walkFileTree must return only relative paths.
581+
List<Path> absolutePaths = PostTraversalWalker.walkFileTree(fs.getPath("/dir/"));
582+
for (Path p : absolutePaths) {
583+
assertWithMessage("Should have been absolute: " + p.toString()).that(p.isAbsolute()).isTrue();
584+
}
585+
assertThat(absolutePaths.size()).isEqualTo(5);
586+
}
587+
}
588+
541589

542590
@Test
543591
public void testDeleteRecursive() throws IOException {
@@ -620,6 +668,32 @@ private String randomSuffix() {
620668
return "-" + rnd.nextInt(99999);
621669
}
622670

671+
private static class PostTraversalWalker extends SimpleFileVisitor<Path> {
672+
private final List<Path> paths = new ArrayList<>();
673+
674+
// Traverse the tree, return the list of files and folders.
675+
static public ImmutableList<Path> walkFileTree(Path start) throws IOException {
676+
PostTraversalWalker walker = new PostTraversalWalker();
677+
Files.walkFileTree(start, walker);
678+
return walker.getPaths();
679+
}
680+
681+
@Override
682+
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
683+
paths.add(file);
684+
return FileVisitResult.CONTINUE;
685+
}
686+
687+
@Override
688+
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
689+
paths.add(dir);
690+
return FileVisitResult.CONTINUE;
691+
}
692+
693+
public ImmutableList<Path> getPaths() {
694+
return ImmutableList.copyOf(paths);
695+
}
696+
}
623697

624698
private CloudStorageFileSystem getTestBucket() throws IOException {
625699
// in typical usage we use the single-argument version of forBucket

0 commit comments

Comments
 (0)