Skip to content

fix: a glob's **/ stands for whole directories, not part of a name - #878

Open
NopeCharon wants to merge 1 commit into
mcpp-community:mainfrom
NopeCharon:fix/glob-double-star-whole-directories
Open

NopeCharon wants to merge 1 commit into
mcpp-community:mainfrom
NopeCharon:fix/glob-double-star-whole-directories

Conversation

@NopeCharon

Copy link
Copy Markdown
Contributor

Summary

relative_path_matches_glob consumed **/ and then retried the rest of the pattern at every character of the path, so what followed **/ could begin in the middle of a name. **/main.cpp selected src/domain.cpp, tests/**/test_*.cpp selected tests/mytest_a.cpp, and **/modules/dnn/**/*.avx2.cpp selected a/submodules/dnn/l.avx2.cpp. The matcher serves every glob with the sources grammar (sources, [build] flags, [scan_overrides], test discover, [pack] include/exclude, include-dir globs, rerun_if_changed_glob), so a [build] flags entry for **/main.cpp also compiled src/app/domain.cpp with its defines.

After **/, the rest of the pattern now resumes only where it stands (zero directories) or just after a /. A ** not followed by / (src/**, src/**.cpp) still crosses segments and names. The literal-prefix and tail pre-filters of expand_glob select a superset of the new matches and are unchanged. docs/04-mcpp-toml.md states the rule in both languages.

Closes #877.

Criteria

  • Glob.ADoubleStarSlashStandsForWholeDirectories (tests/unit/test_modgraph.cpp) checks the matcher directly: **/main.cpp against main.cpp, src/main.cpp, src/a/b/main.cpp and three domain.cpp paths; tests/**/test_*.cpp; the **/modules/dnn/**/*.avx2.cpp form from test_manifest; and src/**, src/**.cpp, **, which keep their meaning. Scanner.ADoubleStarSlashTailMatchesAtTheRoot gains a sub/domain.cpp that the **/main.cpp walk must not return. On aarch64 Linux with the released 2026.10.31.3 binary, mcpp test test_modgraph fails both before the change (the walk returns 3 files; six domain/mytest/submodules cases match) and passes after it.
  • The full unit suite (mcpp test, 160 passed, 0 failed) passes on aarch64 Linux. Other hosts are left to CI.
  • End to end, with the project in fix: a glob's **/ matches part of a name, so **/main.cpp selects src/domain.cpp #877 (flags = [ { glob = "**/main.cpp", defines = ["ENTRY_ONLY"] } ], src/main.cpp, src/app/domain.cpp that #errors under ENTRY_ONLY, and src/main.cpp that #errors without it): the released binary fails on obj/domain.o. The binary built from this branch builds and runs it, so the define reaches src/main.cpp and only it.

Intersections

New rule or feature Invariant it crosses Test at the crossing
**/ resumes only at a segment start **/ also matches no directory: **/main.cpp matches a root main.cpp Scanner.ADoubleStarSlashTailMatchesAtTheRoot, the main.cpp case of the new test
The same expand_glob pre-filters by literal prefix and literal tail before matching Scanner.ExpandGlobStartsAtLiteralPrefix*, Scanner.ADoubleStarSlashTailMatchesAtTheRoot
The same A trailing ** and a ** inside a segment cross segments The src/**, src/**.cpp and ** cases of the new test, Scanner.PerGlobFlagsAttachToMatchedUnits (third_party/**)
The same Brace alternation is desugared before matching Scanner.ExpandGlobBraceAlternation, Scanner.PerGlobFlagsMatchBraceAlternation

Compatibility

A glob with **/ no longer selects a file or directory whose name only ends with the text after it. A project that relied on that, such as **/main.cpp meant to pick domain.cpp, now selects fewer files; a [scan_overrides] glob that only matched that way becomes an unmatched glob and is reported. Every glob without **/, and every path that starts a segment where the pattern resumes, matches as before. No cache key or output format changes.

Checks before merging

  • bash .github/tools/check_docs_style.sh, check_docs_structure.sh and check_version_pins.sh pass.
  • python3 .github/tools/check_workflow_assertions.py passes (a step asserts what its name says).
  • No commit on the branch carries an attribution trailer:
    git log origin/main..HEAD -i --grep='Co-Authored-By' prints nothing.
  • The squash merge is given an explicit subject and body, so GitHub does not
    compose one from the branch's commits. Suggested subject: fix: a glob's **/ stands for whole directories, not part of a name.

relative_path_matches_glob consumed `**/` and then retried the rest of
the pattern at every character of the path, so what followed `**/`
could begin in the middle of a file or directory name. `**/main.cpp`
selected `src/domain.cpp`, `tests/**/test_*.cpp` selected
`tests/mytest_a.cpp`, and `**/modules/dnn/**/*.avx2.cpp` selected
`a/submodules/dnn/l.avx2.cpp`.

The matcher serves every glob with the `sources` grammar: `sources`,
`[build] flags`, `[scan_overrides]`, test `discover`, `[pack]
include`/`exclude`, include-dir globs and `rerun_if_changed_glob`. A
`[build] flags` entry for `**/main.cpp` therefore also compiled
`src/app/domain.cpp` with its defines.

After `**/` the rest of the pattern now resumes only where it stands
(zero directories) or just after a `/`. A `**` not followed by `/`
(`src/**`, `src/**.cpp`) keeps crossing segments and names as before.
The literal-prefix and tail pre-filters of expand_glob are supersets of
the new match and are unchanged.

Tests: Glob.ADoubleStarSlashStandsForWholeDirectories checks the matcher
directly, and Scanner.ADoubleStarSlashTailMatchesAtTheRoot gains a
`sub/domain.cpp` that the `**/main.cpp` walk must not return. docs/04
states the rule in both languages.

Closes mcpp-community#877

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: a glob's **/ matches part of a name, so **/main.cpp selects src/domain.cpp

1 participant

⌂ Proxy