From c97eea7446bd8f40d567931289ba1f93040a238a Mon Sep 17 00:00:00 2001 From: The Coden <75643469+thecoden@users.noreply.github.com> Date: Mon, 7 Dec 2020 15:25:55 -0800 Subject: [PATCH] Fixes #2 : Overlapping Paths --- .../github/shyiko/klob/internal/package.kt | 20 ++++++++----- .../klob/internal/GlobFileFilterTest.kt | 29 +++++++++++++++++++ test-files/a/b/a-b.txt | 0 test-files/a/b/c/a-b-c.txt | 0 test-files/a/b1/a-b1.txt | 0 5 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 test-files/a/b/a-b.txt create mode 100644 test-files/a/b/c/a-b-c.txt create mode 100644 test-files/a/b1/a-b1.txt diff --git a/src/main/java/com/github/shyiko/klob/internal/package.kt b/src/main/java/com/github/shyiko/klob/internal/package.kt index bc48237..760595c 100644 --- a/src/main/java/com/github/shyiko/klob/internal/package.kt +++ b/src/main/java/com/github/shyiko/klob/internal/package.kt @@ -44,12 +44,14 @@ internal fun visit(dir: File, filter: FileFilter, directoryModeFilter: FileFilte internal fun visit(path: Path, option: EnumSet, patterns: List): Sequence { val includeChildren = !option.contains(IterationOption.SKIP_CHILDREN) val directoryMode = option.contains(IterationOption.DIRECTORY) + if (includeChildren && directoryMode) { throw UnsupportedOperationException( "Glob.IterationOption.DIRECTORY must be used together with Glob.IterationOption.SKIP_CHILDREN " + "(please create a ticket at https://github.com/shyiko/klob/issue if it doesn't fit your needs)" ) } + val baseDir = path.toString() val filter = GlobFileFilter(baseDir, *patterns.toTypedArray(), @@ -58,6 +60,7 @@ internal fun visit(path: Path, option: EnumSet, patterns: List< if (option.contains(IterationOption.SKIP_HIDDEN)) it.and(HiddenFileFilter(reverse = true)) else it } + val directoryModeFilter = when { option.contains(IterationOption.DIRECTORY) -> GlobFileFilter(baseDir, @@ -67,14 +70,17 @@ internal fun visit(path: Path, option: EnumSet, patterns: List< ) else -> null } + return patterns + .asSequence() .map { Glob.prefix(slash(it)) } .distinct() - .map { (if (it.startsWith("/")) File(fromSlash(it)) else File(baseDir, fromSlash(it))).canonicalPath } - // remove overlapping paths (e.g. /a & /a/b -> /a) - .sorted() - .fold(ArrayList(), { r, v -> if (r.isEmpty() || !v.startsWith(r.last())) { r.add(v) }; r }) - .map { visit(File(it), filter, directoryModeFilter) } - .asSequence() - .flatten() + .map { + val file = if (it.startsWith("/")) + File(fromSlash(it)) + else + File(baseDir, fromSlash(it)) + + visit(file, filter, directoryModeFilter) + }.flatten() } diff --git a/src/test/java/com/github/shyiko/klob/internal/GlobFileFilterTest.kt b/src/test/java/com/github/shyiko/klob/internal/GlobFileFilterTest.kt index f7fce0d..dedbdaa 100644 --- a/src/test/java/com/github/shyiko/klob/internal/GlobFileFilterTest.kt +++ b/src/test/java/com/github/shyiko/klob/internal/GlobFileFilterTest.kt @@ -1,9 +1,11 @@ package com.github.shyiko.klob.internal +import com.github.shyiko.klob.Glob import org.testng.Assert.assertFalse import org.testng.Assert.assertTrue import org.testng.annotations.Test import java.io.File +import java.nio.file.Path class GlobFileFilterTest { @@ -27,4 +29,31 @@ class GlobFileFilterTest { .accept(File("/C:/ktlint/src/test/kotlin/com/github/shyiko/ktlint/LinterTest.kt"))) } + /** + * Test paths for which the directories are a substring of another, using the [GlobFileFilter] class directly. + */ + @Test + fun testSubPathFold_regression() { + val filter = GlobFileFilter(dir, "$dir/a/b/a-b.txt", "$dir/a/b1/a-b1.txt") + + assertTrue(filter.accept(File("$dir/a/b/a-b.txt"))) + assertTrue(filter.accept(File("$dir/a/b1/a-b1.txt"))) + } + + /** + * Test paths for which the directories are a substring of another, using the the [Glob] interface the way a user normally would. + */ + @Test + fun testSubPathFold_regressionFromFiles() { + val basePath = File("test-files").toPath().toAbsolutePath() + val files = Glob.from("a/b/a-b.txt", "a/b1/a-b1.txt", "a/b/c/a-b-c.txt").iterate(basePath, Glob.IterationOption.SKIP_HIDDEN).asSequence().toList().map { + it.toString().removePrefix(basePath.toString()) + }.toHashSet() + + assertTrue(files.contains("/a/b/a-b.txt"), "/a/b/a-b.txt not matched.\n$files") + assertTrue(files.contains("/a/b1/a-b1.txt"), "/a/b1/a-b1.txt not matched\n$files") + assertTrue(files.contains("/a/b/c/a-b-c.txt"), "/a/b/c/a-b-c.txt not matched\n$files") + assertTrue(3 == files.size, "Only 3 files should match instead of ${files.size}\n${files}") + } + } diff --git a/test-files/a/b/a-b.txt b/test-files/a/b/a-b.txt new file mode 100644 index 0000000..e69de29 diff --git a/test-files/a/b/c/a-b-c.txt b/test-files/a/b/c/a-b-c.txt new file mode 100644 index 0000000..e69de29 diff --git a/test-files/a/b1/a-b1.txt b/test-files/a/b1/a-b1.txt new file mode 100644 index 0000000..e69de29