LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
FileCatalogMetadataExtras_service.cc
Go to the documentation of this file.
1 //
3 // Name: FileCatalogMetadataExtras_service.cc
4 //
6 
7 #include <sstream>
8 #include <fstream>
9 #include <iomanip>
10 #include <vector>
11 #include <string>
12 #include <algorithm>
18 #include "cetlib_except/exception.h"
20 
21 #include "TROOT.h"
22 #include "TFile.h"
23 
24 //--------------------------------------------------------------------
25 // Constructor.
27  art::ActivityRegistry &reg) :
28  fGeneratePerFileMetadata(false),
29  fRenameOverwrite(false),
30  fOutputFileCount(0)
31 {
32  reconfigure(pset);
33 
34  // Register for callbacks.
35 
43 }
44 
45 
46 //--------------------------------------------------------------------
47 // Destructor.
49 {
50  // Shouldn't really be necessary to call checkOutputFiles, as we can
51  // catch final closed files via postEndJob callback. But do it just
52  // for extra safety, and can't do any harm.
53 
55 }
56 
57 //--------------------------------------------------------------------
58 // Set service parameters.
60 {
61  std::vector<std::string> md = pset.get<std::vector<std::string> >("Metadata");
62  fGeneratePerFileMetadata = pset.get<bool>("GeneratePerFileMetadata");
63  fCopyMetadataAttributes = pset.get<std::vector<std::string> >("CopyMetadataAttributes");
64  fRenameTemplate = pset.get<std::string>("RenameTemplate");
65  fRenameOverwrite = pset.get<bool>("RenameOverwrite");
66 
67  // Process name-value pairs.
68 
69  if(md.size() %2 != 0)
70  throw cet::exception("FileCatalogMetadataExtras")
71  << "Metadata array has odd number of entries.\n";
72  for(unsigned int i=0; i<md.size(); i += 2)
73  fPerJobMetadata.insert(std::pair<std::string, std::string>(md[i], md[i+1]));
74 
75  return;
76 }
77 
78 //--------------------------------------------------------------------
79 // PostBeginJob callback.
80 // Insert per-job metadata via FileCatalogMetadata service.
82 {
84 
85  // Get art metadata service.
86 
88 
89  // Loop over metadata.
90 
91  for(auto i=fPerJobMetadata.cbegin(); i!=fPerJobMetadata.cend(); ++i) {
92  const std::string& name = i->first;
93  const std::string& value = i->second;
94 
95  // Ignore null values.
96 
97  if(value.size() > 0) {
98 
99  // See if this (name, value) already exists.
100 
101  bool exists = false;
103  mds->getMetadata(md);
104  for(auto const & nvp : md) {
105  if(nvp.first == name) {
106  exists = true;
107 
108  // If value doesn't match, throw an exception.
109 
110  if(nvp.second != value) {
111  throw cet::exception("FileCatalogMetadataExtras")
112  << "Found duplicate name " << name << " with non-matching value.\n";
113  }
114  }
115  }
116 
117  // Add new (name, value).
118 
119  if(!exists)
120  mds->addMetadata(name, value);
121  }
122  }
123 }
124 
125 //--------------------------------------------------------------------
126 // PostEndJob callback.
128 {
130 }
131 
132 //--------------------------------------------------------------------
133 // PostOpenFile callback.
135 {
136  fLastInputFile = fn;
138 }
139 
140 //--------------------------------------------------------------------
141 // PostCloseFile callback.
143 {
145 }
146 
147 //--------------------------------------------------------------------
148 // PreEvent callback.
150 {
152 }
153 
154 //--------------------------------------------------------------------
155 // PostEvent callback.
157 {
159 
160  // Update metadata for open output files.
161 
162  art::RunNumber_t run = evt.run();
163  art::SubRunNumber_t subrun = evt.subRun();
164  art::EventNumber_t event = evt.event();
165 
166  for(auto const& fn : fOutputFiles) {
167  auto iMap = fPerFileMetadataMap.find(fn);
168  if (iMap == fPerFileMetadataMap.end()) {
169  throw cet::exception("FileCatalogMetadataExtras")
170  << "no metadata for output file '" << fn << "'\n";
171  }
172  PerFileMetadata& md = iMap->second;
173 
174  if(md.fRunNumbers.count(run) == 0)
175  md.fRunNumbers.insert(run);
176  if(md.fSubRunNumbers.count(subrun) == 0)
177  md.fSubRunNumbers.insert(subrun);
178  if(md.fEventCount == 0)
179  md.fFirstEvent = event;
180  md.fLastEvent = event;
181  ++md.fEventCount;
182  if(!fLastInputFile.empty() && md.fParents.count(fLastInputFile) == 0)
183  md.fParents.insert(fLastInputFile);
184  }
185 }
186 
187 //--------------------------------------------------------------------
188 // PostOpenOutputFile callback.
190 {
191  // Add initial per-file metadata for this output file.
192 
193  if(fPerFileMetadataMap.count(fn) != 0)
194  throw cet::exception("FileCatalogMetadataExtras")
195  << "Output file " << fn << " already has metadata.\n";
196  PerFileMetadata md;
197  md.fStartTime = time(0);
198  md.fEndTime = md.fStartTime;
199 
200  // Extract data from current input file.
201 
202  if(fLastInputFile.size() != 0) {
203  md.fParents.insert(fLastInputFile);
204 
205  if(isArtFile(fLastInputFile) && fCopyMetadataAttributes.size() != 0) {
206 
207  // Open sqlite database from input file.
208 
209  TFile* file = TFile::Open(fLastInputFile.c_str(), "READ");
210  if(file != 0 && !file->IsZombie() && file->IsOpen()) {
211 
212  // Open the sqlite datatabase.
213 
214  art::SQLite3Wrapper sqliteDB(file, "RootFileDB");
215  if(sqliteDB) {
216 
217  // Construct query to read all sam metadata.
218 
219  sqlite3_stmt *stmt = 0;
220  int ok = sqlite3_prepare_v2(sqliteDB, "SELECT Name, Value FROM FileCatalog_metadata;",
221  -1, &stmt, NULL);
222 
223  // Above statement will return an error if this art file doesn't
224  // contain sam metadata.
225 
226  if(ok == SQLITE_OK) {
227 
228  // Loop over all rows returned by query.
229 
230  while((ok = sqlite3_step(stmt)) == SQLITE_ROW) {
231 
232  // Reinterpret cast below is necessary because return
233  // type from sqlite3_colum_text is const unsigned char*,
234  // which has no automatic conversion to const char*.
235 
236  std::string name =
237  std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)));
238  std::string value =
239  std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1)));
240 
241  // Loop over copy attributes. Add any matching names to
242  // general per-file metadata.
243 
244  for(auto const& attr : fCopyMetadataAttributes) {
245  if(name == attr)
246  md.fNVPairs.insert(std::pair<std::string, std::string>(name, value));
247  }
248  }
249  sqlite3_finalize(stmt);
250  }
251  }
252  }
253  }
254  }
255 
256  fPerFileMetadataMap[fn] = md;
257 }
258 
259 //--------------------------------------------------------------------
260 // PostCloseOutputFile callback.
262 {
263  const std::string& fn = finfo.fileName();
264 
265  // Update metadata for this output file.
266 
267  addPerFileMetadata(fn);
268 
269  // Rename output file.
270 
271  renameOutputFile(fn);
272 }
273 
274 //--------------------------------------------------------------------
275 // Check whether the specified file is a readable art file.
276 // Do this by opening the file and checking whether it contains
277 // a RootFileDB object.
279 {
280  bool result = false;
281  if(fn.size() != 0) {
282 
283  // Try to open the file for reading.
284  // Apparently, TFile will sometimes throw an exception.
285 
286  TFile* file = 0;
287  try {
288  file = TFile::Open(fn.c_str(), "READ");
289  }
290  catch (...) {
291  file = 0;
292  }
293 
294  if(file != 0 && !file->IsZombie() && file->IsOpen()) {
295 
296  // File successfully opened.
297  // Check whether the file contains a RootFileDB object.
298 
299  TKey* key = file->GetKey("RootFileDB");
300  if(key != 0)
301  result = true;
302  }
303 
304  // Close file.
305 
306  if(file != 0) {
307  if(file->IsOpen())
308  file->Close();
309  delete file;
310  }
311  }
312 
313  // Done.
314 
315  return result;
316 }
317 
318 //--------------------------------------------------------------------
319 // Check output files.
321 {
322  // In this method we generate pseudo-callbacks for opening and
323  // closing output files. We have to do it this way, because the art
324  // ActivityRegistry doesn't currently support callbacks for output
325  // files.
326 
327  // We can skip all of this stuff if we have not been asked to
328  // generate per-file metadata.
329 
331  return;
332 
333  // Get a sorted list of currently open output files.
334 
335  std::vector<std::string> output_files;
336  TIter next(gROOT->GetListOfFiles());
337  while(TFile* file = (TFile*)next()) {
338  if(file->GetBytesWritten() > 0)
339  output_files.push_back(file->GetName());
340  }
341  std::sort(output_files.begin(), output_files.end());
342 
343  // Compare current output files with previously known output files.
344 
345  std::vector<std::string> opened_files(output_files.size());
346  std::vector<std::string> closed_files(fOutputFiles.size());
348  it = std::set_difference(output_files.begin(), output_files.end(),
349  fOutputFiles.begin(), fOutputFiles.end(),
350  opened_files.begin());
351  opened_files.resize(it - opened_files.begin());
352  it = std::set_difference(fOutputFiles.begin(), fOutputFiles.end(),
353  output_files.begin(), output_files.end(),
354  closed_files.begin());
355  closed_files.resize(it - closed_files.begin());
356 
357  // Generate pseudo-callbacks for opened and closed output files.
358  // As of art v1_08_00, callbacks for closed output files are provided
359  // by art ActivityRegistry.
360 
361  for(auto const& of : opened_files)
362  postOpenOutputFile(of);
363 
364  // Update list of open output files.
365 
366  fOutputFiles.swap(output_files);
367 }
368 
369 //--------------------------------------------------------------------
370 // Check output files.
372 {
373  // Do nothing if generating per-file metadata is disabled.
374 
376  return;
377 
378  // Do nothing if this is not an art file (not an error).
379 
380  if(!isArtFile(fn))
381  return;
382 
383  // Locate metadata.
384  // If we don't have metadata for this file in the metadata map,
385  // look for a renamed (non-existing) file.
386 
387  std::string map_fn = fn;
388  if(fPerFileMetadataMap.count(map_fn) == 0) {
389  std::vector<std::string> renamed_files;
390  for(auto const& map_ele : fPerFileMetadataMap) {
391  std::string filename = map_ele.first;
392  std::ifstream file(filename);
393  if(file.good() && file.is_open())
394  file.close();
395  else
396  renamed_files.push_back(filename);
397  }
398 
399  if(renamed_files.size() == 1)
400  map_fn = renamed_files.front();
401  else {
402  throw cet::exception("FileCatalogMetadataExtras")
403  << "Could not access metadata because there is more than one renamed output file.\n";
404  }
405  }
406  if(map_fn != fn) {
407  mf::LogInfo info("FileCatalogMetadataExtras");
408  info << "No metadata for file " << fn
409  << "\nUsing renamed file " << map_fn << " metadata instead.";
410  }
411 
412  if(fPerFileMetadataMap.count(map_fn) == 0)
413  throw cet::exception("FileCatalogMetadataExtras")
414  << "No metadata found for file " << map_fn << ".\n";
415  PerFileMetadata& md = fPerFileMetadataMap[map_fn];
416 
417  // Update end time.
418 
419  md.fEndTime = time(0);
420 
421  // Update sam metadata in root file.
422  // Open exsiting root file for update.
423 
424  TFile* file = TFile::Open(fn.c_str(), "UPDATE");
425  if(file != 0 && !file->IsZombie() && file->IsOpen()) {
426 
427  // Open the sqlite datatabase.
428 
429  art::SQLite3Wrapper sqliteDB(file, "RootFileDB");
430  if(sqliteDB) {
431 
432  // Sqlite database inside art file successfully opened.
433  //
434  // Before attempting to add per-file sam metadata, test
435  // whether the FileCatalog_metadata table exists. It is
436  // normal for the FileCatalog_metadata table to not exist,
437  // since generating sam metadata is optional.
438 
439  art::SQLErrMsg errMsg;
440  sqlite3_exec(sqliteDB, "BEGIN TRANSACTION;", 0, 0, errMsg);
441  sqlite3_stmt *stmt = 0;
442  int ok = sqlite3_prepare_v2(sqliteDB, "SELECT 1 FROM FileCatalog_metadata;",
443  -1, &stmt, NULL);
444  if(ok == SQLITE_OK) {
445  sqlite3_step(stmt);
446  ok = sqlite3_finalize(stmt);
447  }
448  if(ok == SQLITE_OK) {
449 
450  // Now we have verified that the sqlite database in this art
451  // file contqains a FileCatalog_metadata table.
452 
453  // Convert our per-file metadata to name-value pairs.
454 
455  std::multimap<std::string, std::string> mdmap;
456  md.fillMetadata(mdmap);
457 
458  // Insert metadata into sqlite database.
459  // This loop is basically copied exactly from RootOutputFile.cc.
460 
461  sqlite3_prepare_v2(sqliteDB,
462  "INSERT INTO FileCatalog_metadata(Name, Value) VALUES(?, ?);",
463  -1, &stmt, NULL);
464  sqlite3_stmt *delete_stmt = 0;
465  sqlite3_prepare_v2(sqliteDB,
466  "DELETE FROM FileCatalog_metadata WHERE Name=?;",
467  -1, &delete_stmt, NULL);
468  std::string lastName;
469  for ( auto const & nvp : mdmap ) {
470  std::string const & theName (nvp.first);
471  std::string const & theValue (nvp.second);
472 
473  // On the first occurrence of each per-file metadata name,
474  // delete any existing (per-job) metadata with the same
475  // name.
476 
477  if(theName != lastName) {
478  lastName = theName;
479  if(theName.size() != 0) {
480  sqlite3_bind_text(delete_stmt, 1, theName.c_str(),
481  theName.size() + 1, SQLITE_STATIC);
482  sqlite3_step(delete_stmt);
483  sqlite3_reset(delete_stmt);
484  sqlite3_clear_bindings(delete_stmt);
485  }
486  }
487  sqlite3_bind_text(stmt, 1, theName.c_str(),
488  theName.size() + 1, SQLITE_STATIC);
489  sqlite3_bind_text(stmt, 2, theValue.c_str(),
490  theValue.size() + 1, SQLITE_STATIC);
491  sqlite3_step(stmt);
492  sqlite3_reset(stmt);
493  sqlite3_clear_bindings(stmt);
494  }
495  sqlite3_finalize(stmt);
496  sqlite3_finalize(delete_stmt);
497  sqlite3_exec(sqliteDB, "END TRANSACTION;", 0, 0, errMsg);
498  }
499  else {
500 
501  // The else clause is reached if there is no
502  // FileCatalog_metadata table.
503 
504  sqlite3_exec(sqliteDB, "ROLLBACK TRANSACTION;", 0, 0, errMsg);
505  }
506  errMsg.throwIfError();
507  }
508  }
509 
510  // Close (possibly updated) root file.
511 
512  if(file != 0) {
513  if(file->IsOpen())
514  file->Close();
515  delete file;
516  }
517 
518  // Delete the metadata we used from the metadata map, so we don't
519  // accidentally use it again.
520 
521  fPerFileMetadataMap.erase(map_fn);
522 }
523 
524 //--------------------------------------------------------------------
525 // Convert per-file metadata to name-value pairs.
527 fillMetadata(std::multimap<std::string, std::string>& md)
528 {
529  for(auto run : fRunNumbers) {
530  std::ostringstream ostr;
531  ostr << run;
532  md.insert(std::pair<std::string, std::string>("run", ostr.str()));
533  }
534  for(auto subrun : fSubRunNumbers) {
535  std::ostringstream ostr;
536  ostr << subrun;
537  md.insert(std::pair<std::string, std::string>("subRun", ostr.str()));
538  }
539  {
540  std::ostringstream ostr;
541  ostr << fFirstEvent;
542  md.insert(std::pair<std::string, std::string>("firstEvent", ostr.str()));
543  }
544  {
545  std::ostringstream ostr;
546  ostr << fLastEvent;
547  md.insert(std::pair<std::string, std::string>("lastEvent", ostr.str()));
548  }
549  {
550  std::ostringstream ostr;
551  ostr << fEventCount;
552  md.insert(std::pair<std::string, std::string>("eventCount", ostr.str()));
553  }
554  {
555  std::ostringstream ostr;
556  ostr << fStartTime;
557  md.insert(std::pair<std::string, std::string>("startTime", ostr.str()));
558  }
559  {
560  std::ostringstream ostr;
561  ostr << fEndTime;
562  md.insert(std::pair<std::string, std::string>("endTime", ostr.str()));
563  }
564  for(auto parent : fParents) {
565  size_t n = parent.find_last_of('/');
566  size_t f = (n == std::string::npos ? 0 : n+1);
567  md.insert(std::pair<std::string, std::string>("parent", parent.substr(f)));
568  }
569  for(auto const& nvp : fNVPairs)
570  md.insert(nvp);
571 }
572 
573 //--------------------------------------------------------------------
574 // Rename the specified file according to template specified via
575 // fcl parameter fRenameTemplate.
577 {
578  // If the rename template is an empty string, do nothing.
579 
580  if(fRenameTemplate.size() == 0)
581  return;
582 
583  // Make sure the original file is a readable art file.
584  // Do nothing if it is not (not an error).
585 
586  if(isArtFile(fn)) {
587 
588  // Expand the output template.
589 
590  std::string new_fn = expandTemplate();
591  if(new_fn.size() != 0) {
592 
593  // Test whether a file with the new name already exists.
594  // If file does exist, action depends on value of fRenameOverwrite
595  // parameter.
596 
597  bool do_rename = false;
598  std::ifstream file(new_fn);
599  if(file.good()) {
600  if(fRenameOverwrite) {
601 
602  // File exists, but overwriting is enabled.
603  // Delete the existing file and proceed with renaming.
604 
605  remove(new_fn.c_str());
606  do_rename = true;
607  }
608  else {
609 
610  // File exists, and overwriting is not enabled.
611  // Print a warning and do not rename.
612 
613  mf::LogWarning("FileCatalogMetadataExtras")
614  << "Rename failed because a file already exists with name " << new_fn << std::endl;
615  do_rename = false;
616  }
617  }
618  else {
619 
620  // Target file does not exist. Proceed with rename.
621 
622  do_rename = true;
623  }
624 
625  // Do the rename.
626 
627  if(do_rename) {
628  mf::LogInfo("FileCatalogMetadataExtras")
629  << "Renaming " << fn << " to " << new_fn << std::endl;
630  rename(fn.c_str(), new_fn.c_str());
631  }
632  }
633 
634  // Increment output file count (only count art files).
635 
637  }
638 }
639 
640 //--------------------------------------------------------------------
641 // Convert the output file name template to an actual file name.
643 {
644  // Make a copy of the template that we can modify, which will be
645  // the eventual return value.
646 
647  std::string filename = fRenameTemplate;
648 
649  // If template doesn't contain any ${...} expressions, stick the
650  // field "${bnum 0} before the file extension.
651 
652  if(filename.find_first_of("${}") == std::string::npos) {
653  size_t n = filename.find_last_of('.');
654  if(n == std::string::npos)
655  n = filename.size();
656  std::string head = filename.substr(0, n);
657  std::string tail = filename.substr(n);
658  filename = head + std::string("${bnum 0}") + tail;
659  }
660 
661  // Get the current system time (for ${date} ane ${time}).
662 
663  time_t curtime = time(0);
664 
665  // Parse file name, looking for ${...} expressions. We assume these
666  // expressions are not nested, and can be evaluated in any order.
667  // The text inside the braces, can be either a) a keyword plus
668  // arguments, or b) an environment variable. If neither is the case,
669  // a warning is printed and the value of the subargument, if any,
670  // is substituted.
671 
672  size_t f = 0;
673  while((f = filename.find("${")) != std::string::npos) {
674 
675  // Find closing brace. Throw exception in case of problem.
676 
677  size_t n = filename.substr(f).find("}");
678  if(n == std::string::npos)
679  throw cet::exception("FileCatalogMetadataExtras")
680  << "Output file name template: " << filename
681  << " has mismatched braces.\n";
682 
683  // Split current filename into three pieces: head, argument of current
684  // ${...}, and tail.
685 
686  std::string head = filename.substr(0, f);
687  std::string arg = filename.substr(f+2, n-2);
688  std::string tail = filename.substr(f+n+1);
689 
690  // Make sure that the head and argument string don't contain
691  // any of the reserved characters ${}. This check catches
692  // nested ${...} expressions, mismatched braces, and
693  // other typos.
694 
695  if(head.find_first_of("${}") != std::string::npos ||
696  arg.find_first_of("${}") != std::string::npos)
697  throw cet::exception("FileCatalogMetadataExtras")
698  << "Problem parsing output file name template: " << filename << ".\n";
699 
700  // Extract the first and second word out of the argument string,
701  // which we interpret as keyword and subargument.
702 
703  std::string keyword;
704  std::string subarg;
705  {
706  std::istringstream istr(arg);
707  istr >> keyword;
708  istr >> subarg;
709  }
710 
711  // Do interpretation of keyword and subargument.
712 
713  std::string expanded;
714  if(keyword == "base") {
715 
716  // Base name of input file.
717 
718  size_t n = fLastInputFile.find_last_of('/');
719  size_t f = (n == std::string::npos ? 0 : n+1);
720  expanded = fLastInputFile.substr(f);
721  if(subarg.size() != 0 && expanded.rfind(subarg) == expanded.size() - subarg.size())
722  expanded = expanded.substr(0, expanded.size() - subarg.size());
723  }
724  else if(keyword == "dir") {
725 
726  // Directory part of path.
727  // If path doesn't include a directory, expand to ".".
728 
729  size_t n = fLastInputFile.find_last_of('/');
730  if(n != std::string::npos)
731  expanded = fLastInputFile.substr(0, n);
732  else
733  expanded = ".";
734  }
735  else if(keyword == "path") {
736 
737  // Full input file path.
738 
739  expanded = fLastInputFile;
740  if(subarg.size() != 0 && expanded.rfind(subarg) == expanded.size() - subarg.size())
741  expanded = expanded.substr(0, expanded.size() - subarg.size());
742  }
743  else if(keyword == "num") {
744 
745  // Output file count.
746  // Note that outputFileCount_ is incremented after this method is called,
747  // so outputFileCount_ is zero on the first call.
748  // Use the subargument to define an offset.
749 
750  unsigned int offset = 1;
751  if(subarg.size() != 0) {
752  std::istringstream istr(subarg);
753  istr >> offset;
754  }
755  std::ostringstream ostr;
756  ostr << fOutputFileCount + offset;
757  expanded = ostr.str();
758  }
759  else if(keyword == "bnum") {
760 
761  // Output file count.
762  // Same as "num," except expands to empty string for first file.
763 
764  unsigned int offset = 1;
765  if(subarg.size() != 0) {
766  std::istringstream istr(subarg);
767  istr >> offset;
768  }
769  if(fOutputFileCount > 0) {
770  std::ostringstream ostr;
771  ostr << fOutputFileCount + offset;
772  expanded = ostr.str();
773  }
774  }
775  else if(keyword == "date") {
776 
777  // Date formatted as YYYYMMDD in local time zone.
778 
779  struct tm ts;
780  struct tm* pts = 0;
781  pts = localtime_r(&curtime, &ts);
782  if(pts) {
783  std::ostringstream ostr;
784  ostr << std::setw(4) << std::setfill('0') << pts->tm_year + 1900
785  << std::setw(2) << pts->tm_mon + 1
786  << std::setw(2) << pts->tm_mday;
787  expanded = ostr.str();
788  }
789  else {
790 
791  // localtime call failed.
792 
793  expanded = "00000000";
794  }
795  }
796  else if(keyword == "time") {
797 
798  // Time of day formatted as HHMMSS in local time zone.
799 
800  struct tm ts;
801  struct tm* pts = 0;
802  pts = localtime_r(&curtime, &ts);
803  if(pts) {
804  std::ostringstream ostr;
805  ostr << std::setw(2) << std::setfill('0') << pts->tm_hour
806  << std::setw(2) << pts->tm_min
807  << std::setw(2) << pts->tm_sec;
808  expanded = ostr.str();
809  }
810  else {
811 
812  // localtime call failed.
813 
814  expanded = "000000";
815  }
816  }
817  else {
818 
819  // If we get here, the keyword is not known.
820  // Try to interpret the keyword as an environment variable.
821 
822  const char* p = getenv(keyword.c_str());
823  if(p != 0 && *p != 0)
824  expanded = p;
825  else {
826 
827  // Environment variable not defined.
828 
829  mf::LogWarning("FileCatalogMetadataExtras")
830  << "Unknown keyword " << keyword
831  << " in output file name template " << filename << ".\n";
832  expanded = subarg;
833  }
834  }
835 
836  // Make sure no reserved characters made it into the expanded argument.
837  // This ensures we can't get into an infinite loop.
838 
839  if(expanded.find_first_of("${}") != std::string::npos)
840  throw cet::exception("FileCatalogMetadataExtras")
841  << "Problem parsing output file name template: " << filename << ".\n";
842 
843  // Reassemble file name.
844 
845  filename = head + expanded + tail;
846  }
847 
848  // Make sure that the finished file name doesn't contain
849  // reserved characters ${}.
850 
851  if(filename.find_first_of("${}") != std::string::npos)
852  throw cet::exception("FileCatalogMetadataExtras")
853  << "Problem parsing output file name template: "<< filename << ".\n";
854  return filename;
855 }
856 
857 namespace util{
858 
860 
861 } // namespace util
SubRunNumber_t subRun() const
Definition: Event.h:72
Namespace for general, non-LArSoft-specific utilities.
Definition: PIDAAlg.h:17
std::vector< std::pair< std::string, std::string >> collection_type
GlobalSignal< detail::SignalResponseType::FIFO, void()> sPostBeginJob
intermediate_table::iterator iterator
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
#define DEFINE_ART_SERVICE(svc)
Definition: ServiceMacros.h:93
GlobalSignal< detail::SignalResponseType::LIFO, void()> sPostEndJob
void reconfigure(fhicl::ParameterSet const &p)
void postCloseOutputFile(art::OutputFileInfo const &finfo)
std::vector< std::string > fOutputFiles
TFile f
Definition: plotHisto.C:6
std::multimap< std::string, std::string > fNVPairs
void fillMetadata(std::multimap< std::string, std::string > &md)
std::string const & fileName() const
static bool isArtFile(std::string const &fn)
std::vector< std::string > fCopyMetadataAttributes
std::map< std::string, PerFileMetadata > fPerFileMetadataMap
T get(std::string const &key) const
Definition: ParameterSet.h:231
IDNumber_t< Level::SubRun > SubRunNumber_t
Definition: IDNumber.h:118
EventNumber_t event() const
Definition: Event.h:67
std::multimap< std::string, std::string > fPerJobMetadata
std::string value(boost::any const &)
GlobalSignal< detail::SignalResponseType::FIFO, void(Event const &)> sPreProcessEvent
GlobalSignal< detail::SignalResponseType::LIFO, void(std::string const &)> sPostOpenFile
TFile * file
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
IDNumber_t< Level::Event > EventNumber_t
Definition: IDNumber.h:117
void addMetadata(std::string const &key, std::string const &value)
GlobalSignal< detail::SignalResponseType::LIFO, void(OutputFileInfo const &)> sPostCloseOutputFile
Char_t n[5]
GlobalSignal< detail::SignalResponseType::LIFO, void(Event const &)> sPostProcessEvent
void throwIfError()
Definition: SQLErrMsg.cc:10
GlobalSignal< detail::SignalResponseType::LIFO, void()> sPostCloseFile
RunNumber_t run() const
Definition: Event.h:77
void getMetadata(collection_type &coll) const
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
Event finding and building.
FileCatalogMetadataExtras(fhicl::ParameterSet const &pset, art::ActivityRegistry &reg)
IDNumber_t< Level::Run > RunNumber_t
Definition: IDNumber.h:119