CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_3/src/FWCore/ParameterSet/src/ConfigurationDescriptions.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 //
00003 // Package:     ParameterSet
00004 // Class  :     ConfigurationDescriptions
00005 // 
00006 // Implementation:
00007 //     <Notes on implementation>
00008 //
00009 // Original Author:  W. David Dagenhart
00010 //         Created:  17 December 2008
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     // To minimize the number of copies involved create an empty description first
00088     // and push it into the vector.  Then perform the copy.
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     // If there is a matching label
00140     if (psetDesc != 0) {
00141       psetDesc->validate(pset);
00142     }
00143     // Is there an explicit description to be used for a non standard label
00144     else if (defaultDescDefined_) {
00145       defaultDesc_.validate(pset);
00146     }
00147     // Otherwise use the first one.
00148     else if (descriptions_.size() > 0U) {
00149       descriptions_[0].second.validate(pset);
00150     }
00151     // It is possible for no descriptions to be defined and no validation occurs
00152     // for this module ever.
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 }