feat(manifest): case-sensitive config-name globs with character classes (REA-621)#1400
Conversation
The --include-configs/--exclude-configs glob matchers in all three JVM facts producers (Gradle init script, sbt plugin, Maven extension) compiled with CASE_INSENSITIVE, contradicting the documented case-sensitive behavior and the capitalized examples. Make matching case-sensitive, and add `[...]` character classes (enumerations, ranges, `[!..]` negation) so a pattern can span the camelCase boundary — e.g. `*[Tt]est*` matches both testCompileClasspath and androidTestCompileClasspath. A malformed glob falls back to a literal match instead of throwing (which could otherwise fail the build). Help text updated to mention `[...]`; the Maven extension jar is rebuilt from source in CI.
Martin Torp (mtorp)
left a comment
There was a problem hiding this comment.
Approving — the three-language globToRegex port (Groovy/Scala/Java) is faithful and consistent, the escape set is complete, and malformed globs degrade safely to a literal match via the PatternSyntaxException → Pattern.quote fallback. Case-sensitive matching plus [...] classes matches the documented help.
One nit for the CHANGELOG (non-blocking): the Unreleased entry lists "socket manifest gradle, kotlin, sbt, and maven", but there is no socket manifest sbt subcommand — the sbt producer is invoked via socket manifest scala. Suggest scala (or scala (sbt)) so users can find the command by name.
…st-config-name-globs-make-matching-case-sensitive-as # Conflicts: # CHANGELOG.md # src/commands/manifest/cmd-manifest-gradle.mts # src/commands/manifest/cmd-manifest-gradle.test.mts # src/commands/manifest/cmd-manifest-kotlin.mts # src/commands/manifest/cmd-manifest-kotlin.test.mts
|
Good catch on the CHANGELOG — fixed in 28aae8c. Changed the sbt entry to Also merged latest |
Cut 1.1.136 covering the three JVM-manifest changes landing together (REA-519 config-transparency, REA-622 auto-manifest Gradle detection, REA-621 case-sensitive config globs + character classes); tightened the changelog entries to single-line bullets.
Problem
The
--include-configs/--exclude-configsglob matchers in all three JVM facts producers — the Gradle init script (Groovy), the sbt plugin (Scala), and the Maven extension (Java) — compiled their patterns withPattern.CASE_INSENSITIVE. That contradicts the CLI help ("case-sensitive") and the capitalized examples (*CompileClasspath,*RuntimeClasspath). Confirmed:--include-configs '*classpath'(lowercase) matchedcompileClasspathetc.Changes
CASE_INSENSITIVEin all threeglobToRegeximplementations, matching the documented behavior. (The old code even had a comment justifying the insensitivity on a false premise —*Classpathmatches camelCasecompileClasspathcase-sensitively just fine.)[...]now works: enumerations ([cC]), ranges ([a-z]), and[!..]negation. Under case-sensitive matching this lets a pattern span the camelCase boundary, e.g.*[Tt]est*matches bothtestCompileClasspathandandroidTestCompileClasspath— impossible with*/?alone.\/[/&) so exotic input (POSIX classes,&&intersection) degrades to a literal match, andPattern.compileis wrapped so a malformed glob (e.g. reversed range[z-a]) falls back to a literal match instead of throwing and failing the build.[...]; fixed a stale "case-insensitive" javadoc onSocketSupport.parsePatterns.Why a custom converter (not a library /
PathMatcher)Considered
java.nio.file.PathMatcherglob:and TS-side conversion (picomatch). Both were rejected:PathMatcheris case-sensitive on Unix but case-insensitive on Windows (JDKGlobs.toWindowsRegexPatternaddsCASE_INSENSITIVE), andPath.ofis Java 11+ — this code must run on Java 8→newest, Gradle 1→newest, sbt 0.13→newest, Maven 3.3→newest.java.util.regex.Pattern+ string ops are stable since Java 1.4 and behave identically across that whole matrix.[^/], trailing/?) and even mangle[Tt]into(?:\[Tt\]|[Tt])— not portable to Java's regex engine, and passing a regex would change the producers' glob contract and add escaping fragility.An independent review agent reached the same conclusion (custom converter), flagging the hardening/compile-guard and stale comment fixed here.
Testing
*classpath(lowercase) now matches nothing;*Classpathmatches all four classpath configs;*[Tt]est*matches only the test configs; malformed[z-a]exits 0 (literal fallback, no crash).pnpm check:tscclean; 12/12 manifest help tests pass.Follow-up (noted, not in this PR): a shared cross-language conformance fixture would guard against the three hand-written converters drifting.
Closes REA-621. Part of the same Unreleased version as PRs #1398 (REA-519) and #1399 (REA-622). Note: the gradle/kotlin
--include-configshelp line also conflicts trivially with #1398 (which removes stale AGP text from the same string) — resolve by keeping both edits.Note
Medium Risk
Matching semantics change which build configurations/scopes are resolved into facts/SBOMs; users with lowercase or case-loose patterns may see different dependency coverage until patterns are fixed.
Overview
--include-configs/--exclude-configson JVM manifest commands now match configuration/scope names case-sensitively, aligning runtime behavior with the documented CLI help. Patterns that relied on case folding (e.g.*classpathmatchingcompileClasspath) will stop matching unless updated.The Gradle init script, sbt facts plugin, and Maven extension
globToRegeximplementations are updated in parallel: they dropCASE_INSENSITIVE, add[...]glob classes (including[!…]negation), harden class bodies against regex tricks, and fall back to a literal match when compilation fails so bad patterns do not crash the build.CLI flag descriptions and help snapshots for
socket manifest gradle,kotlin,scala, andmavennow mention[...]wildcards; CHANGELOG records the behavior change.Reviewed by Cursor Bugbot for commit 33850b4. Configure here.