CMS 3D CMS Logo

ConfigurationDescriptions.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: ParameterSet
4 // Class : ConfigurationDescriptions
5 //
6 // Implementation:
7 // <Notes on implementation>
8 //
9 // Original Author: W. David Dagenhart
10 // Created: 17 December 2008
11 //
12 
18 
19 #include <fstream>
20 #include <iostream>
21 #include <iomanip>
22 #include <sstream>
23 #include <cstring>
24 #include <cerrno>
25 #include <cstring>
26 
27 namespace {
28  void matchLabel(std::pair<std::string, edm::ParameterSetDescription> const& thePair,
29  std::string const& moduleLabel,
30  edm::ParameterSetDescription const*& psetDesc) {
31  if (thePair.first == moduleLabel) {
32  psetDesc = &thePair.second;
33  }
34  }
35 } // namespace
36 
37 static const char* const kSource = "Source";
38 static const char* const kService = "Service";
39 static const char* const k_source = "source";
40 
41 namespace edm {
42 
44  : baseType_(baseType), pluginName_(pluginName), defaultDescDefined_(false) {}
45 
47 
49 
51 
52  void ConfigurationDescriptions::add(char const* label, ParameterSetDescription const& psetDescription) {
53  std::string labelString(label);
54  add(labelString, psetDescription);
55  }
56 
58  if (0 == strcmp(baseType_.c_str(), kSource)) {
59  if (0 != strcmp(label.c_str(), k_source)) {
61  "ConfigurationDescriptions::add, when adding a ParameterSetDescription for a source the "
62  "label must be \"source\"\n");
63  }
64  if (!descriptions_.empty() || defaultDescDefined_ == true) {
65  throw edm::Exception(
67  "ConfigurationDescriptions::add, for a source only 1 ParameterSetDescription may be added\n");
68  }
69  } else if (0 == strcmp(baseType_.c_str(), kService)) {
70  if (!descriptions_.empty() || defaultDescDefined_ == true) {
71  throw edm::Exception(
73  "ConfigurationDescriptions::add, for a service only 1 ParameterSetDescription may be added\n");
74  }
75  }
76 
77  // To minimize the number of copies involved create an empty description first
78  // and push it into the vector. Then perform the copy.
79  std::pair<std::string, ParameterSetDescription> pairWithEmptyDescription;
80  descriptions_.push_back(pairWithEmptyDescription);
81  std::pair<std::string, ParameterSetDescription>& pair = descriptions_.back();
82 
83  pair.first = label;
84  pair.second = psetDescription;
85  }
86 
89  if (kService == baseType_) {
90  label = pluginName_;
91  } else if (kSource == baseType_) {
92  label = "source";
93  } else {
95  }
96  add(label, psetDescription);
97  }
98 
100  if (0 == strcmp(baseType_.c_str(), kSource) || 0 == strcmp(baseType_.c_str(), kService)) {
101  if (!descriptions_.empty() || defaultDescDefined_ == true) {
103  "ConfigurationDescriptions::addDefault, for a source or service only 1 "
104  "ParameterSetDescription may be added\n");
105  }
106  }
107 
108  defaultDescDefined_ = true;
109  defaultDesc_ = psetDescription;
110  }
111 
113  if (defaultDescDefined_) {
114  return &defaultDesc_;
115  }
116  return nullptr;
117  }
118 
120 
122 
124  ParameterSetDescription const* psetDesc = nullptr;
125  for_all(descriptions_, std::bind(&matchLabel, std::placeholders::_1, std::cref(moduleLabel), std::ref(psetDesc)));
126 
127  // If there is a matching label
128  if (psetDesc != nullptr) {
129  psetDesc->validate(pset);
130  }
131  // Is there an explicit description to be used for a non standard label
132  else if (defaultDescDefined_) {
133  defaultDesc_.validate(pset);
134  }
135  // Otherwise use the first one.
136  else if (!descriptions_.empty()) {
137  descriptions_[0].second.validate(pset);
138  }
139  // It is possible for no descriptions to be defined and no validation occurs
140  // for this module ever.
141  }
142 
143  void ConfigurationDescriptions::writeCfis(std::set<std::string>& usedCfiFileNames) const {
146  std::placeholders::_1,
147  std::cref(baseType_),
148  std::cref(pluginName_),
149  std::ref(usedCfiFileNames)));
150  }
151 
152  void ConfigurationDescriptions::writeCfiForLabel(std::pair<std::string, ParameterSetDescription> const& labelAndDesc,
153  std::string const& baseType,
154  std::string const& pluginName,
155  std::set<std::string>& usedCfiFileNames) {
156  if (0 == strcmp(baseType.c_str(), kService) && labelAndDesc.first != pluginName) {
158  "ConfigurationDescriptions::writeCfiForLabel\nFor a service the label and the plugin name "
159  "must be the same.\n")
160  << "This error is probably caused by an incorrect label being passed\nto the ConfigurationDescriptions::add "
161  "function earlier.\n"
162  << "plugin name = \"" << pluginName << "\" label name = \"" << labelAndDesc.first << "\"\n";
163  }
164 
165  std::string cfi_filename;
166  if (0 == strcmp(baseType.c_str(), kSource)) {
167  cfi_filename = pluginName + "_cfi.py";
168  } else {
169  cfi_filename = labelAndDesc.first + "_cfi.py";
170  }
171  if (!usedCfiFileNames.insert(cfi_filename).second) {
173  "Two cfi files are being generated with the same name in the same directory.\n");
174  ex << "The cfi file name is '" << cfi_filename << "' and\n"
175  << "the module label is \'" << labelAndDesc.first << "\'.\n"
176  << "This error is probably caused by an error in one or more fillDescriptions functions\n"
177  << "where duplicate module labels are being passed to the ConfigurationDescriptions::add\n"
178  << "function. All such module labels must be unique within a package.\n"
179  << "If you do not want the generated cfi file and do not need more than one\n"
180  << "description for a plugin, then a way to fix this is to use the addDefault\n"
181  << "function instead of the add function.\n"
182  << "There are 3 common ways this problem can happen.\n"
183  << "1. This can happen when a module label is explicitly duplicated in one or more\n"
184  << "fillDescriptions functions. Fix these by changing the module labels to be unique.\n"
185  << "2. This can also happen when a module class is a template class and plugins are\n"
186  << "defined by instantiations with differing template parameters and these plugins\n"
187  << "share the same fillDescriptions function. Fix these by specializing the fillDescriptions\n"
188  << "function for each template instantiation.\n"
189  << "3. This can also happen when there is an inheritance heirarchy and multiple plugin modules\n"
190  << "are defined using derived classes and the base class which share the same fillDescriptions\n"
191  << "function. Fix these by redefining the fillDescriptions function in each derived class.\n";
192  ex.addContext("Executing function ConfigurationDescriptions::writeCfiForLabel");
193  throw ex;
194  }
195  std::ofstream outFile(cfi_filename.c_str());
196  if (outFile.fail()) {
197  edm::Exception ex(edm::errors::LogicError, "Creating cfi file failed.\n");
198  ex << "Opening a file '" << cfi_filename << "' for module '" << labelAndDesc.first << "' failed.\n";
199  ex << "Error code from errno " << errno << ": " << std::strerror(errno) << "\n";
200 
201  ex.addContext("Executing function ConfigurationDescriptions::writeCfiForLabel");
202  throw ex;
203  }
204 
205  outFile << "import FWCore.ParameterSet.Config as cms\n\n";
206  outFile << labelAndDesc.first << " = cms." << baseType << "('" << pluginName << "'";
207 
208  bool startWithComma = true;
209  int indentation = 2;
210  labelAndDesc.second.writeCfi(outFile, startWithComma, indentation);
211 
212  outFile << ")\n";
213 
214  outFile.close();
215 
216  if (0 == strcmp(baseType.c_str(), kSource)) {
217  std::cout << pluginName << "\n";
218  } else {
219  std::cout << labelAndDesc.first << "\n";
220  }
221  }
222 
223  void ConfigurationDescriptions::print(std::ostream& os,
224  std::string const& moduleLabel,
225  bool brief,
226  bool printOnlyLabels,
227  size_t lineWidth,
228  int indentation,
229  int iPlugin) const {
230  if (!brief) {
231  if (!comment().empty()) {
232  DocFormatHelper::wrapAndPrintText(os, comment(), indentation, lineWidth);
233  }
234  os << "\n";
235  }
236 
237  if (descriptions_.empty() && !defaultDescDefined_) {
238  char oldFill = os.fill();
239  indentation += DocFormatHelper::offsetModuleLabel();
240  os << std::setfill(' ') << std::setw(indentation) << "";
241  os << "There are no PSet descriptions defined for this plugin.\n";
242  os << std::setfill(' ') << std::setw(indentation) << "";
243  os << "PSets will not be validated and no cfi files will be generated.\n";
244  os << std::setfill(oldFill);
245  if (!brief)
246  os << "\n";
247  return;
248  }
249 
251  indentation += DocFormatHelper::offsetModuleLabel();
252  char oldFill = os.fill();
253  os << std::setfill(' ') << std::setw(indentation) << "";
254  os << "This plugin has not implemented the function which defines its\n";
255  os << std::setfill(' ') << std::setw(indentation) << "";
256  os << "configuration descriptions yet. No descriptions are available.\n";
257  os << std::setfill(' ') << std::setw(indentation) << "";
258  os << "Its PSets will not be validated, and no cfi files will be generated.\n";
259  os << std::setfill(oldFill);
260  if (!brief)
261  os << "\n";
262  return;
263  }
264 
265  if (!brief) {
266  std::stringstream ss;
267  if (defaultDescDefined_) {
268  if (descriptions_.empty()) {
269  ss << "This plugin has only one PSet description. "
270  << "This description is always used to validate configurations. "
271  << "Because this configuration has no label, no cfi files will be generated.";
272  } else {
273  ss << "This plugin has " << (descriptions_.size() + 1U) << " PSet descriptions. "
274  << "The description used to validate a configuration is selected by "
275  << "matching the module labels. If none match, then the last description, "
276  << "which has no label, is selected. "
277  << "A cfi file will be generated for each configuration with a module label.";
278  }
279  } else {
280  if (descriptions_.size() == 1U) {
281  ss << "This plugin has " << descriptions_.size() << " PSet description. "
282  << "This description is always used to validate configurations. "
283  << "The label below is used when generating the cfi file.";
284  } else {
285  ss << "This plugin has " << descriptions_.size() << " PSet descriptions. "
286  << "The description used to validate a configuration is selected by "
287  << "matching the module labels. If none match the first description below is used. "
288  << "The module labels below are also used when generating the cfi files.";
289  }
290  }
291  DocFormatHelper::wrapAndPrintText(os, ss.str(), indentation, lineWidth);
292  os << "\n";
293  }
294 
295  indentation += DocFormatHelper::offsetModuleLabel();
296 
298  counter.iPlugin = iPlugin;
299  counter.iSelectedModule = 0;
300  counter.iModule = 0;
301 
302  for (auto const& d : descriptions_) {
303  printForLabel(d, os, moduleLabel, brief, printOnlyLabels, lineWidth, indentation, counter);
304  }
305 
306  if (defaultDescDefined_) {
307  printForLabel(os,
308  std::string("@default"),
309  defaultDesc_,
310  moduleLabel,
311  brief,
312  printOnlyLabels,
313  lineWidth,
314  indentation,
315  counter);
316  }
317  }
318 
319  void ConfigurationDescriptions::printForLabel(std::pair<std::string, ParameterSetDescription> const& labelAndDesc,
320  std::ostream& os,
321  std::string const& moduleLabel,
322  bool brief,
323  bool printOnlyLabels,
324  size_t lineWidth,
325  int indentation,
326  DescriptionCounter& counter) const {
327  printForLabel(os,
328  labelAndDesc.first,
329  labelAndDesc.second,
330  moduleLabel,
331  brief,
332  printOnlyLabels,
333  lineWidth,
334  indentation,
335  counter);
336  }
337 
339  std::string const& label,
341  std::string const& moduleLabel,
342  bool brief,
343  bool printOnlyLabels,
344  size_t lineWidth,
345  int indentation,
346  DescriptionCounter& counter) const {
347  ++counter.iModule;
348  if (!moduleLabel.empty() && label != moduleLabel)
349  return;
350  ++counter.iSelectedModule;
351 
352  std::stringstream ss;
353  ss << counter.iPlugin << "." << counter.iSelectedModule;
354  std::string section = ss.str();
355 
356  char oldFill = os.fill();
357  os << std::setfill(' ') << std::setw(indentation) << "" << std::setfill(oldFill);
358  os << section << " ";
359  if (label == std::string("@default")) {
360  os << "description without a module label\n";
361  } else {
362  if (!brief) {
363  if (0 == strcmp(baseType_.c_str(), kSource) || 0 == strcmp(baseType_.c_str(), kService)) {
364  os << "label: ";
365  } else {
366  os << "module label: ";
367  }
368  }
369  os << label << "\n";
370  }
371 
372  if (!brief) {
373  if (!description.comment().empty()) {
374  DocFormatHelper::wrapAndPrintText(os, description.comment(), indentation, lineWidth - indentation);
375  }
376  os << "\n";
377  }
378  if (printOnlyLabels)
379  return;
380 
381  DocFormatHelper dfh;
382  dfh.setBrief(brief);
383  dfh.setLineWidth(lineWidth);
385  dfh.setSection(section);
387 
388  description.print(os, dfh);
389  }
390 } // namespace edm
ConfigurationDescriptions(std::string const &baseType, std::string const &pluginName)
static void writeCfiForLabel(std::pair< std::string, ParameterSetDescription > const &labelAndDesc, std::string const &baseType, std::string const &pluginName, std::set< std::string > &usedCfiFileNames)
void addWithDefaultLabel(ParameterSetDescription const &psetDescription)
void printForLabel(std::pair< std::string, ParameterSetDescription > const &labelAndDesc, std::ostream &os, std::string const &moduleLabel, bool brief, bool printOnlyLabels, size_t lineWidth, int indentationn, DescriptionCounter &counter) const
static const char *const kService
void validate(ParameterSet &pset) const
static void wrapAndPrintText(std::ostream &os, std::string const &text, size_t indent, size_t suggestedWidth)
ParameterSetDescription * defaultDescription()
Returns 0 if no default has been assigned.
static const char *const kSource
Func for_all(ForwardSequence &s, Func f)
wrapper for std::for_each
Definition: Algorithms.h:14
static int offsetModuleLabel()
char const * label
void addDefault(ParameterSetDescription const &psetDescription)
void setBrief(bool value)
std::vector< std::pair< std::string, ParameterSetDescription > > descriptions_
void print(std::ostream &os, DocFormatHelper &dfh) const
std::string defaultModuleLabel(std::string label)
Definition: value.py:1
void setComment(std::string const &value)
void add(std::string const &label, ParameterSetDescription const &psetDescription)
void addContext(std::string const &context)
Definition: Exception.cc:165
HLT enums.
static std::atomic< unsigned int > counter
void print(std::ostream &os, std::string const &moduleLabel, bool brief, bool printOnlyLabels, size_t lineWidth, int indentation, int iPlugin) const
void validate(ParameterSet &pset, std::string const &moduleLabel) const
std::string const & comment() const
std::string const & comment() const
static const char *const k_source
static int offsetTopLevelPSet()
void setSection(std::string const &value)
std::vector< std::pair< std::string, ParameterSetDescription > >::iterator iterator
void setParent(DescriptionParent value)
void setIndentation(int value)
void writeCfis(std::set< std::string > &usedCfiFileNames) const
void setLineWidth(size_t value)