@@ -35,9 +35,12 @@ ROOT::CmdLine::GetMatchingPathsInFile(std::string_view fileName, std::string_vie
3535 }
3636
3737 const auto patternSplits = pattern.empty () ? std::vector<std::string>{} : ROOT::Split (pattern, " /" );
38+ std::vector<bool > patternWasMatchedAtLeastOnce (patternSplits.size ());
3839
39- // Match all objects at all nesting levels down to the deepest nesting level of `pattern` (or all nesting levels
40- // if we have the "recursive listing" flag). The nodes are visited breadth-first.
40+ // / Match all objects at all nesting levels down to the deepest nesting level of `pattern` (or all nesting levels
41+ // / if we have the "recursive listing" flag). The nodes are visited breadth-first.
42+
43+ // Initialize the nodeTree with the root node and mark it as the first node to visit.
4144 {
4245 ROOT::CmdLine::RootObjNode rootNode = {};
4346 rootNode.fName = std::string (fileName);
@@ -57,7 +60,7 @@ ROOT::CmdLine::GetMatchingPathsInFile(std::string_view fileName, std::string_vie
5760 ROOT::CmdLine::RootObjNode *cur = &nodeTree.fNodes [curIdx];
5861 assert (cur->fDir );
5962
60- // Sort the keys by name
63+ // Gather all keys under this directory and sort them by name.
6164 std::vector<TKey *> keys;
6265 keys.reserve (cur->fDir ->GetListOfKeys ()->GetEntries ());
6366 for (TKey *key : ROOT::Detail::TRangeStaticCast<TKey>(cur->fDir ->GetListOfKeys ()))
@@ -68,10 +71,19 @@ ROOT::CmdLine::GetMatchingPathsInFile(std::string_view fileName, std::string_vie
6871
6972 namesFound.clear ();
7073
74+ // Iterate the keys and find matches
7175 for (TKey *key : keys) {
72- // Don't recurse lower than requested by `pattern` unless we explicitly have the `recursive listing` flag.
73- if (cur->fNesting < patternSplits.size () && !MatchesGlob (key->GetName (), patternSplits[cur->fNesting ]))
74- continue ;
76+ // NOTE: cur->fNesting can only be >= patternSplits.size() if we have `isRecursive == true` (see the code near
77+ // the end of the outer do/while loop).
78+ // In that case we don't care about matching patterns anymore because we are already beyond the nesting level
79+ // where pattern filtering applies.
80+ // In all other cases, we check if the key name matches the pattern and skip it if it doesn't.
81+ if (cur->fNesting < patternSplits.size ()) {
82+ if (MatchesGlob (key->GetName (), patternSplits[cur->fNesting ]))
83+ patternWasMatchedAtLeastOnce[cur->fNesting ] = true ;
84+ else
85+ continue ;
86+ }
7587
7688 if (namesFound.count (key->GetName ()) > 0 ) {
7789 std::cerr << " WARNING: Several versions of '" << key->GetName () << " ' are present in '" << fileName
@@ -94,7 +106,8 @@ ROOT::CmdLine::GetMatchingPathsInFile(std::string_view fileName, std::string_vie
94106 newChild.fDir = cur->fDir ->GetDirectory (key->GetName ());
95107 }
96108
97- // Only recurse into subdirectories that are up to the deepest level we ask for through `pattern`.
109+ // Only recurse into subdirectories that are up to the deepest level we ask for through `pattern` (except in
110+ // case of recursive listing).
98111 if (cur->fNesting < patternSplits.size () || isRecursive) {
99112 for (auto childIdx = cur->fFirstChild ; childIdx < cur->fFirstChild + cur->fNChildren ; ++childIdx) {
100113 auto &child = nodeTree.fNodes [childIdx];
@@ -112,6 +125,19 @@ ROOT::CmdLine::GetMatchingPathsInFile(std::string_view fileName, std::string_vie
112125 }
113126 } while (!nodesToVisit.empty ());
114127
128+ if (!(flags & kIgnoreFailedMatches )) {
129+ for (auto i = 0u ; i < patternSplits.size (); ++i) {
130+ // We don't append errors for '*' because its semantics imply "0 or more matches", so 0 matches is a valid
131+ // case. For any other pattern we expect at least 1 match.
132+ if (!patternWasMatchedAtLeastOnce[i] && !patternSplits[i].empty () && patternSplits[i] != " *" ) {
133+ std::string err = " '" + std::string (fileName) + " :" +
134+ ROOT::Join (" /" , std::span<const std::string>{patternSplits.data (), i + 1 }) +
135+ " ' matches no objects." ;
136+ source.fErrors .push_back (err);
137+ }
138+ }
139+ }
140+
115141 return source;
116142}
117143
0 commit comments