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) {
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->leaf());
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.native_file_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.native_file_string() << ")\n"
00188 " the file " << f.native_file_string() << " does not." << std::endl;
00189 }
00190 files.push_back(f.leaf());
00191 }
00192 }
00193
00194 path cacheFile(directory);
00195 cacheFile /= edmplugin::standard::cachefileName();
00196
00197 CacheParser::LoadableToPlugins old;
00198 if(exists(cacheFile)) {
00199 std::ifstream cf(cacheFile.native_file_string().c_str());
00200 if(!cf) {
00201 cms::Exception("FailedToOpen") << "unable to open file '" << cacheFile.native_file_string() << "' for reading even though it is present.\n"
00202 "Please check permissions on the file.";
00203 }
00204 CacheParser::read(cf, old);
00205 }
00206
00207
00208
00209 Listener listener;
00210 edmplugin::PluginFactoryManager* pfm = edmplugin::PluginFactoryManager::get();
00211 pfm->newFactory_.connect(boost::bind(boost::mem_fn(&Listener::newFactory), &listener, _1));
00212 edm::for_all(*pfm, boost::bind(boost::mem_fn(&Listener::newFactory), &listener, _1));
00213
00214
00215
00216 std::string temporaryFilename = (cacheFile.native_file_string() + ".tmp");
00217 std::ofstream cf(temporaryFilename.c_str());
00218 if(!cf) {
00219 cms::Exception("FailedToOpen") << "unable to open file '"
00220 << temporaryFilename << "' for writing.\n"
00221 "Please check permissions on the file.";
00222 }
00223
00224
00225 std::sort(files.begin(), files.end());
00226
00227 for(size_t fi = 0, fe = files.size(); fi < fe; fi += PER_PROCESS_DSO)
00228 {
00229 CacheParser::LoadableToPlugins ltp;
00230 pid_t worker = fork();
00231 if (worker == 0)
00232 {
00233
00234
00235
00236 size_t ci = PER_PROCESS_DSO;
00237 while (ci && fi != fe)
00238 {
00239 path loadableFile(directory);
00240 loadableFile /= (files[fi]);
00241 listener.nameAndTypes_.clear();
00242
00243 returnValue = 0;
00244
00245 try {
00246 try {
00247 edmplugin::SharedLibrary lib(loadableFile);
00248
00249
00250 PluginCapabilities::get()->tryToFind(lib);
00251 ltp[files[fi]] = listener.nameAndTypes_;
00252
00253 } catch(cms::Exception const& iException) {
00254 if(iException.category() == "PluginLibraryLoadError") {
00255 std::cerr << "Caught exception " << iException.what() << " will ignore " << files[fi] << " and continue." << std::endl;
00256 } else {
00257 throw;
00258 }
00259 }
00260 }catch(std::exception& iException) {
00261 std::cerr << "Caught exception " << iException.what() << std::endl;
00262 exit(1);
00263 }
00264 ++fi;
00265 --ci;
00266 }
00267 CacheParser::write(ltp, cf);
00268 cf << std::flush;
00269 _exit(0);
00270 }
00271 else
00272 {
00273
00274 int status = 0;
00275 waitpid(worker, &status, 0);
00276 if (WIFEXITED(status) == true && status != 0)
00277 {
00278 std::cerr << "Error while processing." << std::endl;
00279 exit(status);
00280 }
00281 }
00282 }
00283
00284 cf << std::flush;
00285
00286
00287 CacheParser::LoadableToPlugins ltp;
00288 std::ifstream icf(temporaryFilename.c_str());
00289 if(!icf) {
00290 cms::Exception("FailedToOpen") << "unable to open file '" << temporaryFilename.c_str() << "' for reading even though it is present.\n"
00291 "Please check permissions on the file.";
00292 }
00293 CacheParser::read(icf, ltp);
00294
00295 for (CacheParser::LoadableToPlugins::iterator itFile = ltp.begin() ;
00296 itFile != ltp.end() ;
00297 ++itFile)
00298 {
00299 old[itFile->first] = itFile->second;
00300 }
00301
00302
00303
00304 if(removeMissingFiles) {
00305 for(CacheParser::LoadableToPlugins::iterator itFile = old.begin();
00306 itFile != old.end();
00307 ) {
00308 path loadableFile(directory);
00309 loadableFile /= (itFile->first);
00310 if(not exists(loadableFile)) {
00311 std::cout << "removing file '" << temporaryFilename.c_str() << "'" << std::endl;
00312 CacheParser::LoadableToPlugins::iterator itToItemBeingRemoved = itFile;
00313
00314 ++itFile;
00315 old.erase(itToItemBeingRemoved);
00316 } else {
00317
00318 ++itFile;
00319 }
00320 }
00321 }
00322
00323
00324 std::ofstream fcf(temporaryFilename.c_str());
00325 if(!fcf) {
00326 cms::Exception("FailedToOpen") << "unable to open file '" << temporaryFilename.c_str() << "' for writing.\n"
00327 "Please check permissions on the file.";
00328 }
00329 CacheParser::write(old, fcf);
00330 rename(temporaryFilename.c_str(), cacheFile.native_file_string().c_str());
00331 } catch(std::exception& iException) {
00332 std::cerr << "Caught exception " << iException.what() << std::endl;
00333 returnValue = 1;
00334 }
00335
00336 return returnValue;
00337 }