LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
file_info_dumper.cc
Go to the documentation of this file.
5 #include "boost/program_options.hpp"
8 #include "cetlib/HorizontalRule.h"
9 #include "cetlib/container_algorithms.h"
10 
11 #include "TError.h"
12 #include "TFile.h"
13 
14 extern "C" {
15 #include "sqlite3.h"
16 }
17 
18 #include <algorithm>
19 #include <bitset>
20 #include <iostream>
21 #include <ostream>
22 #include <sstream>
23 #include <string>
24 
25 namespace bpo = boost::program_options;
26 
27 using namespace std::string_literals;
29 using std::ostream;
30 using std::string;
31 using std::vector;
32 using stringvec = vector<string>;
33 
34 int print_process_history(InfoDumperInputFile const& file, ostream& output);
36  ostream& output,
37  bool compact);
38 int print_event_list(InfoDumperInputFile const& file, ostream& output);
39 int print_file_index(InfoDumperInputFile const& file, ostream& output);
40 int print_branchIDLists(InfoDumperInputFile const& file, ostream& output);
42  ostream& output,
43  ostream& errors);
44 
45 namespace {
46 
47  void
48  RootErrorHandler(int const level,
49  bool const die,
50  char const* location,
51  char const* message)
52  {
53  // Ignore dictionary errors.
54  if (level == kWarning && (!die) &&
55  strcmp(location, "TClass::TClass") == 0 &&
56  std::string(message).find("no dictionary") != std::string::npos) {
57  return;
58  } else {
59  // Default behavior
60  DefaultErrorHandler(level, die, location, message);
61  }
62  }
63 
64  // Code taken from the SQLite webpage:
65  // https://www.sqlite.org/backup.html
66  // With modifications.
67  //
68  // SQLite comments:
69  //
70  // This function is used to load the contents of a database file on disk
71  // into the "main" database of open database connection pInMemory, or
72  // to save the current contents of the database opened by pInMemory into
73  // a database file on disk. pInMemory is probably an in-memory database,
74  // but this function will also work fine if it is not.
75  //
76  // Parameter zFilename points to a nul-terminated string containing the
77  // name of the database file on disk to load from or save to. If parameter
78  // isSave is non-zero, then the contents of the file zFilename are
79  // overwritten with the contents of the database opened by pInMemory. If
80  // parameter isSave is zero, then the contents of the database opened by
81  // pInMemory are replaced by data loaded from the file zFilename.
82  //
83  // If the operation is successful, SQLITE_OK is returned. Otherwise, if
84  // an error occurs, an SQLite error code is returned.
85 
86  int
87  dbToFile(sqlite3* pInMemory, const char* zFilename)
88  {
89  int rc{0}; // Function return code
90  sqlite3* pFile{nullptr}; // Database connection opened on zFilename
91  sqlite3_backup* pBackup{nullptr}; // Backup object used to copy data
92 
93  // Open the database file identified by zFilename. Exit early if this fails
94  // for any reason.
95  rc = sqlite3_open(zFilename, &pFile);
96  if (rc == SQLITE_OK) {
97 
98  // Set up the backup procedure to copy from the "main" database of
99  // connection pFile to the main database of connection pInMemory.
100  // If something goes wrong, pBackup will be set to NULL and an error
101  // code and message left in connection pTo.
102 
103  // If the backup object is successfully created, call backup_step()
104  // to copy data from pFile to pInMemory. Then call backup_finish()
105  // to release resources associated with the pBackup object. If an
106  // error occurred, then an error code and message will be left in
107  // connection pTo. If no error occurred, then the error code belonging
108  // to pTo is set to SQLITE_OK.
109 
110  pBackup = sqlite3_backup_init(pFile, "main", pInMemory, "main");
111  if (pBackup != nullptr) {
112  (void)sqlite3_backup_step(pBackup, -1);
113  (void)sqlite3_backup_finish(pBackup);
114  }
115  rc = sqlite3_errcode(pFile);
116  }
117 
118  // Close the database connection opened on database file zFilename
119  // and return the result of this function.
120  (void)sqlite3_close(pFile);
121  return rc;
122  }
123 }
124 
125 int
126 main(int argc, char* argv[]) try {
127  // ------------------
128  // use the boost command line option processing library to help out
129  // with command line options
130  std::ostringstream descstr;
131  descstr << argv[0] << " <options> [<source-file>]+";
132 
133  bpo::options_description desc{descstr.str()};
134  desc.add_options()("help,h", "produce help message")(
135  "full-path", "print full path of file name")(
136  "event-list", "print event-list for each input file")(
137  "file-index", "prints FileIndex object for each input file")(
138  "process-history",
139  "prints list of processes that produced this file (output given in "
140  "chronological order)")(
141  "range-of-validity",
142  bpo::value<string>()->implicit_value("full"),
143  "prints range of validity for each input file. Allowed values are\n"
144  " \"full\" (default)\n"
145  " \"compact\"")("branch-ids,B",
146  "prints BranchID lists stored in the file")(
147  "db-to-file",
148  ("Writes RootFileDB to external SQLite database with the same base name as the input file and the suffix '.db'.\n"s +
149  "(Writes to directory in which '"s + argv[0] + "' is executed)."s)
150  .c_str())(
151  "source,s", bpo::value<stringvec>(), "source data file (multiple OK)");
152 
153  bpo::options_description all_opts{"All Options"};
154  all_opts.add(desc);
155 
156  // Each non-option argument is interpreted as the name of a files to
157  // be processed. Any number of filenames is allowed.
158  bpo::positional_options_description pd;
159  pd.add("source", -1);
160  // The variables_map contains the actual program options.
161  bpo::variables_map vm;
162  try {
163  bpo::store(bpo::command_line_parser(argc, argv)
164  .options(all_opts)
165  .positional(pd)
166  .run(),
167  vm);
168  bpo::notify(vm);
169  }
170  catch (bpo::error const& e) {
171  std::cerr << "Exception from command line processing in " << argv[0] << ": "
172  << e.what() << "\n";
173  return 2;
174  }
175 
176  if (vm.count("help")) {
177  std::cout << desc << std::endl;
178  return 1;
179  }
180 
181  // Get the names of the files we will process.
182  stringvec file_names;
183  size_t const file_count{vm.count("source")};
184  if (file_count < 1) {
185  std::cerr << "One or more input files must be specified;"
186  << " supply filenames as program arguments\n"
187  << "For usage and options list, please do '" << argv[0]
188  << " --help'.\n";
189  return 3;
190  }
191  file_names.reserve(file_count);
192  cet::copy_all(vm["source"].as<stringvec>(), std::back_inserter(file_names));
193 
194  enum options_t {
195  PrintProcessHistory = 0,
196  PrintRangeSetsFull,
197  PrintRangeSetsCompact,
198  PrintEventList,
199  PrintFileIndex,
200  SaveDBtoFile,
201  FullPath,
202  PrintBranchIDLists,
203  NumOptions
204  };
205 
206  std::bitset<NumOptions> options;
207  options[PrintProcessHistory] = vm.count("process-history") > 0;
208  if (vm.count("range-of-validity") > 0) {
209  auto const& rov_value = vm["range-of-validity"].as<std::string>();
210  if (rov_value == "full") {
211  options.set(PrintRangeSetsFull);
212  } else if (rov_value == "compact") {
213  options.set(PrintRangeSetsCompact);
214  } else {
215  std::cerr
216  << "Incorrect argument value supplied for the 'range-of-validity'\n"
217  << "program option. Allowed values are:\n"
218  << " \"full\" (default)\n"
219  << " \"compact\"\n";
220  return 4;
221  }
222  }
223  options[PrintEventList] = vm.count("event-list") > 0;
224  options[PrintFileIndex] = vm.count("file-index") > 0;
225  options[SaveDBtoFile] = vm.count("db-to-file") > 0;
226  options[FullPath] = vm.count("full-path") > 0;
227  options[PrintBranchIDLists] = vm.count("branch-ids") > 0;
228 
229  if (options.none()) {
230  std::cerr << "No options were specified for processing input files.\n"
231  << "For usage and options list, please do '" << argv[0]
232  << " --help'.\n";
233  return 5;
234  }
235 
236  if (options.test(PrintEventList) && options.test(PrintFileIndex)) {
237  std::cerr
238  << "The --event-list and --file-index options are mutually exclusive.\n";
239  return 6;
240  }
241 
242  SetErrorHandler(RootErrorHandler);
243  tkeyvfs_init();
244 
245  ostream& output = std::cout;
246  ostream& errors = std::cerr;
247 
248  int rc{0};
249  for (auto const& fn : file_names) {
250  auto const& printed_name =
251  options.test(FullPath) ? fn : fn.substr(fn.find_last_of('/') + 1ul);
252  output << cet::HorizontalRule{30}('=') << '\n'
253  << "File: " << printed_name << '\n';
254  InfoDumperInputFile const file{fn};
255  if (options.test(PrintProcessHistory))
256  rc += print_process_history(file, output);
257  if (options.test(PrintRangeSetsFull))
258  rc += print_range_sets(file, output, false);
259  if (options.test(PrintRangeSetsCompact))
260  rc += print_range_sets(file, output, true);
261  if (options.test(PrintFileIndex))
262  rc += print_file_index(file, output);
263  if (options.test(PrintEventList))
264  rc += print_event_list(file, output);
265  if (options.test(SaveDBtoFile))
266  rc += db_to_file(file, output, errors);
267  if (options.test(PrintBranchIDLists))
268  rc += print_branchIDLists(file, output);
269  output << '\n';
270  }
271  return rc;
272 }
273 catch (cet::exception const& e) {
274  std::cerr << e.what() << '\n';
275  return 7;
276 }
277 catch (...) {
278  std::cerr << "Exception thrown for the last processed file. Please remove "
279  "it from the file list.\n";
280  return 8;
281 }
282 
283 //============================================================================
284 
285 int
287 {
288  file.print_process_history(output);
289  return 0;
290 }
291 
292 int
294  ostream& output,
295  bool const compactRanges)
296 {
297  file.print_range_sets(output, compactRanges);
298  return 0;
299 }
300 
301 int
302 print_event_list(InfoDumperInputFile const& file, ostream& output)
303 {
304  file.print_event_list(output);
305  return 0;
306 }
307 
308 int
309 print_file_index(InfoDumperInputFile const& file, ostream& output)
310 {
311  file.print_file_index(output);
312  return 0;
313 }
314 
315 int
317 {
318  file.print_branchIDLists(output);
319  return 0;
320 }
321 
322 int
323 db_to_file(InfoDumperInputFile const& file, ostream& output, ostream& errors)
324 {
325  TFile* current_file = file.tfile();
326  std::string const& rootFileName = current_file->GetName();
327 
328  // db file name has the same base as the input art/ROOT file
329  std::string::size_type const dist{rootFileName.find(".root") -
330  rootFileName.find_last_of('/')};
331  std::string const base{
332  rootFileName.substr(rootFileName.find_last_of('/') + 1, dist)};
333  std::string const extFileName{base + "db"};
334 
335  art::SQLite3Wrapper db{current_file, "RootFileDB"};
336  int const rc{dbToFile(db, extFileName.c_str())};
337  if (rc == 0) {
338  output << "\nRootFileDB from file \"" << current_file->GetName() << "\"\n"
339  << "saved to external database file \"" << extFileName << "\".\n";
340  } else {
341  errors << "\nCould not save RootFileDB from file \""
342  << current_file->GetName() << "\"\n"
343  << "to external database file.\n";
344  }
345  return rc;
346 }
int main(int argc, char *argv[])
Float_t s
Definition: plot.C:23
void print_event_list(std::ostream &) const
int print_range_sets(InfoDumperInputFile const &file, ostream &output, bool compact)
int print_file_index(InfoDumperInputFile const &file, ostream &output)
void RootErrorHandler(int level, bool die, char const *location, char const *message)
std::vector< std::string > stringvec
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
int print_branchIDLists(InfoDumperInputFile const &file, ostream &output)
int print_event_list(InfoDumperInputFile const &file, ostream &output)
int db_to_file(InfoDumperInputFile const &file, ostream &output, ostream &errors)
int tkeyvfs_init(void)
Definition: tkeyvfs.cc:1768
int print_process_history(InfoDumperInputFile const &file, ostream &output)
void print_process_history(std::ostream &) const
TFile * file
void print_range_sets(std::ostream &, bool compactRanges) const
void print_file_index(std::ostream &) const
Float_t e
Definition: plot.C:34
void print_branchIDLists(std::ostream &os) const
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33