LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
FileCatalogOptionsHandler.cc
Go to the documentation of this file.
2 
7 #include "cetlib/split.h"
8 #include "fhiclcpp/coding.h"
11 #include "fhiclcpp/parse.h"
12 
13 #include <iostream>
14 #include <iterator>
15 #include <string>
16 #include <vector>
17 
21 using string_pair_t = std::pair<std::string const, std::string>;
22 using std::string;
23 using std::vector;
24 
25 namespace {
26 
28  split_to_pair(string const& to_split)
29  {
30  vector<string> tmp;
31  tmp.reserve(2);
32  cet::split(to_split, ':', std::back_inserter(tmp));
33  switch (tmp.size()) {
34  case 0:
35  return string_pair_t();
36  case 1:
37  return string_pair_t(string("_default"), std::move(tmp[0]));
38  case 2:
39  return string_pair_t(std::move(tmp[0]), std::move(tmp[1]));
40  default:
42  << "Expected \"key:value\", got multiple \":\".\n";
43  }
44  }
45 
46  void
47  check_metadata_options(bpo::variables_map const& vm)
48  {
49  auto check_for_conflicting_options =
50  [&vm](string const& firstOpt, std::initializer_list<string> opts) {
51  for (auto const& opt : opts) {
52  if (vm.count(opt) + vm.count(firstOpt) > 1)
54  << "The options '--" << opt << "' and '--" << firstOpt
55  << "' are mutually exclusive.";
56  }
57  };
58 
59  check_for_conflicting_options(
60  "sam-file-type", {"sam-inherit-metadata", "sam-inherit-file-type"});
61  check_for_conflicting_options(
62  "sam-run-type", {"sam-inherit-metadata", "sam-inherit-run-type"});
63  }
64 
65  void
66  fill_tiers_streams(bpo::variables_map const& vm,
67  fhicl::intermediate_table& raw_config)
68  {
69  // Precondition: at least one output module defined in the
70  // configuration.
71  auto const& table = raw_config.get<table_t const&>("outputs");
72  string const outputs_stem{"outputs"};
73  string const tier_spec_stem{"dataTier"};
74  string const stream_name_stem{"streamName"};
75  vector<string> data_tiers((vm.count("sam-data-tier") > 0) ?
76  vm["sam-data-tier"].as<vector<string>>() :
77  vector<string>());
78  vector<string> stream_names((vm.count("sam-stream-name") > 0) ?
79  vm["sam-stream-name"].as<vector<string>>() :
80  vector<string>());
81  std::map<string, string> sep_tiers, sep_streams;
82  for (auto const& tier : data_tiers) {
83  sep_tiers.insert(split_to_pair(tier));
84  }
85  for (auto const& stream : stream_names) {
86  sep_streams.insert(split_to_pair(stream));
87  }
88  auto const def_tier_it(sep_tiers.find("_default"));
89  auto const def_tier((def_tier_it != sep_tiers.end()) ? def_tier_it->second :
90  "");
91  auto const def_stream_it(sep_streams.find("_default"));
92  auto const def_stream(
93  (def_stream_it != sep_streams.end()) ? def_stream_it->second : "");
94  for (auto const& output : table) {
96  raw_config, fhicl_key(outputs_stem, output.first, "module_type"))) {
97  continue; // Not a module parameter set.
98  }
99  auto const& tier_spec_key =
100  fhicl_key(outputs_stem, output.first, tier_spec_stem);
101  auto const& stream_name_key =
102  fhicl_key(outputs_stem, output.first, stream_name_stem);
103  auto tiers_it(sep_tiers.find(output.first));
104  string tier;
105  if (tiers_it != sep_tiers.end()) {
106  tier = tiers_it->second;
107  } else if (!exists_outside_prolog(raw_config, tier_spec_key)) {
108  tier = def_tier;
109  }
110  if (!tier.empty()) {
111  raw_config.put(tier_spec_key, tier);
112  }
113  auto streams_it(sep_streams.find(output.first));
114  string stream;
115  if (streams_it != sep_streams.end()) {
116  stream = streams_it->second;
117  } else if (!exists_outside_prolog(raw_config, stream_name_key)) {
118  stream = (!def_stream.empty()) ? def_stream : output.first;
119  }
120  if (!stream.empty()) {
121  raw_config.put(stream_name_key, stream);
122  }
123  if (raw_config.get<string>(fhicl_key(
124  outputs_stem, output.first, "module_type")) == "RootOutput") {
125  if (!(exists_outside_prolog(raw_config, tier_spec_key) &&
126  exists_outside_prolog(raw_config, stream_name_key))) {
128  << "Output \"" << output.first << "\" must be configured with "
129  << tier_spec_stem << " (--sam-data-tier=" << output.first
130  << ":<tier>) and " << stream_name_stem
131  << " (--sam-stream-name=" << output.first << ":<stream>).\n";
132  }
133  }
134  }
135  }
136 
137  bool
138  have_outputs(fhicl::intermediate_table& table)
139  {
140  bool result{false};
141  if (exists_outside_prolog(table, "outputs")) {
142  auto const& ev = table.find("outputs");
143  if (ev.is_a(fhicl::TABLE) &&
144  !table.get<fhicl::extended_value::table_t const&>("outputs")
145  .empty()) {
146  result = true;
147  }
148  }
149  return result;
150  }
151 
152  void
153  maybeThrowOnMissingMetadata(fhicl::intermediate_table const& table)
154  {
155  string const key_stem{"services.FileCatalogMetadata."};
156  vector<string> missingItems;
157  if (!exists_outside_prolog(table, key_stem + "applicationFamily")) {
158  missingItems.emplace_back(key_stem +
159  "applicationFamily (--sam-application-family)");
160  }
161  if (!exists_outside_prolog(table, key_stem + "applicationVersion")) {
162  missingItems.emplace_back(
163  key_stem + "applicationVersion (--sam-application-version)");
164  }
165  if (!exists_outside_prolog(table, key_stem + "group")) {
166  missingItems.emplace_back(key_stem + "group (--sam-group)");
167  }
168  if (!missingItems.empty()) {
170  e << "SAM metadata information is required -- missing metadata:\n";
171  for (auto const& s : missingItems) {
172  e << s << "\n";
173  }
174  }
175  }
176 
177 } // namespace
178 
180  bpo::options_description& desc)
181  : appFamily_{}, appVersion_{}
182 {
183  bpo::options_description sam_options{"SAM options"};
184  auto options = sam_options.add_options();
185  add_opt(
186  options, "sam-web-uri", bpo::value<string>(), "URI for SAM web service.");
187  add_opt(options, "sam-process-id", bpo::value<string>(), "SAM process ID.");
188  add_opt(options,
189  "sam-application-family",
190  bpo::value<string>(&appFamily_),
191  "SAM application family.");
192  add_opt(options,
193  "sam-app-family",
194  bpo::value<string>(&appFamily_),
195  "SAM application family.");
196  add_opt(options,
197  "sam-application-version",
198  bpo::value<string>(&appVersion_),
199  "SAM application version.");
200  add_opt(options,
201  "sam-app-version",
202  bpo::value<string>(&appVersion_),
203  "SAM application version.");
204  add_opt(options, "sam-group", bpo::value<string>(), "SAM group.");
205  add_opt(options,
206  "sam-file-type",
207  bpo::value<string>(),
208  "File type for SAM metadata.");
209  add_opt(options,
210  "sam-data-tier",
211  bpo::value<vector<string>>(),
212  "SAM data tier (<spec-label>:<tier-spec>).");
213  add_opt(options,
214  "sam-run-type",
215  bpo::value<string>(),
216  "Global run-type for SAM metadata.");
217  add_opt(options,
218  "sam-stream-name",
219  bpo::value<vector<string>>(),
220  "SAM stream name (<module-label>:<stream-name>).");
221  add_opt(options,
222  "sam-inherit-metadata",
223  "Input file provides the file type and run type.");
224  add_opt(
225  options, "sam-inherit-file-type", "Input file provides the file type.");
226  add_opt(options, "sam-inherit-run-type", "Input file provides the run type.");
227  desc.add(sam_options);
228 }
229 
230 int
232 {
233  // Checks can't be done until after post-processing.
234  return 0;
235 }
236 
237 int
239  bpo::variables_map const& vm,
240  fhicl::intermediate_table& raw_config)
241 {
242  std::string const services{"services"};
243  auto const& ciLocation = fhicl_key(services, "CatalogInterface");
244  auto const& ftLocation = fhicl_key(services, "FileTransfer");
245  auto const& fcmdLocation = fhicl_key(services, "FileCatalogMetadata");
246 
248  // Load up the configuration with command-line options.
249  //
250  // sam-web-uri and sam-process-id.
251  if (vm.count("sam-web-uri") > 0) {
252  raw_config.put(fhicl_key(ciLocation, "webURI"),
253  vm["sam-web-uri"].as<string>());
254  }
255  if (vm.count("sam-process-id") > 0) {
256  // Sequence.
257  raw_config.put("source.fileNames",
258  vector<string>{vm["sam-process-id"].as<string>()});
259  // Atom.
260  raw_config.put(fhicl_key(fcmdLocation, "processID"),
261  vm["sam-process-id"].as<string>());
262  }
263  if (exists_outside_prolog(raw_config, fhicl_key(ciLocation, "webURI")) !=
265  raw_config, fhicl_key(fcmdLocation, "processID"))) { // Inconsistent.
267  << "configurations " << fhicl_key(ciLocation, "webURI")
268  << " (--sam-web-uri) and\n"
269  << fhicl_key(fcmdLocation, "processID")
270  << " (--sam-process-id) must be specified\n"
271  << "together or not at all.\n";
272  }
273  bool const wantSAMweb{
274  exists_outside_prolog(raw_config, fhicl_key(ciLocation, "webURI")) &&
275  exists_outside_prolog(raw_config, "source.fileNames")};
276  // Other metadata items.
277  if (!appFamily_.empty()) {
278  raw_config.put(fhicl_key(fcmdLocation, "applicationFamily"), appFamily_);
279  }
280  if (vm.count("sam-group") > 0) {
281  raw_config.put(fhicl_key(fcmdLocation, "group"),
282  vm["sam-group"].as<string>());
283  }
284  if (!appVersion_.empty()) {
285  raw_config.put(fhicl_key(fcmdLocation, "applicationVersion"), appVersion_);
286  }
287 
288  check_metadata_options(vm);
289 
290  string const mdFromInput{"metadataFromInput"};
291  bool specifyDataTier{false}; // The output module needs a
292  // 'dataTier' if "fileType" is
293  // provided either by the input file
294  // or as a configuration parameter.
295  if (vm.count("sam-inherit-metadata") > 0) {
296  raw_config.put(fhicl_key(fcmdLocation, mdFromInput),
297  vector<string>{"fileType", "runType"});
298  specifyDataTier = true;
299  raw_config.erase(fhicl_key(fcmdLocation, "fileType"));
300  raw_config.erase(fhicl_key(fcmdLocation, "runType"));
301  } else {
302  vector<string> md;
303  if (vm.count("sam-inherit-file-type") > 0) {
304  md.emplace_back("fileType");
305  specifyDataTier = true;
306  raw_config.erase(fhicl_key(fcmdLocation, "fileType"));
307  }
308  if (vm.count("sam-inherit-run-type") > 0) {
309  md.emplace_back("runType");
310  raw_config.erase(fhicl_key(fcmdLocation, "runType"));
311  }
312  if (!md.empty()) {
313  raw_config.put(fhicl_key(fcmdLocation, mdFromInput), md);
314  }
315  }
316 
317  if (vm.count("sam-run-type") > 0) {
318  raw_config.put(fhicl_key(fcmdLocation, "runType"),
319  vm["sam-run-type"].as<string>());
320  }
321  if (vm.count("sam-file-type") > 0) {
322  raw_config.put(fhicl_key(fcmdLocation, "fileType"),
323  vm["sam-file-type"].as<string>());
324  }
325  bool const requireMetadata =
326  have_outputs(raw_config) &&
327  (wantSAMweb ||
328  exists_outside_prolog(raw_config,
329  fhicl_key(fcmdLocation, "applicationFamily")) ||
330  exists_outside_prolog(raw_config,
331  fhicl_key(fcmdLocation, "applicationVersion")) ||
332  exists_outside_prolog(raw_config, fhicl_key(fcmdLocation, "group")) ||
333  exists_outside_prolog(raw_config, fhicl_key(fcmdLocation, "fileType")) ||
334  specifyDataTier);
335 
336  if (requireMetadata) {
337  fill_tiers_streams(vm, raw_config);
338  maybeThrowOnMissingMetadata(raw_config);
339  }
340 
341  string process_name;
342  if (exists_outside_prolog(raw_config, "process_name")) {
343  process_name = raw_config.get<string>("process_name");
344  }
345  if (requireMetadata && process_name.empty()) {
347  << "Non-empty / default process_name required for SAM metadata.\n";
348  }
349  if (wantSAMweb) {
350  raw_config.put(fhicl_key(ciLocation, "service_provider"),
351  "IFCatalogInterface");
352  raw_config.put(fhicl_key(ftLocation, "service_provider"), "IFFileTransfer");
353  art::ensureTable(raw_config, fhicl_key(services, "IFDH"));
354  }
355  return 0;
356 }
Float_t s
Definition: plot.C:23
FileCatalogOptionsHandler(bpo::options_description &desc)
bool exists_outside_prolog(fhicl::intermediate_table const &config, std::string const &key)
void add_opt(T &t, Args &&...args)
int doProcessOptions(bpo::variables_map const &vm, fhicl::intermediate_table &raw_config) override
int doCheckOptions(bpo::variables_map const &vm) override
Float_t tmp
Definition: plot.C:37
void erase(std::string const &name, bool in_prolog=false)
void ensureTable(fhicl::intermediate_table &table, std::string const &fhicl_spec)
Definition: ensureTable.cc:6
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
shims::map< std::string, extended_value > table_t
extended_value const & find(std::string const &name) const
bool put(std::string const &name, std::string const &value, bool in_prolog=false)
std::enable_if_t< std::is_convertible< T, std::string >::value, std::string > fhicl_key(T const &name)
Definition: fhicl_key.h:13
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
std::string value(boost::any const &)
T get(std::string const &name)
Float_t e
Definition: plot.C:34
std::pair< std::string const, std::string > string_pair_t