CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_4_4_5_patch3/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 
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     // To minimize the number of copies involved create an empty description first
00083     // and push it into the vector.  Then perform the copy.
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     if (baseType_ == std::string("ESSource") || baseType_ == std::string("ESProducer")) {
00092       std::string name("appendToDataLabel");
00093       if (pair.second.isLabelUnused(name)) {
00094         pair.second.add<std::string>(name, std::string(""));
00095       }
00096     }
00097   }
00098 
00099   void
00100   ConfigurationDescriptions::addDefault(ParameterSetDescription const& psetDescription) {
00101 
00102     if (baseType_ == std::string("Source") || baseType_ == std::string("Service")) {
00103       if (descriptions_.size() != 0U ||
00104           defaultDescDefined_ == true) {
00105         throw edm::Exception(edm::errors::LogicError,
00106           "ConfigurationDescriptions::addDefault, for a source or service only 1 ParameterSetDescription may be added\n");
00107       }
00108     }
00109 
00110     defaultDescDefined_ = true;
00111     defaultDesc_ = psetDescription;
00112 
00113     if (baseType_ == std::string("ESSource") || baseType_ == std::string("ESProducer")) {
00114       std::string name("appendToDataLabel");
00115       if (defaultDesc_.isLabelUnused(name)) {
00116         defaultDesc_.add<std::string>(name, std::string(""));
00117       }
00118     }
00119   }
00120 
00121   void
00122   ConfigurationDescriptions::validate(ParameterSet & pset,
00123                                       std::string const& moduleLabel) const {
00124     
00125     ParameterSetDescription const* psetDesc = 0;
00126     for_all(descriptions_, boost::bind(&matchLabel,
00127                                        _1,
00128                                        boost::cref(moduleLabel),
00129                                        boost::ref(psetDesc)));
00130 
00131     // If there is a matching label
00132     if (psetDesc != 0) {
00133       psetDesc->validate(pset);
00134     }
00135     // Is there an explicit description to be used for a non standard label
00136     else if (defaultDescDefined_) {
00137       defaultDesc_.validate(pset);
00138     }
00139     // Otherwise use the first one.
00140     else if (descriptions_.size() > 0U) {
00141       descriptions_[0].second.validate(pset);
00142     }
00143     // It is possible for no descriptions to be defined and no validation occurs
00144     // for this module ever.
00145   }
00146 
00147   void
00148   ConfigurationDescriptions::writeCfis(std::string const& baseType,
00149                                        std::string const& pluginName) const {
00150 
00151     for_all(descriptions_, boost::bind(&ConfigurationDescriptions::writeCfiForLabel,
00152                                        _1,
00153                                        boost::cref(baseType),
00154                                        boost::cref(pluginName)));
00155   }
00156 
00157 
00158   void
00159   ConfigurationDescriptions::writeCfiForLabel(std::pair<std::string, ParameterSetDescription> const& labelAndDesc,
00160                                               std::string const& baseType,
00161                                               std::string const& pluginName)
00162   {
00163     if (baseType == std::string("Service") && labelAndDesc.first != pluginName) {
00164       throw edm::Exception(edm::errors::LogicError,
00165         "ConfigurationDescriptions::writeCfiForLabel\nFor a service the label and the plugin name must be the same.\n")
00166         << "This error probably is caused by an incorrect label being passed\nto the ConfigurationDescriptions::add function earlier.\n"
00167         << "plugin name = \"" << pluginName << "\"  label name = \"" << labelAndDesc.first << "\"\n";
00168     }
00169 
00170     std::string cfi_filename;
00171     if (baseType == std::string("Source")) {
00172       cfi_filename = pluginName + "_cfi.py";
00173     }
00174     else {
00175       cfi_filename = labelAndDesc.first + "_cfi.py";
00176     }
00177     std::ofstream outFile(cfi_filename.c_str());
00178 
00179 
00180     outFile << "import FWCore.ParameterSet.Config as cms\n\n";
00181     outFile << labelAndDesc.first << " = cms." << baseType << "('" << pluginName << "'";
00182 
00183     bool startWithComma = true;
00184     int indentation = 2;
00185     labelAndDesc.second.writeCfi(outFile, startWithComma, indentation);
00186 
00187     outFile << ")\n";
00188   
00189     outFile.close();
00190 
00191     if (baseType == std::string("Source")) {
00192       std::cout << pluginName << "\n";
00193     }
00194     else {
00195       std::cout << labelAndDesc.first << "\n";
00196     }
00197   }
00198 
00199   void ConfigurationDescriptions::print(std::ostream & os,
00200                                         std::string const& moduleLabel,
00201                                         bool brief,
00202                                         bool printOnlyLabels,
00203                                         size_t lineWidth,
00204                                         int indentation,
00205                                         int iPlugin) const {
00206     if (!brief) {
00207       if (!comment().empty()) {
00208         DocFormatHelper::wrapAndPrintText(os, comment(), indentation, lineWidth);
00209       }
00210       os << "\n";
00211     }
00212 
00213     char oldFill = os.fill();
00214     if (descriptions_.empty() && !defaultDescDefined_) {
00215       indentation += DocFormatHelper::offsetModuleLabel();
00216       os << std::setfill(' ') << std::setw(indentation) << "";
00217       os << "There are no PSet descriptions defined for this plugin.\n";
00218       os << std::setfill(' ') << std::setw(indentation) << "";
00219       os << "PSets will not be validated and no cfi files will be generated.\n";
00220       if (!brief) os << "\n";
00221       os.fill(oldFill);
00222       return;
00223     }
00224 
00225     if (descriptions_.empty() && defaultDescDefined_ && defaultDesc_.isUnknown()) {
00226       indentation += DocFormatHelper::offsetModuleLabel();
00227       os << std::setfill(' ') << std::setw(indentation) << "";
00228       os << "This plugin has not implemented the function which defines its\n";
00229       os << std::setfill(' ') << std::setw(indentation) << "";
00230       os << "configuration descriptions yet. No descriptions are available.\n";
00231       os << std::setfill(' ') << std::setw(indentation) << "";
00232       os << "Its PSets will not be validated, and no cfi files will be generated.\n";
00233       if (!brief) os << "\n";
00234       os.fill(oldFill);
00235       return;
00236     }
00237 
00238     if (!brief) {
00239       std::stringstream ss;
00240       if (defaultDescDefined_) {
00241         if (descriptions_.empty()) {
00242           ss << "This plugin has only one PSet description. "
00243              << "This description is always used to validate configurations. "
00244              << "Because this configuration has no label, no cfi files will be generated.";
00245         }
00246         else {
00247           ss << "This plugin has " << (descriptions_.size() + 1U) << " PSet descriptions. "
00248              << "The description used to validate a configuration is selected by "
00249              << "matching the module labels. If none match, then the last description, "
00250              << "which has no label, is selected. "
00251              << "A cfi file will be generated for each configuration with a module label.";
00252         }
00253       }
00254       else {
00255         if (descriptions_.size() == 1U) {
00256           ss << "This plugin has " << descriptions_.size() << " PSet description. "
00257              << "This description is always used to validate configurations. "
00258              << "The label below is used when generating the cfi file.";
00259         }
00260         else {
00261           ss << "This plugin has " << descriptions_.size() << " PSet descriptions. "
00262              << "The description used to validate a configuration is selected by "
00263              << "matching the module labels. If none match the first description below is used. "
00264              << "The module labels below are also used when generating the cfi files.";
00265         }
00266       }
00267       DocFormatHelper::wrapAndPrintText(os, ss.str(), indentation, lineWidth);
00268       os << "\n";
00269     }
00270 
00271     indentation += DocFormatHelper::offsetModuleLabel();
00272 
00273     DescriptionCounter counter;
00274     counter.iPlugin = iPlugin;
00275     counter.iSelectedModule = 0;
00276     counter.iModule = 0;
00277 
00278     for_all(descriptions_, boost::bind(&ConfigurationDescriptions::printForLabel,
00279                                        this,
00280                                        _1,
00281                                        boost::ref(os),
00282                                        boost::cref(moduleLabel),
00283                                        brief,
00284                                        printOnlyLabels,
00285                                        lineWidth,
00286                                        indentation,
00287                                        boost::ref(counter)));
00288 
00289     if (defaultDescDefined_) {
00290       printForLabel(os,
00291                     std::string("@default"),
00292                     defaultDesc_,
00293                     moduleLabel,
00294                     brief,
00295                     printOnlyLabels,
00296                     lineWidth,
00297                     indentation,
00298                     counter);
00299     }
00300   }
00301 
00302   void
00303   ConfigurationDescriptions::printForLabel(std::pair<std::string, ParameterSetDescription> const& labelAndDesc,
00304                                            std::ostream & os,
00305                                            std::string const& moduleLabel,
00306                                            bool brief,
00307                                            bool printOnlyLabels,
00308                                            size_t lineWidth,
00309                                            int indentation,
00310                                            DescriptionCounter & counter) const
00311   {
00312     printForLabel(os,
00313                   labelAndDesc.first,
00314                   labelAndDesc.second,
00315                   moduleLabel,
00316                   brief,
00317                   printOnlyLabels,
00318                   lineWidth,
00319                   indentation,
00320                   counter);
00321   }
00322 
00323   void
00324   ConfigurationDescriptions::printForLabel(std::ostream & os,
00325                                            std::string const& label,
00326                                            ParameterSetDescription const& description,
00327                                            std::string const& moduleLabel,
00328                                            bool brief,
00329                                            bool printOnlyLabels,
00330                                            size_t lineWidth,
00331                                            int indentation,
00332                                            DescriptionCounter & counter) const
00333   {
00334     ++counter.iModule;
00335     if (!moduleLabel.empty() && label != moduleLabel) return;
00336     ++counter.iSelectedModule;
00337 
00338     std::stringstream ss;
00339     ss << counter.iPlugin << "." << counter.iSelectedModule;
00340     std::string section = ss.str();
00341 
00342     char oldFill = os.fill();
00343     os << std::setfill(' ') << std::setw(indentation) << "";
00344     os.fill(oldFill);
00345     os << section << " ";
00346     if (label == std::string("@default")) {
00347       os << "description without a module label\n";
00348     }
00349     else {
00350       if (!brief) {
00351         if (baseType_ == std::string("Source") || baseType_ == std::string("Service")) {
00352           os << "label: ";
00353         }
00354         else {
00355           os << "module label: ";
00356         }
00357       }
00358       os << label << "\n";      
00359     }
00360 
00361     if (!brief) {
00362       if (!description.comment().empty()) {
00363         DocFormatHelper::wrapAndPrintText(os, description.comment(), indentation, lineWidth - indentation);        
00364       }
00365       os << "\n";
00366     }
00367     if (printOnlyLabels) return;
00368 
00369     DocFormatHelper dfh;
00370     dfh.setBrief(brief);
00371     dfh.setLineWidth(lineWidth);
00372     dfh.setIndentation(indentation + DocFormatHelper::offsetTopLevelPSet());
00373     dfh.setSection(section);
00374     dfh.setParent(DocFormatHelper::TOP);
00375 
00376     description.print(os, dfh);
00377   }
00378 }