20static bool MatchesGlob(std::string_view haystack, std::string_view pattern)
31 const char *fileMode =
"READ_WITHOUT_GLOBALREGISTRATION";
32 const std::string fileNameStr { fileName };
36 source.
fErrors.push_back(
"File '" + fileNameStr +
"' does not exist or is not writable.");
39 fileMode =
"UPDATE_WITHOUT_GLOBALREGISTRATION";
41 nodeTree.
fFile = std::unique_ptr<TFile>(
TFile::Open(fileNameStr.c_str(), fileMode));
42 if (!nodeTree.fFile || nodeTree.fFile->IsZombie()) {
43 source.
fErrors.push_back(
"Failed to open file '" + fileNameStr +
"'");
47 const auto patternSplits = pattern.empty() ? std::vector<std::string>{} :
ROOT::Split(pattern,
"/");
48 std::vector<bool> patternWasMatchedAtLeastOnce(patternSplits.size());
56 rootNode.
fName = std::string(fileName);
57 rootNode.
fClassName = nodeTree.fFile->Class()->GetName();
58 rootNode.
fDir = nodeTree.fFile.get();
59 nodeTree.fNodes.emplace_back(std::move(rootNode));
61 std::deque<NodeIdx_t> nodesToVisit{0};
66 nodesToVisit.pop_front();
71 std::vector<TKey *> keys;
76 std::sort(keys.begin(), keys.end(), [](
const TKey *
a,
const TKey *
b) {
77 int cmp = strcmp(a->GetName(), b->GetName());
79 return (cmp != 0) ? (cmp < 0) : (a->GetCycle() > b->GetCycle());
83 for (
TKey *key : keys) {
89 if (cur->
fNesting < patternSplits.size()) {
90 const auto &patternSplit = patternSplits[cur->
fNesting];
91 const bool hasCycle = patternSplit.rfind(
';') != std::string_view::npos;
92 const auto nameCycle =
93 std::string(key->GetName()) + (hasCycle ?
';' + std::to_string(key->GetCycle()) :
"");
95 patternWasMatchedAtLeastOnce[cur->
fNesting] =
true;
100 auto &newChild = nodeTree.fNodes.emplace_back(
NodeFromKey(*key));
102 cur = &nodeTree.fNodes[curIdx];
104 newChild.fParent = curIdx;
110 if (cl && cl->InheritsFrom(
"TDirectory"))
116 if (cur->
fNesting < patternSplits.size() || isRecursive) {
118 auto &child = nodeTree.fNodes[childIdx];
120 nodesToVisit.push_back(childIdx);
121 else if (cur->
fNesting < patternSplits.size())
122 nodeTree.fLeafList.push_back(childIdx);
125 if (cur->
fNesting == patternSplits.size()) {
127 nodeTree.fDirList.push_back(curIdx);
129 nodeTree.fLeafList.push_back(curIdx);
131 }
while (!nodesToVisit.empty());
134 for (
auto i = 0u; i < patternSplits.size(); ++i) {
137 if (!patternWasMatchedAtLeastOnce[i] && !patternSplits[i].empty() && patternSplits[i] !=
"*") {
138 std::string
err =
"'" + std::string(fileName) +
":" +
139 ROOT::Join(
"/", std::span<const std::string>{patternSplits.data(), i + 1}) +
140 "' matches no objects.";
152 auto prefixIdx = sourceRaw.find(
"://");
153 std::string_view::size_type separatorIdx = 0;
154 if (prefixIdx != std::string_view::npos) {
155 bool prefixFound =
false;
157 static const char *
const specialPrefixes[] = {
"http",
"https",
"root",
"gs",
"s3"};
158 auto prefix = sourceRaw.substr(0, prefixIdx);
159 for (std::string_view knownPrefix : specialPrefixes) {
160 if (prefix == knownPrefix) {
166 return R__FAIL(
"unknown file protocol");
168 separatorIdx = sourceRaw.substr(prefixIdx + 3).find_first_of(
':');
169 if (separatorIdx != std::string_view::npos)
170 separatorIdx += prefixIdx + 3;
172 separatorIdx = sourceRaw.find_first_of(
':');
175 if (separatorIdx != std::string_view::npos) {
176 return {{sourceRaw.substr(0, separatorIdx), sourceRaw.substr(separatorIdx + 1)}};
178 return {{sourceRaw, std::string_view{}}};
187 source.
fErrors.push_back(res.GetError()->GetReport());
191 auto [fileName, tokens] = res.Unwrap();
198std::vector<ROOT::CmdLine::RootSource>
201 std::vector<ROOT::CmdLine::RootSource> sources;
202 sources.reserve(sourcesRaw.size());
204 for (
const auto &srcRaw : sourcesRaw) {
213 if (
tree.fNodes.empty())
217 std::set<NodeIdx_t> fChildren;
219 std::vector<RevNode> revNodes;
220 revNodes.resize(
tree.fNodes.size());
223 for (
int i = (
int)
tree.fNodes.size() - 1; i >= 0; --i) {
227 while (childIdx != parentIdx) {
228 auto &revNodeParent = revNodes[parentIdx];
229 revNodeParent.fChildren.insert(childIdx);
231 childIdx = parentIdx;
232 parentIdx =
node->fParent;
238 std::vector<std::pair<std::uint32_t, NodeIdx_t>> nodesToVisit = {{0, 0}};
239 while (!nodesToVisit.empty()) {
240 const auto [nesting, nodeIdx] = nodesToVisit.back();
241 nodesToVisit.pop_back();
242 const auto &cur = revNodes[nodeIdx];
243 const auto &
node =
tree.fNodes[nodeIdx];
244 for (
auto i = 0u; i < 2 * nesting; ++i)
246 out <<
node.fName <<
";" <<
node.fCycle <<
" : " <<
node.fClassName <<
"\n";
248 for (
auto it = cur.fChildren.rbegin(); it != cur.fChildren.rend(); ++it) {
249 nodesToVisit.push_back({nesting + 1, *it});
258 std::string fullPath =
node->fName;
259 while (
node->fParent != 0) {
261 fullPath =
node->fName + (fullPath.empty() ?
"" :
"/") + fullPath;
264 fullPath =
tree.fNodes[0].fName +
":" + fullPath;
#define R__FAIL(msg)
Short-hand to return an RResult<T> in an error state; the RError is implicitly converted into RResult...
static bool MatchesGlob(std::string_view haystack, std::string_view pattern)
The class is used as a return type for operations that can fail; wraps a value of type T or an RError...
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
virtual Int_t GetEntries() const
virtual TDirectory * GetDirectory(const char *namecycle, Bool_t printError=false, const char *funcname="GetDirectory")
Find a directory using apath.
virtual TList * GetListOfKeys() const
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
Create / open a file.
Book space in a file, create I/O buffers, to fill them, (un)compress them.
subroutine node(ivo, nuserm, iposp)
RootSource ParseRootSource(std::string_view sourceRaw, std::uint32_t flags)
Given a string like "file.root:dir/obj", converts it to a RootSource.
ROOT::RResult< std::pair< std::string_view, std::string_view > > SplitIntoFileNameAndPattern(std::string_view sourceRaw)
Given a string like "root://file.root:a/b/c", splits it into { "root://file.root",...
std::string NodeFullPath(const RootObjTree &tree, NodeIdx_t nodeIdx, ENodeFullPathOpt opt)
Given a node, returns its full path. If opt == kIncludeFilename, the path is prepended by "filename....
void PrintObjTree(const RootObjTree &tree, std::ostream &out=std::cout)
Prints out the structure of the object tree. Helpful for debugging.
@ kRecursive
Recurse into subdirectories when matching objects.
std::vector< ROOT::CmdLine::RootSource > ParseRootSources(const std::vector< std::string > &sourcesRaw, std::uint32_t flags)
Given a list of strings like "file.root:dir/obj", converts each string to a RootSource.
RootObjNode NodeFromKey(TKey &key)
RootSource GetMatchingPathsInFile(std::string_view fileName, std::string_view pattern, std::uint32_t flags)
Given a file and a "path pattern", returns a RootSource containing the tree of matched objects.
TRangeCast< T, false > TRangeStaticCast
TRangeStaticCast is an adapter class that allows the typed iteration through a TCollection.
std::string Join(const std::string &sep, StringCollection_t &&strings)
Concatenate a list of strings with a separator.
std::vector< std::string > Split(std::string_view str, std::string_view delims, bool skipEmpty=false)
Splits a string at each character in delims.
constexpr full_match_result< const_iterator_t< Sequence >, const_iterator_t< Pattern > > match(Sequence &&sequence, Pattern &&pattern, const cards< container_item_t< Pattern > > &c=cards< container_item_t< Pattern > >(), const EqualTo &equal_to=EqualTo())
A representation of all objects involved in a rootls-style ROOT file listing.
std::unique_ptr< TFile > fFile
std::vector< std::string > fErrors