11 #include <boost/program_options.hpp>
25 using namespace edmplugin;
39 #define PER_PROCESS_DSO 20
40 #elif defined(__aarch64__)
41 #define PER_PROCESS_DSO 10
43 #define PER_PROCESS_DSO 2000
47 ostream& operator<<(std::ostream& o, vector<std::string>
const& iValue) {
50 for (std::vector<std::string>::const_iterator it = iValue.begin(), itEnd = iValue.end(); it != itEnd; ++it) {
63 using std::placeholders::_1;
64 using std::placeholders::_2;
65 iBase->
newPluginAdded_.connect(std::bind(std::mem_fn(&Listener::newPlugin),
this, _1, _2));
68 nameAndTypes_.push_back(NameAndType(iInfo.
name_, iCategory));
71 NameAndTypes nameAndTypes_;
75 using namespace boost::program_options;
76 using std::placeholders::_1;
78 static char const*
const kPathsOpt =
"paths";
79 static char const*
const kPathsCommandOpt =
"paths,p";
82 static char const*
const kHelpOpt =
"help";
86 descString +=
" [options] [[--";
87 descString += kPathsOpt;
88 descString +=
"] path [path]] \nAllowed options";
89 options_description
desc(descString);
92 if (!defaultDirList.empty()) {
93 defaultDir = defaultDirList[0];
97 value<std::vector<std::string> >()->default_value(std::vector<std::string>(1, defaultDir)),
98 "a directory or a list of files to scan")
102 positional_options_description
p;
103 p.add(kPathsOpt, -1);
107 store(command_line_parser(argc, argv).
options(desc).positional(
p).
run(), vm);
109 }
catch (
error const& iException) {
126 int returnValue = EXIT_SUCCESS;
129 std::vector<std::string> requestedPaths(vm[kPathsOpt].as<std::vector<std::string> >());
133 std::vector<std::string>
files;
134 bool removeMissingFiles =
false;
135 if (std::filesystem::is_directory(directory)) {
136 if (requestedPaths.size() > 1) {
137 std::cerr <<
"if a directory is given then only one argument is allowed" << std::endl;
142 removeMissingFiles =
true;
144 std::filesystem::directory_iterator
file(directory);
145 std::filesystem::directory_iterator
end;
147 path cacheFile(directory);
151 if (exists(cacheFile)) {
152 cacheLastChange = last_write_time(cacheFile);
156 path shortName(file->path().filename());
157 const std::string& stringName = shortName.string();
160 if (stringName.size() < kPluginPrefix.size()) {
163 if (stringName.substr(0, kPluginPrefix.size()) != kPluginPrefix) {
167 if (last_write_time(filename) > cacheLastChange) {
168 files.push_back(stringName);
173 directory = directory.parent_path();
174 for (std::vector<std::string>::iterator it = requestedPaths.begin(), itEnd = requestedPaths.end(); it != itEnd;
178 std::cerr <<
"the file '" << f.string() <<
"' does not exist" << std::endl;
181 if (is_directory(f)) {
182 std::cerr <<
"either one directory or a list of files are allowed as arguments" << std::endl;
185 if (directory != f.parent_path()) {
186 std::cerr <<
"all files must have be in the same directory (" << directory.string()
189 << f.string() <<
" does not." << std::endl;
191 #if (BOOST_VERSION / 100000) >= 1 && ((BOOST_VERSION / 100) % 1000) >= 47
192 files.push_back(f.filename().string());
194 files.push_back(f.leaf());
199 path cacheFile(directory);
203 if (exists(cacheFile)) {
204 std::ifstream cf(cacheFile.string().c_str());
206 cms::Exception(
"FailedToOpen") <<
"unable to open file '" << cacheFile.string()
207 <<
"' for reading even though it is present.\n"
208 "Please check permissions on the file.";
216 pfm->
newFactory_.connect(std::bind(std::mem_fn(&Listener::newFactory), &listener, _1));
217 edm::for_all(*pfm, std::bind(std::mem_fn(&Listener::newFactory), &listener, _1));
221 std::string temporaryFilename = (cacheFile.string() +
".tmp");
222 std::ofstream cf(temporaryFilename.c_str());
224 cms::Exception(
"FailedToOpen") <<
"unable to open file '" << temporaryFilename
225 <<
"' for writing.\n"
226 "Please check permissions on the file.";
230 std::sort(files.begin(), files.end());
232 for (
size_t fi = 0, fe = files.size(); fi < fe; fi +=
PER_PROCESS_DSO) {
234 pid_t worker = fork();
240 while (ci && fi != fe) {
241 path loadableFile(directory);
242 loadableFile /= (files[fi]);
243 listener.nameAndTypes_.clear();
251 ltp[files[fi]] = listener.nameAndTypes_;
254 if (iException.
category() ==
"PluginLibraryLoadError") {
255 std::cerr <<
"Caught exception " << iException.
what() <<
" will ignore " << files[fi]
256 <<
" and continue." << std::endl;
262 std::cerr <<
"Caught exception " << iException.what() << std::endl;
274 waitpid(worker, &status, 0);
275 if (WIFEXITED(status) ==
true && status != 0) {
276 std::cerr <<
"Error while processing." << std::endl;
286 std::ifstream icf(temporaryFilename.c_str());
288 cms::Exception(
"FailedToOpen") <<
"unable to open file '" << temporaryFilename.c_str()
289 <<
"' for reading even though it is present.\n"
290 "Please check permissions on the file.";
294 for (CacheParser::LoadableToPlugins::iterator itFile = ltp.begin(); itFile != ltp.end(); ++itFile) {
295 old[itFile->first] = itFile->second;
300 if (removeMissingFiles) {
301 for (CacheParser::LoadableToPlugins::iterator itFile = old.begin(); itFile != old.end();
303 path loadableFile(directory);
304 loadableFile /= (itFile->first);
305 if (not exists(loadableFile)) {
306 std::cout <<
"removing file '" << temporaryFilename.c_str() <<
"'" << std::endl;
307 CacheParser::LoadableToPlugins::iterator itToItemBeingRemoved = itFile;
310 old.erase(itToItemBeingRemoved);
319 std::ofstream fcf(temporaryFilename.c_str());
321 cms::Exception(
"FailedToOpen") <<
"unable to open file '" << temporaryFilename.c_str()
322 <<
"' for writing.\n"
323 "Please check permissions on the file.";
326 rename(temporaryFilename.c_str(), cacheFile.string().c_str());
328 std::cerr <<
"Caught exception " << iException.what() << std::endl;
329 returnValue = EXIT_FAILURE;
334 std::cerr << iException.what() << std::endl;
const std::filesystem::path & cachefileName()
bool tryToFind(const SharedLibrary &iLoadable)
Check to see if any capabilities are in the file, returns 'true' if found.
std::string const & category() const
static void read(std::istream &, const std::filesystem::path &iDirectory, CategoryToInfos &oOut)
const std::string & pluginPrefix()
std::pair< std::string, std::string > NameAndType
Func for_all(ForwardSequence &s, Func f)
wrapper for std::for_each
std::map< std::filesystem::path, NameAndTypes > LoadableToPlugins
PluginManager::Config config()
edm::signalslot::Signal< void(const PluginFactoryBase *)> newFactory_
edm::signalslot::Signal< void(const std::string &, const PluginInfo &)> newPluginAdded_
signal containing plugin category, and plugin info for newly added plugin
char const * what() const noexceptoverride
static PluginCapabilities * get()
static void write(const CategoryToInfos &, std::ostream &)
std::vector< NameAndType > NameAndTypes
static const char *const kHelpCommandOpt
Config & searchPath(const SearchPath &iPath)
static const char *const kHelpOpt
static PluginFactoryManager * get()