Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
rootls.cxx
Go to the documentation of this file.
1// \file rootls.cxx
2///
3/// Native implementation of rootls, partially based on rootls.py.
4///
5/// \author Giacomo Parolini <giacomo.parolini@cern.ch>
6/// \date 2025-06-27
7
8/*************************************************************************
9 * Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. *
10 * All rights reserved. *
11 * *
12 * For the licensing terms see $ROOTSYS/LICENSE. *
13 * For the list of contributors see $ROOTSYS/README/CREDITS. *
14 *************************************************************************/
15
16#include <algorithm>
17#include <cstdint>
18#include <cstring>
19#include <deque>
20#include <iomanip>
21#include <iostream>
22#include <string>
23#include <vector>
24
25#include "logging.hxx"
26#include "optparse.hxx"
27#include "RootObjTree.hxx"
28#include "RootObjTree.cxx"
29
30#include <TBranch.h>
31#include <TError.h>
32#include <TFile.h>
33#include <TKey.h>
34#include <TTree.h>
35
36#include <ROOT/StringUtils.hxx>
37#include <ROOT/RError.hxx>
38#include <ROOT/RNTuple.hxx>
40
41#if defined(R__UNIX)
42#include <sys/ioctl.h>
43#include <unistd.h>
44#elif defined(R__WIN32)
45#define WIN32_LEAN_AND_MEAN
46#define VC_EXTRALEAN
47#include <windows.h>
48#undef GetClassName
49#endif
50
51using namespace ROOT::CmdLine;
52
53static const char *const kAnsiNone = "\x1B[0m";
54static const char *const kAnsiGreen = "\x1B[32m";
55static const char *const kAnsiBlue = "\x1B[34m";
56static const char *const kAnsiBold = "\x1B[1m";
57
58static const char *Color(const char *col)
59{
60#if defined(R__WIN32)
61 return "";
62#else
63 const static bool isTerm = isatty(STDOUT_FILENO);
64 if (isTerm)
65 return col;
66 return "";
67#endif
68}
69
70static const char *const kLongHelp = R"(
71Display ROOT files contents in the terminal.
72
73positional arguments:
74 FILE Input file
75
76options:
77 -h, --help show this help message and exit
78 -1, --oneColumn Print content in one column
79 -c, --allCycles Force display of all objects' cycles
80 -l, --longListing Use a long listing format.
81 -t, --treeListing Print tree recursively and use a long listing format.
82 -R, --rntupleListing Print RNTuples recursively and use a long listing format.
83 -r, --recursiveListing Traverse file recursively entering any TDirectory.
84
85Examples:
86- rootls example.root
87 Display contents of the ROOT file 'example.root'.
88
89- rootls example.root:dir
90 Display contents of the directory 'dir' from the ROOT file 'example.root'.
91
92- rootls example.root:*
93 Display contents of the ROOT file 'example.root' and his subdirectories.
94
95- rootls file1.root file2.root
96 Display contents of ROOT files 'file1.root' and 'file2.root'.
97
98- rootls *.root
99 Display contents of ROOT files whose name ends with '.root'.
100
101- rootls -1 example.root
102 Display contents of the ROOT file 'example.root' in one column.
103
104- rootls -l example.root
105 Display contents of the ROOT file 'example.root' and use a long listing format.
106
107- rootls -t example.root
108 Display contents of the ROOT file 'example.root', use a long listing format and print trees recursively.
109
110- rootls -r example.root
111 Display contents of the ROOT file 'example.root', traversing recursively any TDirectory.
112)";
113
114static bool ClassInheritsFrom(const char *class_, const char *baseClass)
115{
116 const auto *cl = TClass::GetClass(class_);
117 const bool inherits = cl && cl->InheritsFrom(baseClass);
118 return inherits;
119}
120
131
137
138 std::uint32_t fFlags = 0;
139 std::vector<RootSource> fSources;
141};
142
143struct V2i {
144 int x, y;
145};
146
148{
149 int columns = 80, rows = 25;
150#if defined(R__UNIX)
151 {
152 winsize w;
153 if (::ioctl(STDIN_FILENO, TIOCGWINSZ, &w) == 0 || ::ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0 ||
154 ::ioctl(STDERR_FILENO, TIOCGWINSZ, &w) == 0) {
155 rows = w.ws_row;
156 columns = w.ws_col;
157 }
158 }
159#elif defined(R__WINDOWS)
160 {
161 CONSOLE_SCREEN_BUFFER_INFO csbi;
162 if (::GetConsoleScreenBufferInfo(::GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
163 columns = csbi.srWindow.Right - csbi.srWindow.Left + 1;
164 rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
165 }
166 }
167#endif
168 return {columns, rows};
169}
170
171using Indent = int;
172
173static void PrintIndent(std::ostream &stream, Indent indent)
174{
175 for (int i = 0; i < indent; ++i) {
176 stream << ' ';
177 }
178}
179
180static void PrintDatime(std::ostream &stream, const TDatime &datime)
181{
182 static const char *kMonths[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
183 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
184 int monthNo = datime.GetMonth() - 1;
185 const char *month = monthNo >= 0 && monthNo < 12 ? kMonths[monthNo] : "???";
186 std::ios defaultFmt(nullptr);
187 stream << month << ' ';
188 stream << std::right << std::setfill('0') << std::setw(2) << datime.GetDay() << ' ';
189 stream << std::setw(2) << datime.GetHour() << ':' << datime.GetMinute() << ' ' << datime.GetYear() << ' ';
190 stream.copyfmt(defaultFmt);
191}
192
193// NOTE: T may be a TTree or a TBranch
194template <typename T>
195static void PrintTTree(std::ostream &stream, T &tree, Indent indent)
196{
197 TObjArray *branches = tree.GetListOfBranches();
198 std::size_t maxNameLen = 0, maxTitleLen = 0;
199 for (int i = 0; i < branches->GetEntries(); ++i) {
200 TBranch *branch = static_cast<TBranch *>((*branches)[i]);
201 maxNameLen = std::max(maxNameLen, strlen(branch->GetName()));
202 maxTitleLen = std::max(maxTitleLen, strlen(branch->GetTitle()));
203 }
204 maxNameLen += 2;
205 maxTitleLen += 4;
206
207 for (int i = 0; i < branches->GetEntries(); ++i) {
208 TBranch *branch = static_cast<TBranch *>((*branches)[i]);
209 PrintIndent(stream, indent);
210 stream << std::left << std::setw(maxNameLen) << branch->GetName();
211 std::string titleStr = std::string("\"") + branch->GetTitle() + "\"";
212 stream << std::setw(maxTitleLen) << titleStr;
213 stream << std::setw(1) << branch->GetTotBytes();
214 stream << '\n';
215 PrintTTree(stream, *branch, indent + 2);
216 }
217}
218
219static void PrintClusters(std::ostream &stream, TTree &tree, Indent indent)
220{
221 PrintIndent(stream, indent);
222 stream << Color(kAnsiBold) << "Cluster INCLUSIVE ranges:\n" << Color(kAnsiNone);
223
224 std::size_t nTotClusters = 0;
225 auto clusterIt = tree.GetClusterIterator(0);
226 auto clusterStart = clusterIt();
227 const auto nEntries = tree.GetEntries();
228 while (clusterStart < nEntries) {
229 PrintIndent(stream, indent);
230 stream << " - # " << nTotClusters << ": [" << clusterStart << ", " << clusterIt.GetNextEntry() - 1 << "]\n";
231 ++nTotClusters;
232 clusterStart = clusterIt();
233 }
234 PrintIndent(stream, indent);
235 stream << Color(kAnsiBold) << "The total number of clusters is " << nTotClusters << "\n";
236}
237
238// Prints an RNTuple field tree recursively.
239static void PrintRNTuple(std::ostream &stream, const ROOT::RNTupleDescriptor &desc, Indent indent,
240 const ROOT::RFieldDescriptor &rootField, std::size_t minNameLen = 0,
241 std::size_t minTypeLen = 0)
242{
243 std::size_t maxNameLen = 0, maxTypeLen = 0;
244 std::vector<const ROOT::RFieldDescriptor *> fields;
245 fields.reserve(rootField.GetLinkIds().size());
246 for (const auto &field : desc.GetFieldIterable(rootField.GetId())) {
247 fields.push_back(&field);
248 maxNameLen = std::max(maxNameLen, field.GetFieldName().length());
249 maxTypeLen = std::max(maxTypeLen, field.GetTypeName().length());
250 }
251 maxNameLen = std::max(minNameLen, maxNameLen + 2);
252 maxTypeLen = std::max(minTypeLen, maxTypeLen + 4);
253
254 std::sort(fields.begin(), fields.end(),
255 [](const auto &a, const auto &b) { return a->GetFieldName() < b->GetFieldName(); });
256
257 // To aid readability a bit, we use a '.' fill for all nested subfields.
258 const char fillChar = minNameLen == 0 ? ' ' : '.';
259 for (const auto *field : fields) {
260 PrintIndent(stream, indent);
261 stream << std::left << std::setfill(fillChar) << std::setw(maxNameLen) << field->GetFieldName();
262 stream << std::setfill(' ') << std::setw(maxTypeLen) << field->GetTypeName();
263 if (!field->GetFieldDescription().empty()) {
264 std::string descStr = '"' + field->GetFieldDescription() + '"';
265 stream << std::setw(1) << descStr;
266 }
267 stream << '\n';
268 PrintRNTuple(stream, desc, indent + 2, *field, maxNameLen - 2, maxTypeLen - 2);
269 }
270}
271
272static void PrintChildrenDetailed(std::ostream &stream, const RootObjTree &tree, NodeIdx_t nodeIdx, std::uint32_t flags,
273 Indent indent, std::size_t minNameLen = 0, std::size_t minClassLen = 0);
274
275/// Prints a `ls -l`-like output:
276///
277/// $ rootls -l https://root.cern/files/tutorials/hsimple.root
278/// TProfile Jun 30 23:59 2018 hprof;1 "Profile of pz versus px"
279/// TH1F Jun 30 23:59 2018 hpx;1 "This is the px distribution"
280/// TH2F Jun 30 23:59 2018 hpxpy;1 "py vs px"
281/// TNtuple Jun 30 23:59 2018 ntuple;1 "Demo ntuple"
282///
283/// \param stream The output stream to print to
284/// \param tree The node tree
285/// \param nodesBegin The first node to be printed
286/// \param nodesEnd The last node to be printed
287/// \param flags A bitmask of RootLsArgs::Flags that influence how stuff is printed
288/// \param indent Each line of the output will have these many leading whitespaces
289static void PrintNodesDetailed(std::ostream &stream, const RootObjTree &tree,
290 std::vector<NodeIdx_t>::const_iterator nodesBegin,
291 std::vector<NodeIdx_t>::const_iterator nodesEnd, std::uint32_t flags, Indent indent,
292 std::size_t minNameLen = 0, std::size_t minClassLen = 0)
293{
294 std::size_t maxClassLen = 0, maxNameLen = 0;
295 for (auto childIt = nodesBegin; childIt != nodesEnd; ++childIt) {
296 const auto &child = tree.fNodes[*childIt];
297 maxClassLen = std::max(maxClassLen, child.fClassName.length());
298 maxNameLen = std::max(maxNameLen, child.fName.length());
299 }
300 maxClassLen = std::max(minClassLen, maxClassLen + 2);
301 maxNameLen = std::max(minNameLen, maxNameLen + 2);
302
303 for (auto childIt = nodesBegin; childIt != nodesEnd; ++childIt) {
304 NodeIdx_t childIdx = *childIt;
305 const auto &child = tree.fNodes[childIdx];
306
307 const char *cycleStr = "";
308 // If this key is the first one in the list, or if it has a different name than the previous one, it means that
309 // it's the first object of that kind in the list.
310 if (childIt == nodesBegin || child.fName != tree.fNodes[childIdx - 1].fName) {
311 // Then we check the following key. If the current key is not the last key in the list and if the following key
312 // has the same name, then it means it's another cycle of the same object. Thus, it's gonna be a backup cycle
313 // of the same object. Otherwise, it's just a key with one cycle so we don't need to print information two
314 // distinguish between different cycles of the same key.
315 if (std::next(childIt) != nodesEnd && child.fName == tree.fNodes[childIdx + 1].fName) {
316 cycleStr = "[current cycle]";
317 }
318 } else {
319 // This key is a subsequent cycle of a previous key
320 cycleStr = "[backup cycle]";
321 }
322
323 PrintIndent(stream, indent);
324 stream << std::left;
325 stream << Color(kAnsiBold) << std::setw(maxClassLen) << child.fClassName << Color(kAnsiNone);
326 PrintDatime(stream, child.fKey->GetDatime());
327 std::string namecycle = child.fName + ';' + std::to_string(child.fKey->GetCycle());
328 stream << std::left << std::setw(maxNameLen) << namecycle;
329 stream << " \"" << child.fKey->GetTitle() << "\" " << cycleStr;
330 stream << '\n';
331
332 if (flags & RootLsArgs::kTreeListing) {
333 if (ClassInheritsFrom(child.fClassName.c_str(), "TTree")) {
334 TTree *ttree = child.fKey->ReadObject<TTree>();
335 if (ttree) {
336 PrintTTree(stream, *ttree, indent + 2);
337 PrintClusters(stream, *ttree, indent + 2);
338 }
339 }
340 }
341 if (flags & RootLsArgs::kRNTupleListing) {
342 if (ClassInheritsFrom(child.fClassName.c_str(), "ROOT::RNTuple")) {
343 auto *rntuple = child.fKey->ReadObject<ROOT::RNTuple>();
344 if (rntuple) {
345 auto reader = ROOT::RNTupleReader::Open(*rntuple);
346 const auto &desc = reader->GetDescriptor();
347 PrintRNTuple(stream, desc, indent + 2, desc.GetFieldZero());
348 } else {
349 Err() << "failed to read RNTuple object: " << child.fName << "\n";
350 }
351 }
352 }
353 if ((flags & RootLsArgs::kRecursiveListing) && ClassInheritsFrom(child.fClassName.c_str(), "TDirectory")) {
354 PrintChildrenDetailed(stream, tree, childIdx, flags, indent + 2, maxNameLen - 2, maxClassLen - 2);
355 }
356 }
357 stream << std::flush;
358}
359
360/// \param nodeIdx The index of the node whose children should be printed
361static void PrintChildrenDetailed(std::ostream &stream, const RootObjTree &tree, NodeIdx_t nodeIdx, std::uint32_t flags,
362 Indent indent, std::size_t minNameLen, std::size_t minClassLen)
363{
364
365 const auto &node = tree.fNodes[nodeIdx];
366 if (node.fNChildren == 0)
367 return;
368
369 std::vector<NodeIdx_t> children(node.fNChildren);
370 std::iota(children.begin(), children.end(), node.fFirstChild);
371 PrintNodesDetailed(stream, tree, children.begin(), children.end(), flags, indent, minNameLen, minClassLen);
372}
373
374// Prints all children of `nodeIdx`-th node in a ls-like fashion.
375static void PrintChildrenInColumns(std::ostream &stream, const RootObjTree &tree, NodeIdx_t nodeIdx,
376 std::uint32_t flags, Indent indent);
377
378// Prints a `ls`-like output
379static void PrintNodesInColumns(std::ostream &stream, const RootObjTree &tree,
380 std::vector<NodeIdx_t>::const_iterator nodesBegin,
381 std::vector<NodeIdx_t>::const_iterator nodesEnd, std::uint32_t flags, Indent indent)
382{
383 const bool displayAllCycles = (flags & RootLsArgs::kForceAllCycles);
384
385 // Calculate number of nodes, min and max name length
386 std::size_t minElemWidth = std::numeric_limits<std::size_t>::max();
387 std::size_t maxElemWidth = 0;
388 std::vector<NodeIdx_t> uniqueNodes;
389 std::string_view prevNodeName;
390 for (auto it = nodesBegin; it != nodesEnd; ++it) {
391 NodeIdx_t nodeIdx = *it;
392 const auto &node = tree.fNodes[nodeIdx];
393 // De-duplicate node names (we only print one name even if the node has multiple cycles - unless we have the
394 // kForceAllCycles flag active)
395 if (!displayAllCycles && node.fName == prevNodeName)
396 continue;
397 uniqueNodes.push_back(nodeIdx);
398 auto elemWidth = node.fName.length();
399 if (displayAllCycles) {
400 // If we're displaying the cycles we need to keep that in mind for calculating the column widths.
401 const auto cycleLen = std::to_string(node.fCycle).length();
402 elemWidth += cycleLen + 1; // +1 to account for the ';'
403 }
404 minElemWidth = std::min(elemWidth, minElemWidth);
405 maxElemWidth = std::max(elemWidth, maxElemWidth);
406 prevNodeName = node.fName;
407 }
408
409 const auto nNodes = uniqueNodes.size();
410 if (nNodes == 0)
411 return;
412
413 V2i terminalSize = GetTerminalSize();
414 terminalSize.x -= indent;
415 const int minCharsBetween = 2;
416 minElemWidth += minCharsBetween;
417 maxElemWidth += minCharsBetween;
418
419 // Figure out how many columns do we need
420 std::size_t nCols = 0;
421 std::vector<int> colWidths;
422 const bool oneColumn = (flags & RootLsArgs::kOneColumn);
423 if (maxElemWidth > static_cast<std::size_t>(terminalSize.x) || oneColumn) {
424 nCols = 1;
425 colWidths = {1};
426 } else {
427 // Start with the max possible number of columns and reduce it until it fits
428 nCols = std::min<int>(nNodes, terminalSize.x / static_cast<int>(minElemWidth));
429 while (1) {
430 int totWidth = 0;
431
432 // Find maximum width of each column
433 for (auto colIdx = 0u; colIdx < nCols; ++colIdx) {
434 int width = 0;
435 for (auto j = 0u; j < nNodes; ++j) {
436 if ((j % nCols) == colIdx) {
437 NodeIdx_t childIdx = nodesBegin[j];
438 const RootObjNode &child = tree.fNodes[childIdx];
439 auto nameLen = child.fName.length();
440 if (displayAllCycles) {
441 const auto cycleLen = std::to_string(child.fCycle).length();
442 nameLen += cycleLen + 1; // +1 to account for the ';'
443 }
444 width = std::max<int>(width, nameLen + minCharsBetween);
445 }
446 }
447
448 totWidth += width;
449 if (totWidth > terminalSize.x) {
450 --nCols;
451 colWidths.clear();
452 break;
453 }
454
455 colWidths.push_back(width);
456 }
457
458 if (!colWidths.empty())
459 break;
460
461 // The loop should always end at some point given the check on maxElemWidth <= terminalSize.x
462 assert(nCols > 0);
463 }
464 }
465
466 //// Do the actual printing
467
468 const bool isTerminal = terminalSize.x + terminalSize.y > 0;
469
470 auto curCol = 0u;
471 for (auto i = 0u; i < nNodes; ++i) {
472 NodeIdx_t childIdx = uniqueNodes[i];
473 const auto &child = tree.fNodes[childIdx];
474
475 if (curCol == 0) {
476 PrintIndent(stream, indent);
477 }
478
479 // Colors
480 const bool isDir = ClassInheritsFrom(child.fClassName.c_str(), "TDirectory");
481 if (isTerminal) {
482 if (isDir)
483 stream << Color(kAnsiBlue);
484 else if (ClassInheritsFrom(child.fClassName.c_str(), "TTree"))
485 stream << Color(kAnsiGreen);
486 }
487
488 // Handle line breaks. Lines are broken in the following situations:
489 // - when the current column number reaches the max number of columns
490 // - when we are in recursive mode and the item is a directory with children
491 // - when we are in recursive mode and the NEXT item is a directory with children
492
493 const bool isDirWithRecursiveDisplay = isDir && (flags & RootLsArgs::kRecursiveListing) && child.fNChildren > 0;
494
495 bool nextIsDirWithRecursiveDisplay = false;
496 if ((flags & RootLsArgs::kRecursiveListing) && i < nNodes - 1) {
497 NodeIdx_t nextChildIdx = uniqueNodes[i + 1];
498 const auto &nextChild = tree.fNodes[nextChildIdx];
499 nextIsDirWithRecursiveDisplay =
500 nextChild.fNChildren > 0 && ClassInheritsFrom(nextChild.fClassName.c_str(), "TDirectory");
501 }
502
503 const bool isExtremal = (((curCol + 1) % nCols) == 0) || (i == nNodes - 1) || isDirWithRecursiveDisplay ||
504 nextIsDirWithRecursiveDisplay;
505 auto nodeName = child.fName + (displayAllCycles ? ";" + std::to_string(child.fCycle) : "");
506 if (!isExtremal) {
507 stream << std::left << std::setw(colWidths[curCol % nCols]) << nodeName;
508 } else {
509 stream << std::setw(1) << nodeName;
510 }
511 stream << Color(kAnsiNone);
512
513 if (isExtremal) {
514 stream << '\n';
515 curCol = 0;
516 } else {
517 ++curCol;
518 }
519
520 if (isDirWithRecursiveDisplay) {
521 PrintChildrenInColumns(stream, tree, childIdx, flags, indent + 2);
522 }
523 }
524}
525
526// Prints all children of `nodeIdx`-th node in a ls-like fashion.
527static void PrintChildrenInColumns(std::ostream &stream, const RootObjTree &tree, NodeIdx_t nodeIdx,
528 std::uint32_t flags, Indent indent)
529{
530 const auto &node = tree.fNodes[nodeIdx];
531 if (node.fNChildren == 0)
532 return;
533
534 std::vector<NodeIdx_t> children(node.fNChildren);
535 std::iota(children.begin(), children.end(), node.fFirstChild);
536 PrintNodesInColumns(stream, tree, children.begin(), children.end(), flags, indent);
537}
538
539// Main entrypoint of the program
540static void RootLs(const RootLsArgs &args, std::ostream &stream = std::cout)
541{
542 const Indent outerIndent = (args.fSources.size() > 1) * 2;
543 for (const auto &source : args.fSources) {
544 if (args.fSources.size() > 1) {
545 stream << source.fFileName << " :\n";
546 }
547
549 PrintNodesDetailed(stream, source.fObjectTree, source.fObjectTree.fLeafList.begin(),
550 source.fObjectTree.fLeafList.end(), args.fFlags, outerIndent);
551 else
552 PrintNodesInColumns(stream, source.fObjectTree, source.fObjectTree.fLeafList.begin(),
553 source.fObjectTree.fLeafList.end(), args.fFlags, outerIndent);
554
555 const bool manySources = source.fObjectTree.fDirList.size() + source.fObjectTree.fLeafList.size() > 1;
556 const Indent indent = outerIndent + manySources * 2;
557 for (NodeIdx_t rootIdx : source.fObjectTree.fDirList) {
558 if (manySources) {
559 PrintIndent(stream, outerIndent);
560 stream << NodeFullPath(source.fObjectTree, rootIdx, ENodeFullPathOpt::kExcludeFilename) << " :\n";
561 }
562
564 PrintChildrenDetailed(stream, source.fObjectTree, rootIdx, args.fFlags, indent);
565 else
566 PrintChildrenInColumns(stream, source.fObjectTree, rootIdx, args.fFlags, indent);
567 }
568 }
569}
570
571static RootLsArgs ParseArgs(const char **args, int nArgs)
572{
573 RootLsArgs outArgs;
575 opts.AddFlag({"-h", "--help"});
576 opts.AddFlag({"-1", "--oneColumn"});
577 opts.AddFlag({"-l", "--longListing"});
578 opts.AddFlag({"-t", "--treeListing"});
579 opts.AddFlag({"-R", "--rntupleListing"});
580 opts.AddFlag({"-r", "--recursiveListing"});
581 opts.AddFlag({"-c", "--allCycles"});
582
583 opts.Parse(args, nArgs);
584 for (const auto &err : opts.GetErrors())
585 Err() << err << "\n";
586
587 if (opts.GetSwitch("help")) {
589 return outArgs;
590 }
591
592 if (!opts.GetErrors().empty() || opts.GetArgs().empty()) {
594 return outArgs;
595 }
596
597 outArgs.fFlags |= opts.GetSwitch("oneColumn") * RootLsArgs::kOneColumn;
598 outArgs.fFlags |= opts.GetSwitch("longListing") * RootLsArgs::kLongListing;
599 outArgs.fFlags |= opts.GetSwitch("treeListing") * RootLsArgs::kTreeListing;
600 outArgs.fFlags |= opts.GetSwitch("recursiveListing") * RootLsArgs::kRecursiveListing;
601 outArgs.fFlags |= opts.GetSwitch("rntupleListing") * RootLsArgs::kRNTupleListing;
602 outArgs.fFlags |= opts.GetSwitch("allCycles") * RootLsArgs::kForceAllCycles;
603
604 // Positional arguments
606 outArgs.fSources = ROOT::CmdLine::ParseRootSources(opts.GetArgs(), flags);
607
608 return outArgs;
609}
610
611int main(int argc, char **argv)
612{
613 // Ignore diagnostics up to (but excluding) kError to avoid spamming users with TClass::Init warnings.
615
616 InitLog("rootls");
617
618 auto args = ParseArgs(const_cast<const char **>(argv) + 1, argc - 1);
619 if (args.fPrintUsageAndExit != RootLsArgs::EPrintUsage::kNo) {
620 std::cerr << "usage: rootls [-1hltr] FILE [FILE ...]\n";
621 if (args.fPrintUsageAndExit == RootLsArgs::EPrintUsage::kLong) {
622 std::cerr << kLongHelp;
623 return 0;
624 }
625 return 1;
626 }
627
628 // sort sources by name
629 std::sort(args.fSources.begin(), args.fSources.end(),
630 [](const auto &a, const auto &b) { return a.fFileName < b.fFileName; });
631
632 // sort leaves by namecycle
633 bool errors = false;
634 for (auto &source : args.fSources) {
635 if (!source.fErrors.empty()) {
636 errors = true;
637 for (const auto &err : source.fErrors)
638 Err() << err << "\n";
639 }
640 std::sort(source.fObjectTree.fLeafList.begin(), source.fObjectTree.fLeafList.end(),
641 [&tree = source.fObjectTree](NodeIdx_t aIdx, NodeIdx_t bIdx) {
642 const auto &a = tree.fNodes[aIdx];
643 const auto &b = tree.fNodes[bIdx];
644 // Note that we order by decreasing cycle, i.e. from most to least recent
645 return (a.fName != b.fName) ? a.fName < b.fName : a.fCycle > b.fCycle;
646 });
647 }
648
649 RootLs(args);
650
651 return errors;
652}
#define b(i)
Definition RSha256.hxx:100
#define a(i)
Definition RSha256.hxx:99
static void indent(ostringstream &buf, int indent_level)
constexpr Int_t kError
Definition TError.h:47
externInt_t gErrorIgnoreLevel
errors with level below this value will be ignored. Default is kUnset.
Definition TError.h:140
Double_t err
std::vector< double > errors
void AddFlag(std::initializer_list< std::string_view > aliases, EFlagType type=EFlagType::kSwitch, std::string_view help="", std::uint32_t flagOpts=0)
Defines a new flag (either a switch or a flag with argument).
Definition optparse.hxx:208
const std::vector< std::string > & GetErrors() const
Returns all parsing errors.
Definition optparse.hxx:180
int GetSwitch(std::string_view name) const
If name refers to a previously-defined switch (i.e.
Definition optparse.hxx:300
const std::vector< std::string > & GetArgs() const
Retrieves all positional arguments.
Definition optparse.hxx:182
void Parse(const char **args, std::size_t nArgs)
Definition optparse.hxx:425
Metadata stored for every field of an RNTuple.
ROOT::DescriptorId_t GetId() const
const std::vector< ROOT::DescriptorId_t > & GetLinkIds() const
The on-storage metadata of an RNTuple.
RFieldDescriptorIterable GetFieldIterable(const RFieldDescriptor &fieldDesc) const
static std::unique_ptr< RNTupleReader > Open(std::string_view ntupleName, std::string_view storage, const ROOT::RNTupleReadOptions &options=ROOT::RNTupleReadOptions())
Open an RNTuple for reading.
Representation of an RNTuple data set in a ROOT file.
Definition RNTuple.hxx:67
A TTree is a list of TBranches.
Definition TBranch.h:93
Long64_t GetTotBytes(Option_t *option="") const
Return total number of bytes in the branch (excluding current buffer) if option ="*" includes all sub...
Definition TBranch.cxx:2219
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.
Definition TClass.cxx:2994
This class stores the date and time with a precision of one second in an unsigned 32 bit word (950130...
Definition TDatime.h:37
Int_t GetMonth() const
Definition TDatime.h:66
Int_t GetDay() const
Definition TDatime.h:67
Int_t GetHour() const
Definition TDatime.h:69
Int_t GetYear() const
Definition TDatime.h:65
Int_t GetMinute() const
Definition TDatime.h:70
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:50
An array of TObjects.
Definition TObjArray.h:31
A TTree represents a columnar dataset.
Definition TTree.h:89
int main()
subroutine node(ivo, nuserm, iposp)
Definition g2root.f:833
void InitLog(const char *name, int defaultVerbosity=1)
Definition logging.hxx:39
std::ostream & Err()
Definition logging.hxx:55
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....
@ kRecursive
Recurse into subdirectories when matching objects.
std::uint32_t NodeIdx_t
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.
int width
Definition main.c:107
static const char *const kLongHelp
static void PrintDatime(std::ostream &stream, const TDatime &datime)
Definition rootls.cxx:180
static void PrintRNTuple(std::ostream &stream, const ROOT::RNTupleDescriptor &desc, Indent indent, const ROOT::RFieldDescriptor &rootField, std::size_t minNameLen=0, std::size_t minTypeLen=0)
Definition rootls.cxx:239
static void PrintTTree(std::ostream &stream, T &tree, Indent indent)
Definition rootls.cxx:195
static void PrintNodesDetailed(std::ostream &stream, const RootObjTree &tree, std::vector< NodeIdx_t >::const_iterator nodesBegin, std::vector< NodeIdx_t >::const_iterator nodesEnd, std::uint32_t flags, Indent indent, std::size_t minNameLen=0, std::size_t minClassLen=0)
Prints a ls -l-like output:
Definition rootls.cxx:289
static const char *const kAnsiGreen
Definition rootls.cxx:54
static void PrintClusters(std::ostream &stream, TTree &tree, Indent indent)
Definition rootls.cxx:219
static void RootLs(const RootLsArgs &args, std::ostream &stream=std::cout)
Definition rootls.cxx:540
static const char *const kAnsiBlue
Definition rootls.cxx:55
static void PrintChildrenDetailed(std::ostream &stream, const RootObjTree &tree, NodeIdx_t nodeIdx, std::uint32_t flags, Indent indent, std::size_t minNameLen=0, std::size_t minClassLen=0)
Definition rootls.cxx:361
static const char *const kAnsiBold
Definition rootls.cxx:56
static const char * Color(const char *col)
Definition rootls.cxx:58
static const char *const kAnsiNone
Definition rootls.cxx:53
static void PrintIndent(std::ostream &stream, Indent indent)
Definition rootls.cxx:173
static bool ClassInheritsFrom(const char *class_, const char *baseClass)
Definition rootls.cxx:114
int Indent
Definition rootls.cxx:171
static void PrintNodesInColumns(std::ostream &stream, const RootObjTree &tree, std::vector< NodeIdx_t >::const_iterator nodesBegin, std::vector< NodeIdx_t >::const_iterator nodesEnd, std::uint32_t flags, Indent indent)
Definition rootls.cxx:379
static RootLsArgs ParseArgs(const char **args, int nArgs)
Definition rootls.cxx:571
static V2i GetTerminalSize()
Definition rootls.cxx:147
static void PrintChildrenInColumns(std::ostream &stream, const RootObjTree &tree, NodeIdx_t nodeIdx, std::uint32_t flags, Indent indent)
Definition rootls.cxx:527
A representation of all objects involved in a rootls-style ROOT file listing.
std::vector< RootSource > fSources
Definition rootls.cxx:139
std::uint32_t fFlags
Definition rootls.cxx:138
@ kRecursiveListing
Definition rootls.cxx:128
@ kForceAllCycles
Definition rootls.cxx:129
@ kRNTupleListing
Definition rootls.cxx:127
EPrintUsage fPrintUsageAndExit
Definition rootls.cxx:140
int x
Definition rootls.cxx:144
int y
Definition rootls.cxx:144
Int_t month
TTree * tree