00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
00014 #include "FWCore/ParameterSet/interface/DocFormatHelper.h"
00015 #include "FWCore/Utilities/interface/Algorithms.h"
00016 #include "FWCore/Utilities/interface/EDMException.h"
00017
00018 #include "boost/bind.hpp"
00019
00020 #include <fstream>
00021 #include <iostream>
00022 #include <iomanip>
00023 #include <sstream>
00024 #include <cstring>
00025
00026 namespace {
00027 void matchLabel(std::pair<std::string, edm::ParameterSetDescription> const& thePair,
00028 std::string const& moduleLabel,
00029 edm::ParameterSetDescription const*& psetDesc) {
00030 if (thePair.first == moduleLabel) {
00031 psetDesc = &thePair.second;
00032 }
00033 }
00034 }
00035
00036 static const char* const kSource ="Source";
00037 static const char* const kService = "Service";
00038 static const char* const k_source = "source";
00039
00040 namespace edm {
00041
00042 ConfigurationDescriptions::ConfigurationDescriptions(std::string const& baseType) :
00043 baseType_(baseType),
00044 defaultDescDefined_(false)
00045 { }
00046
00047 ConfigurationDescriptions::~ConfigurationDescriptions() {}
00048
00049 void
00050 ConfigurationDescriptions::setComment(std::string const & value)
00051 { comment_ = value; }
00052
00053 void
00054 ConfigurationDescriptions::setComment(char const* value)
00055 { comment_ = value; }
00056
00057 void
00058 ConfigurationDescriptions::add(char const* label,
00059 ParameterSetDescription const& psetDescription) {
00060 std::string labelString(label);
00061 add(labelString, psetDescription);
00062 }
00063
00064 void
00065 ConfigurationDescriptions::add(std::string const& label,
00066 ParameterSetDescription const& psetDescription) {
00067
00068 if (0==strcmp(baseType_.c_str(),kSource)) {
00069 if (0!=strcmp(label.c_str(),k_source)) {
00070 throw edm::Exception(edm::errors::LogicError,
00071 "ConfigurationDescriptions::add, when adding a ParameterSetDescription for a source the label must be \"source\"\n");
00072 }
00073 if (descriptions_.size() != 0U ||
00074 defaultDescDefined_ == true) {
00075 throw edm::Exception(edm::errors::LogicError,
00076 "ConfigurationDescriptions::add, for a source only 1 ParameterSetDescription may be added\n");
00077 }
00078 }
00079 else if (0==strcmp(baseType_.c_str(),kService)) {
00080 if (descriptions_.size() != 0U ||
00081 defaultDescDefined_ == true) {
00082 throw edm::Exception(edm::errors::LogicError,
00083 "ConfigurationDescriptions::add, for a service only 1 ParameterSetDescription may be added\n");
00084 }
00085 }
00086
00087
00088
00089 std::pair<std::string, ParameterSetDescription> pairWithEmptyDescription;
00090 descriptions_.push_back(pairWithEmptyDescription);
00091 std::pair<std::string, ParameterSetDescription> & pair = descriptions_.back();
00092
00093 pair.first = label;
00094 pair.second = psetDescription;
00095
00096 }
00097
00098 void
00099 ConfigurationDescriptions::addDefault(ParameterSetDescription const& psetDescription) {
00100
00101 if (0==strcmp(baseType_.c_str(),kSource) || 0==strcmp(baseType_.c_str(),kService)) {
00102 if (descriptions_.size() != 0U ||
00103 defaultDescDefined_ == true) {
00104 throw edm::Exception(edm::errors::LogicError,
00105 "ConfigurationDescriptions::addDefault, for a source or service only 1 ParameterSetDescription may be added\n");
00106 }
00107 }
00108
00109 defaultDescDefined_ = true;
00110 defaultDesc_ = psetDescription;
00111
00112 }
00113
00114 ParameterSetDescription*
00115 ConfigurationDescriptions::defaultDescription() {
00116 if (defaultDescDefined_) {
00117 return &defaultDesc_;
00118 }
00119 return 0;
00120 }
00121
00122 ConfigurationDescriptions::iterator
00123 ConfigurationDescriptions::begin() { return descriptions_.begin();}
00124
00125 ConfigurationDescriptions::iterator
00126 ConfigurationDescriptions::end() {return descriptions_.end();}
00127
00128
00129 void
00130 ConfigurationDescriptions::validate(ParameterSet & pset,
00131 std::string const& moduleLabel) const {
00132
00133 ParameterSetDescription const* psetDesc = 0;
00134 for_all(descriptions_, boost::bind(&matchLabel,
00135 _1,
00136 boost::cref(moduleLabel),
00137 boost::ref(psetDesc)));
00138
00139
00140 if (psetDesc != 0) {
00141 psetDesc->validate(pset);
00142 }
00143
00144 else if (defaultDescDefined_) {
00145 defaultDesc_.validate(pset);
00146 }
00147
00148 else if (descriptions_.size() > 0U) {
00149 descriptions_[0].second.validate(pset);
00150 }
00151
00152
00153 }
00154
00155 void
00156 ConfigurationDescriptions::writeCfis(std::string const& baseType,
00157 std::string const& pluginName) const {
00158
00159 for_all(descriptions_, boost::bind(&ConfigurationDescriptions::writeCfiForLabel,
00160 _1,
00161 boost::cref(baseType),
00162 boost::cref(pluginName)));
00163 }
00164
00165
00166 void
00167 ConfigurationDescriptions::writeCfiForLabel(std::pair<std::string, ParameterSetDescription> const& labelAndDesc,
00168 std::string const& baseType,
00169 std::string const& pluginName)
00170 {
00171 if (0 == strcmp(baseType.c_str(),kService) && labelAndDesc.first != pluginName) {
00172 throw edm::Exception(edm::errors::LogicError,
00173 "ConfigurationDescriptions::writeCfiForLabel\nFor a service the label and the plugin name must be the same.\n")
00174 << "This error probably is caused by an incorrect label being passed\nto the ConfigurationDescriptions::add function earlier.\n"
00175 << "plugin name = \"" << pluginName << "\" label name = \"" << labelAndDesc.first << "\"\n";
00176 }
00177
00178 std::string cfi_filename;
00179 if (0 == strcmp(baseType.c_str(),kSource)) {
00180 cfi_filename = pluginName + "_cfi.py";
00181 }
00182 else {
00183 cfi_filename = labelAndDesc.first + "_cfi.py";
00184 }
00185 std::ofstream outFile(cfi_filename.c_str());
00186
00187
00188 outFile << "import FWCore.ParameterSet.Config as cms\n\n";
00189 outFile << labelAndDesc.first << " = cms." << baseType << "('" << pluginName << "'";
00190
00191 bool startWithComma = true;
00192 int indentation = 2;
00193 labelAndDesc.second.writeCfi(outFile, startWithComma, indentation);
00194
00195 outFile << ")\n";
00196
00197 outFile.close();
00198
00199 if (0 == strcmp(baseType.c_str(),kSource)) {
00200 std::cout << pluginName << "\n";
00201 }
00202 else {
00203 std::cout << labelAndDesc.first << "\n";
00204 }
00205 }
00206
00207 void ConfigurationDescriptions::print(std::ostream & os,
00208 std::string const& moduleLabel,
00209 bool brief,
00210 bool printOnlyLabels,
00211 size_t lineWidth,
00212 int indentation,
00213 int iPlugin) const {
00214 if (!brief) {
00215 if (!comment().empty()) {
00216 DocFormatHelper::wrapAndPrintText(os, comment(), indentation, lineWidth);
00217 }
00218 os << "\n";
00219 }
00220
00221 if (descriptions_.empty() && !defaultDescDefined_) {
00222 char oldFill = os.fill();
00223 indentation += DocFormatHelper::offsetModuleLabel();
00224 os << std::setfill(' ') << std::setw(indentation) << "";
00225 os << "There are no PSet descriptions defined for this plugin.\n";
00226 os << std::setfill(' ') << std::setw(indentation) << "";
00227 os << "PSets will not be validated and no cfi files will be generated.\n";
00228 os << std::setfill(oldFill);
00229 if (!brief) os << "\n";
00230 return;
00231 }
00232
00233 if (descriptions_.empty() && defaultDescDefined_ && defaultDesc_.isUnknown()) {
00234 indentation += DocFormatHelper::offsetModuleLabel();
00235 char oldFill = os.fill();
00236 os << std::setfill(' ') << std::setw(indentation) << "";
00237 os << "This plugin has not implemented the function which defines its\n";
00238 os << std::setfill(' ') << std::setw(indentation) << "";
00239 os << "configuration descriptions yet. No descriptions are available.\n";
00240 os << std::setfill(' ') << std::setw(indentation) << "";
00241 os << "Its PSets will not be validated, and no cfi files will be generated.\n";
00242 os << std::setfill(oldFill);
00243 if (!brief) os << "\n";
00244 return;
00245 }
00246
00247 if (!brief) {
00248 std::stringstream ss;
00249 if (defaultDescDefined_) {
00250 if (descriptions_.empty()) {
00251 ss << "This plugin has only one PSet description. "
00252 << "This description is always used to validate configurations. "
00253 << "Because this configuration has no label, no cfi files will be generated.";
00254 }
00255 else {
00256 ss << "This plugin has " << (descriptions_.size() + 1U) << " PSet descriptions. "
00257 << "The description used to validate a configuration is selected by "
00258 << "matching the module labels. If none match, then the last description, "
00259 << "which has no label, is selected. "
00260 << "A cfi file will be generated for each configuration with a module label.";
00261 }
00262 }
00263 else {
00264 if (descriptions_.size() == 1U) {
00265 ss << "This plugin has " << descriptions_.size() << " PSet description. "
00266 << "This description is always used to validate configurations. "
00267 << "The label below is used when generating the cfi file.";
00268 }
00269 else {
00270 ss << "This plugin has " << descriptions_.size() << " PSet descriptions. "
00271 << "The description used to validate a configuration is selected by "
00272 << "matching the module labels. If none match the first description below is used. "
00273 << "The module labels below are also used when generating the cfi files.";
00274 }
00275 }
00276 DocFormatHelper::wrapAndPrintText(os, ss.str(), indentation, lineWidth);
00277 os << "\n";
00278 }
00279
00280 indentation += DocFormatHelper::offsetModuleLabel();
00281
00282 DescriptionCounter counter;
00283 counter.iPlugin = iPlugin;
00284 counter.iSelectedModule = 0;
00285 counter.iModule = 0;
00286
00287 for_all(descriptions_, boost::bind(&ConfigurationDescriptions::printForLabel,
00288 this,
00289 _1,
00290 boost::ref(os),
00291 boost::cref(moduleLabel),
00292 brief,
00293 printOnlyLabels,
00294 lineWidth,
00295 indentation,
00296 boost::ref(counter)));
00297
00298 if (defaultDescDefined_) {
00299 printForLabel(os,
00300 std::string("@default"),
00301 defaultDesc_,
00302 moduleLabel,
00303 brief,
00304 printOnlyLabels,
00305 lineWidth,
00306 indentation,
00307 counter);
00308 }
00309 }
00310
00311 void
00312 ConfigurationDescriptions::printForLabel(std::pair<std::string, ParameterSetDescription> const& labelAndDesc,
00313 std::ostream & os,
00314 std::string const& moduleLabel,
00315 bool brief,
00316 bool printOnlyLabels,
00317 size_t lineWidth,
00318 int indentation,
00319 DescriptionCounter & counter) const
00320 {
00321 printForLabel(os,
00322 labelAndDesc.first,
00323 labelAndDesc.second,
00324 moduleLabel,
00325 brief,
00326 printOnlyLabels,
00327 lineWidth,
00328 indentation,
00329 counter);
00330 }
00331
00332 void
00333 ConfigurationDescriptions::printForLabel(std::ostream & os,
00334 std::string const& label,
00335 ParameterSetDescription const& description,
00336 std::string const& moduleLabel,
00337 bool brief,
00338 bool printOnlyLabels,
00339 size_t lineWidth,
00340 int indentation,
00341 DescriptionCounter & counter) const
00342 {
00343 ++counter.iModule;
00344 if (!moduleLabel.empty() && label != moduleLabel) return;
00345 ++counter.iSelectedModule;
00346
00347 std::stringstream ss;
00348 ss << counter.iPlugin << "." << counter.iSelectedModule;
00349 std::string section = ss.str();
00350
00351 char oldFill = os.fill();
00352 os << std::setfill(' ') << std::setw(indentation) << "" << std::setfill(oldFill);
00353 os << section << " ";
00354 if (label == std::string("@default")) {
00355 os << "description without a module label\n";
00356 }
00357 else {
00358 if (!brief) {
00359 if (0 == strcmp(baseType_.c_str(),kSource) || 0 == strcmp(baseType_.c_str(),kService)) {
00360 os << "label: ";
00361 }
00362 else {
00363 os << "module label: ";
00364 }
00365 }
00366 os << label << "\n";
00367 }
00368
00369 if (!brief) {
00370 if (!description.comment().empty()) {
00371 DocFormatHelper::wrapAndPrintText(os, description.comment(), indentation, lineWidth - indentation);
00372 }
00373 os << "\n";
00374 }
00375 if (printOnlyLabels) return;
00376
00377 DocFormatHelper dfh;
00378 dfh.setBrief(brief);
00379 dfh.setLineWidth(lineWidth);
00380 dfh.setIndentation(indentation + DocFormatHelper::offsetTopLevelPSet());
00381 dfh.setSection(section);
00382 dfh.setParent(DocFormatHelper::TOP);
00383
00384 description.print(os, dfh);
00385 }
00386 }