diff --git a/lib/src/main/java/io/cloudquery/glob/Glob.java b/lib/src/main/java/io/cloudquery/glob/Glob.java
new file mode 100644
index 0000000..14eb355
--- /dev/null
+++ b/lib/src/main/java/io/cloudquery/glob/Glob.java
@@ -0,0 +1,42 @@
+package io.cloudquery.glob;
+
+public class Glob {
+ public static final String GLOB = "*";
+
+ public static boolean match(String pattern, String subject) {
+ if (pattern.isEmpty()) {
+ return subject.equals(pattern);
+ }
+
+ if (pattern.equals(GLOB)) {
+ return true;
+ }
+
+ String[] parts = pattern.split("\\" + GLOB, -1);
+ if (parts.length == 1) {
+ return subject.equals(pattern);
+ }
+
+ boolean leadingGlob = pattern.startsWith(GLOB);
+ boolean trailingGlob = pattern.endsWith(GLOB);
+ int end = parts.length - 1;
+
+ for (int i = 0; i < end; i++) {
+ int idx = subject.indexOf(parts[i]);
+
+ if (i == 0) {
+ if (!leadingGlob && idx != 0) {
+ return false;
+ }
+ } else {
+ if (idx < 0) {
+ return false;
+ }
+ }
+
+ subject = subject.substring(idx + parts[i].length());
+ }
+
+ return trailingGlob || subject.endsWith(parts[end]);
+ }
+}
diff --git a/lib/src/main/java/io/cloudquery/glob/LICENSE b/lib/src/main/java/io/cloudquery/glob/LICENSE
new file mode 100644
index 0000000..a9f1724
--- /dev/null
+++ b/lib/src/main/java/io/cloudquery/glob/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Ryan Uber
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/lib/src/main/java/io/cloudquery/glob/README.md b/lib/src/main/java/io/cloudquery/glob/README.md
new file mode 100644
index 0000000..380f61d
--- /dev/null
+++ b/lib/src/main/java/io/cloudquery/glob/README.md
@@ -0,0 +1,3 @@
+# Glob Matching Library
+
+This glob-matching library was copied from [ryanuber/go-glob](https://github.com/ryanuber/go-glob) and therefore falls under its [license](LICENSE).
diff --git a/lib/src/main/java/io/cloudquery/helper/GlobMatcher.java b/lib/src/main/java/io/cloudquery/helper/GlobMatcher.java
deleted file mode 100644
index 36ecad4..0000000
--- a/lib/src/main/java/io/cloudquery/helper/GlobMatcher.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package io.cloudquery.helper;
-
-import lombok.Getter;
-
-import java.nio.file.FileSystems;
-import java.nio.file.Path;
-import java.nio.file.PathMatcher;
-
-public class GlobMatcher {
- private final PathMatcher pathMatcher;
-
- @Getter
- private final String stringMatch;
-
- public GlobMatcher(String stringMatch) {
- this.stringMatch = stringMatch;
- this.pathMatcher = FileSystems.getDefault().getPathMatcher("glob:" + stringMatch);
- }
-
- public boolean matches(String name) {
- return pathMatcher.matches(Path.of(name));
- }
-}
diff --git a/lib/src/main/java/io/cloudquery/schema/Table.java b/lib/src/main/java/io/cloudquery/schema/Table.java
index d2c6fac..df1b83a 100644
--- a/lib/src/main/java/io/cloudquery/schema/Table.java
+++ b/lib/src/main/java/io/cloudquery/schema/Table.java
@@ -1,6 +1,6 @@
package io.cloudquery.schema;
-import io.cloudquery.helper.GlobMatcher;
+import io.cloudquery.glob.Glob;
import lombok.Builder;
import lombok.Getter;
@@ -28,38 +28,35 @@ public static List
flattenTables(List tables) {
}
public static List filterDFS(List tables, List includeConfiguration, List skipConfiguration, boolean skipDependentTables) throws SchemaException {
- List includes = includeConfiguration.stream().map(GlobMatcher::new).toList();
- List excludes = skipConfiguration.stream().map(GlobMatcher::new).toList();
-
List flattenedTables = flattenTables(tables);
- for (GlobMatcher includeMatcher : includes) {
+ for (String includePattern : includeConfiguration) {
boolean includeMatch = false;
for (Table table : flattenedTables) {
- if (includeMatcher.matches(table.getName())) {
+ if (Glob.match(includePattern, table.getName())) {
includeMatch = true;
break;
}
}
if (!includeMatch) {
- throw new SchemaException("table configuration includes a pattern \"" + includeMatcher.getStringMatch() + "\" with no matches");
+ throw new SchemaException("table configuration includes a pattern \"" + includePattern + "\" with no matches");
}
}
- for (GlobMatcher excludeMatcher : excludes) {
+ for (String excludePattern : skipConfiguration) {
boolean excludeMatch = false;
for (Table table : flattenedTables) {
- if (excludeMatcher.matches(table.getName())) {
+ if (Glob.match(excludePattern, table.getName())) {
excludeMatch = true;
break;
}
}
if (!excludeMatch) {
- throw new SchemaException("skip configuration includes a pattern \"" + excludeMatcher.getStringMatch() + "\" with no matches");
+ throw new SchemaException("skip configuration includes a pattern \"" + excludePattern + "\" with no matches");
}
}
Predicate include = table -> {
- for (GlobMatcher matcher : includes) {
- if (matcher.matches(table.getName())) {
+ for (String includePattern : includeConfiguration) {
+ if (Glob.match(includePattern, table.getName())) {
return true;
}
}
@@ -67,8 +64,8 @@ public static List filterDFS(List tables, List includeConf
};
Predicate exclude = table -> {
- for (GlobMatcher matcher : excludes) {
- if (matcher.matches(table.getName())) {
+ for (String excludePattern : skipConfiguration) {
+ if (Glob.match(excludePattern, table.getName())) {
return true;
}
}
diff --git a/lib/src/test/java/io/cloudquery/glob/GlobTest.java b/lib/src/test/java/io/cloudquery/glob/GlobTest.java
new file mode 100644
index 0000000..51e6847
--- /dev/null
+++ b/lib/src/test/java/io/cloudquery/glob/GlobTest.java
@@ -0,0 +1,100 @@
+package io.cloudquery.glob;
+
+import org.junit.Test;
+
+import java.util.List;
+
+import static io.cloudquery.glob.Glob.GLOB;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class GlobTest {
+ @Test
+ public void testEmptyPattern() {
+ assertGlobMatch("", "");
+ assertNotGlobMatch("", "test");
+ }
+
+ @Test
+ public void testEmptySubject() {
+ for (String s : List.of("",
+ "*",
+ "**",
+ "***",
+ "****************",
+ GLOB.repeat(1000000)
+ )) {
+ assertGlobMatch(s, "");
+ }
+
+ for (String pattern : List.of(
+ // No globs/non-glob characters
+ "test",
+ "*test*",
+
+ // Trailing characters
+ "*x",
+ "*****************x",
+ GLOB.repeat(1000000) + "x",
+
+ // Leading characters
+ "x*",
+ "x*****************",
+ "x" + GLOB.repeat(1000000),
+
+ // Mixed leading/trailing characters
+ "x*x",
+ "x****************x",
+ "x" + GLOB.repeat(1000000) + "x"
+ )) {
+ assertNotGlobMatch(pattern, "");
+ }
+ }
+
+ @Test
+ public void testPatternWithoutGlobs() {
+ assertGlobMatch("test", "test");
+ }
+
+ @Test
+ public void testGlobs() {
+ for (String pattern : List.of(
+ "*test", // Leading glob
+ "this*", // Trailing glob
+ "this*test", // Middle glob
+ "*is *", // String in between two globs
+ "*is*a*", // Lots of globs
+ "**test**", // Double glob characters
+ "**is**a***test*", // Varying number of globs
+ "* *", // White space between globs
+ "*", // Lone glob
+ "**********", // Nothing but globs
+ "*Ѿ*", // Unicode with globs
+ "*is a ϗѾ *" // Mixed ASCII/unicode
+ )) {
+ assertGlobMatch(pattern, "this is a ϗѾ test");
+ }
+
+ for(String pattern:List.of(
+ "test*", // Implicit substring match
+ "*is", // Partial match
+ "*no*", // Globs without a match between them
+ " ", // Plain white space
+ "* ", // Trailing white space
+ " *", // Leading white space
+ "*ʤ*", // Non-matching unicode
+ "this*this is a test" // Repeated prefix
+ )) {
+ assertNotGlobMatch(pattern, "this is a test");
+ }
+ }
+
+ public void assertGlobMatch(String pattern, String subject) {
+ assertTrue(String.format("\"%s\" should match \"%s\"", pattern, subject), Glob.match(pattern, subject));
+ }
+
+ public void assertNotGlobMatch(String pattern, String subject) {
+ assertFalse(String.format("\"%s\" should not match \"%s\"", pattern, subject), Glob.match(pattern, subject));
+ }
+
+}
\ No newline at end of file
diff --git a/lib/src/test/java/io/cloudquery/helper/GlobMatcherTest.java b/lib/src/test/java/io/cloudquery/helper/GlobMatcherTest.java
deleted file mode 100644
index e62c622..0000000
--- a/lib/src/test/java/io/cloudquery/helper/GlobMatcherTest.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package io.cloudquery.helper;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class GlobMatcherTest {
- @Test
- public void shouldMatchWildcard() {
- GlobMatcher globMatcher = new GlobMatcher("*");
-
- assertTrue(globMatcher.matches("aws_ec2_vpc"));
- assertTrue(globMatcher.matches("aws_ec2_eip"));
- assertTrue(globMatcher.matches("aws_ec2_instance"));
- }
-
- @Test
- public void shouldMatchWildcardSuffix() {
- GlobMatcher globMatcher = new GlobMatcher("aws_*");
-
- assertTrue(globMatcher.matches("aws_ec2_vpc"));
- assertTrue(globMatcher.matches("aws_ec2_eip"));
- assertTrue(globMatcher.matches("aws_ec2_instance"));
-
- assertFalse(globMatcher.matches("gcp_project"));
- assertFalse(globMatcher.matches("other_aws_resource"));
- }
-
- @Test
- public void shouldMatchWildcardPrefixAndSuffix() {
- GlobMatcher globMatcher = new GlobMatcher("*ec2*");
-
- assertTrue(globMatcher.matches("aws_ec2_vpc"));
- assertTrue(globMatcher.matches("aws_ec2_eip"));
- assertTrue(globMatcher.matches("aws_ec2_instance"));
-
- assertFalse(globMatcher.matches("gcp_project"));
- assertFalse(globMatcher.matches("other_aws_resource"));
- }
-}
\ No newline at end of file