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