Go to the documentation of this file.00001 #include "FWCore/PluginManager/interface/CacheParser.h"
00002 #include "FWCore/PluginManager/interface/PluginCapabilities.h"
00003 #include "FWCore/PluginManager/interface/PluginFactoryBase.h"
00004 #include "FWCore/PluginManager/interface/PluginFactoryManager.h"
00005 #include "FWCore/PluginManager/interface/SharedLibrary.h"
00006 #include "FWCore/PluginManager/interface/standard.h"
00007
00008 #include "FWCore/Utilities/interface/Exception.h"
00009 #include "FWCore/Utilities/interface/Algorithms.h"
00010
00011 #include <boost/bind.hpp>
00012 #include <boost/filesystem/operations.hpp>
00013 #include <boost/mem_fn.hpp>
00014 #include <boost/program_options.hpp>
00015
00016 #include <algorithm>
00017 #include <cstdlib>
00018 #include <fstream>
00019 #include <iostream>
00020 #include <set>
00021 #include <string>
00022 #include <utility>
00023
00024 #include <sys/wait.h>
00025
00026 using namespace edmplugin;
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #ifdef __APPLE__
00040 #define PER_PROCESS_DSO 20
00041 #else
00042 #define PER_PROCESS_DSO 200
00043 #endif
00044
00045 namespace std {
00046 ostream& operator<<(std::ostream& o, vector<std::string> const& iValue) {
00047 std::string sep("");
00048 std::string commaSep(",");
00049 for(std::vector<std::string>::const_iterator it = iValue.begin(), itEnd = iValue.end();
00050 it != itEnd;
00051 ++it) {
00052 o << sep << *it;
00053 sep = commaSep;
00054 }
00055 return o;
00056 }
00057 }
00058 namespace {
00059 struct Listener {
00060 typedef edmplugin::CacheParser::NameAndType NameAndType;
00061 typedef edmplugin::CacheParser::NameAndTypes NameAndTypes;
00062
00063 void newFactory(edmplugin::PluginFactoryBase const* iBase) {
00064 iBase->newPluginAdded_.connect(boost::bind(boost::mem_fn(&Listener::newPlugin), this, _1, _2));
00065 }
00066 void newPlugin(std::string const& iCategory, edmplugin::PluginInfo const& iInfo) {
00067 nameAndTypes_.push_back(NameAndType(iInfo.name_, iCategory));
00068 }
00069
00070 NameAndTypes nameAndTypes_;
00071 };
00072 }
00073 int main (int argc, char **argv) try {
00074 using namespace boost::program_options;
00075
00076 static char const* const kPathsOpt = "paths";
00077 static char const* const kPathsCommandOpt = "paths,p";
00078
00079
00080 static char const* const kHelpOpt = "help";
00081 static char const* const kHelpCommandOpt = "help,h";
00082
00083 std::string descString(argv[0]);
00084 descString += " [options] [[--";
00085 descString += kPathsOpt;
00086 descString += "] path [path]] \nAllowed options";
00087 options_description desc(descString);
00088 std::string defaultDir(".");
00089 std::vector<std::string> defaultDirList = edmplugin::standard::config().searchPath();
00090 if(!defaultDirList.empty()) {
00091 defaultDir = defaultDirList[0];
00092 }
00093 desc.add_options()
00094 (kHelpCommandOpt, "produce help message")
00095 (kPathsCommandOpt, value<std::vector<std::string> >()->default_value(
00096 std::vector<std::string>(1, defaultDir))
00097 , "a directory or a list of files to scan")
00098
00099 ;
00100
00101 positional_options_description p;
00102 p.add(kPathsOpt, -1);
00103
00104 variables_map vm;
00105 try {
00106 store(command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
00107 notify(vm);
00108 } catch(error const& iException) {
00109 std::cerr << iException.what();
00110 return 1;
00111 }
00112
00113 if(vm.count(kHelpOpt)) {
00114 std::cout << desc << std::endl;
00115 return 0;
00116 }
00117
00118 using boost::filesystem::path;
00119
00120
00121
00122
00123
00124
00125 int returnValue = EXIT_SUCCESS;
00126
00127 try {
00128 std::vector<std::string> requestedPaths(vm[kPathsOpt].as<std::vector<std::string> >());
00129
00130
00131 path directory(requestedPaths[0]);
00132 std::vector<std::string> files;
00133 bool removeMissingFiles = false;
00134 if(boost::filesystem::is_directory(directory)) {
00135 if (requestedPaths.size() > 1) {
00136 std::cerr << "if a directory is given then only one argument is allowed" << std::endl;
00137 return 1;
00138 }
00139
00140
00141 removeMissingFiles = true;
00142
00143 boost::filesystem::directory_iterator file (directory);
00144 boost::filesystem::directory_iterator end;
00145
00146 path cacheFile(directory);
00147 cacheFile /= standard::cachefileName();
00148
00149 std::time_t cacheLastChange(0);
00150 if(exists(cacheFile)) {
00151 cacheLastChange = last_write_time(cacheFile);
00152 }
00153 for (; file != end; ++file)
00154 {
00155
00156 path filename (*file);
00157 path shortName(file->path().filename());
00158 std::string stringName = shortName.string();
00159
00160 static std::string kPluginPrefix(standard::pluginPrefix());
00161 if (stringName.size() < kPluginPrefix.size()) {
00162 continue;
00163 }
00164 if(stringName.substr(0, kPluginPrefix.size()) != kPluginPrefix) {
00165 continue;
00166 }
00167
00168 if(last_write_time(filename) > cacheLastChange) {
00169 files.push_back(stringName);
00170 }
00171 }
00172 } else {
00173
00174 directory = directory.branch_path();
00175 for(std::vector<std::string>::iterator it = requestedPaths.begin(), itEnd = requestedPaths.end();
00176 it != itEnd; ++it) {
00177 boost::filesystem::path f(*it);
00178 if (!exists(f)) {
00179 std::cerr << "the file '" << f.string() << "' does not exist" << std::endl;
00180 return 1;
00181 }
00182 if (is_directory(f)) {
00183 std::cerr << "either one directory or a list of files are allowed as arguments" << std::endl;
00184 return 1;
00185 }
00186 if(directory != f.branch_path()) {
00187 std::cerr << "all files must have be in the same directory (" << directory.string() << ")\n"
00188 " the file " << f.string() << " does not." << std::endl;
00189 }
00190 #if (BOOST_VERSION / 100000) >= 1 && ((BOOST_VERSION / 100) % 1000) >= 47
00191 files.push_back(f.filename().string());
00192 #else
00193 files.push_back(f.leaf());
00194 #endif
00195 }
00196 }
00197
00198 path cacheFile(directory);
00199 cacheFile /= edmplugin::standard::cachefileName();
00200
00201 CacheParser::LoadableToPlugins old;
00202 if(exists(cacheFile)) {
00203 std::ifstream cf(cacheFile.string().c_str());
00204 if(!cf) {
00205 cms::Exception("FailedToOpen") << "unable to open file '" << cacheFile.string() << "' for reading even though it is present.\n"
00206 "Please check permissions on the file.";
00207 }
00208 CacheParser::read(cf, old);
00209 }
00210
00211
00212
00213 Listener listener;
00214 edmplugin::PluginFactoryManager* pfm = edmplugin::PluginFactoryManager::get();
00215 pfm->newFactory_.connect(boost::bind(boost::mem_fn(&Listener::newFactory), &listener, _1));
00216 edm::for_all(*pfm, boost::bind(boost::mem_fn(&Listener::newFactory), &listener, _1));
00217
00218
00219
00220 std::string temporaryFilename = (cacheFile.string() + ".tmp");
00221 std::ofstream cf(temporaryFilename.c_str());
00222 if(!cf) {
00223 cms::Exception("FailedToOpen") << "unable to open file '"
00224 << temporaryFilename << "' for writing.\n"
00225 "Please check permissions on the file.";
00226 }
00227
00228
00229 std::sort(files.begin(), files.end());
00230
00231 for(size_t fi = 0, fe = files.size(); fi < fe; fi += PER_PROCESS_DSO)
00232 {
00233 CacheParser::LoadableToPlugins ltp;
00234 pid_t worker = fork();
00235 if (worker == 0)
00236 {
00237
00238
00239
00240 size_t ci = PER_PROCESS_DSO;
00241 while (ci && fi != fe)
00242 {
00243 path loadableFile(directory);
00244 loadableFile /= (files[fi]);
00245 listener.nameAndTypes_.clear();
00246
00247 returnValue = 0;
00248
00249 try {
00250 try {
00251 edmplugin::SharedLibrary lib(loadableFile);
00252
00253
00254 PluginCapabilities::get()->tryToFind(lib);
00255 ltp[files[fi]] = listener.nameAndTypes_;
00256
00257 } catch(cms::Exception const& iException) {
00258 if(iException.category() == "PluginLibraryLoadError") {
00259 std::cerr << "Caught exception " << iException.what() << " will ignore " << files[fi] << " and continue." << std::endl;
00260 } else {
00261 throw;
00262 }
00263 }
00264 }catch(std::exception& iException) {
00265 std::cerr << "Caught exception " << iException.what() << std::endl;
00266 exit(1);
00267 }
00268 ++fi;
00269 --ci;
00270 }
00271 CacheParser::write(ltp, cf);
00272 cf << std::flush;
00273 _exit(0);
00274 }
00275 else
00276 {
00277
00278 int status = 0;
00279 waitpid(worker, &status, 0);
00280 if (WIFEXITED(status) == true && status != 0)
00281 {
00282 std::cerr << "Error while processing." << std::endl;
00283 exit(status);
00284 }
00285 }
00286 }
00287
00288 cf << std::flush;
00289
00290
00291 CacheParser::LoadableToPlugins ltp;
00292 std::ifstream icf(temporaryFilename.c_str());
00293 if(!icf) {
00294 cms::Exception("FailedToOpen") << "unable to open file '" << temporaryFilename.c_str() << "' for reading even though it is present.\n"
00295 "Please check permissions on the file.";
00296 }
00297 CacheParser::read(icf, ltp);
00298
00299 for (CacheParser::LoadableToPlugins::iterator itFile = ltp.begin() ;
00300 itFile != ltp.end() ;
00301 ++itFile)
00302 {
00303 old[itFile->first] = itFile->second;
00304 }
00305
00306
00307
00308 if(removeMissingFiles) {
00309 for(CacheParser::LoadableToPlugins::iterator itFile = old.begin();
00310 itFile != old.end();
00311 ) {
00312 path loadableFile(directory);
00313 loadableFile /= (itFile->first);
00314 if(not exists(loadableFile)) {
00315 std::cout << "removing file '" << temporaryFilename.c_str() << "'" << std::endl;
00316 CacheParser::LoadableToPlugins::iterator itToItemBeingRemoved = itFile;
00317
00318 ++itFile;
00319 old.erase(itToItemBeingRemoved);
00320 } else {
00321
00322 ++itFile;
00323 }
00324 }
00325 }
00326
00327
00328 std::ofstream fcf(temporaryFilename.c_str());
00329 if(!fcf) {
00330 cms::Exception("FailedToOpen") << "unable to open file '" << temporaryFilename.c_str() << "' for writing.\n"
00331 "Please check permissions on the file.";
00332 }
00333 CacheParser::write(old, fcf);
00334 rename(temporaryFilename.c_str(), cacheFile.string().c_str());
00335 } catch(std::exception& iException) {
00336 std::cerr << "Caught exception " << iException.what() << std::endl;
00337 returnValue = 1;
00338 }
00339
00340 return returnValue;
00341 } catch(std::exception const& iException) {
00342 std::cerr << iException.what() << std::endl;
00343 return 1;
00344 }