------------------------------------------------------------ revno: 3271 committer: poy <p...@123gen.com> branch nick: trunk timestamp: Tue 2013-04-23 17:34:45 +0200 message: plugins: OS differentiation in dcext; name the install dir from the UUID; rework errors modified: Plugin format (dcext).txt dcpp/PluginManager.cpp dcpp/PluginManager.h win32/PluginInfoDlg.cpp win32/PluginInfoDlg.h win32/PluginPage.cpp
-- lp:dcplusplus https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk Your team Dcplusplus-team is subscribed to branch lp:dcplusplus. To unsubscribe from this branch go to https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk/+edit-subscription
=== modified file 'Plugin format (dcext).txt' --- Plugin format (dcext).txt 2013-04-22 22:31:37 +0000 +++ Plugin format (dcext).txt 2013-04-23 15:34:45 +0000 @@ -34,13 +34,18 @@ - "Description" (optional): Short description of the plugin. - "Website" (optional): Plugin website. -- "Plugin" (compulsory): Location of the loadable shared extension within the archive. The optional - "Arch" attribute of this tag designates the architecture this plugin has been compiled for. It - may be one of "x86", "x64"; "x86" is assumed by default in the absence of this attribute. - Multiple "Plugin" tags may be provided for different architectures. +- "Plugin" (compulsory): Location of the loadable shared extension within the archive. The required + "Platform" attribute of this tag must be a value from the "Platform codes" list below. Multiple + "Plugin" tags may be provided for different platforms. - "Files" (optional): Additional files required by the plugin, each within a "File" tag. "File" - tags may contain an "Arch" attribute to specify the architecture the file works on; files are - assumed to target every architecture by default. + tags may contain an optional "Platform" attribute which must be a value from the "Platform + codes" list below; in its absence, files are assumed to be platform-independant by default. + +Platform codes: +- elf-x64: ELF format, x64 architecture. +- elf-x86: ELF format, x86 architecture. +- pe-x64: PE format, x64 architecture. +- pe-x86: PE format, x86 architecture. Example info.xml: @@ -53,11 +58,13 @@ <Author>Test team</Author> <Description>Plugin to do X</Description> <Website>http://example.com</Website> - <Plugin Arch="x86">x86/TestPlugin.so</Plugin> - <Plugin Arch="x64">x64/TestPlugin.so</Plugin> + <Plugin Platform="elf-x64">x64/TestPlugin.so</Plugin> + <Plugin Platform="elf-x86">x86/TestPlugin.so</Plugin> + <Plugin Platform="pe-x64">x64/TestPlugin.dll</Plugin> + <Plugin Platform="pe-x86">x86/TestPlugin.dll</Plugin> <Files> <File>icons/TestPlugin.ico</File> <File>fonts/cool.font</File> - <File Arch="x64">FasterHash.so</File> + <File Platform="elf-x64">FasterHash.so</File> </Files> </dcext> === modified file 'dcpp/PluginManager.cpp' --- dcpp/PluginManager.cpp 2013-04-22 22:31:37 +0000 +++ dcpp/PluginManager.cpp 2013-04-23 15:34:45 +0000 @@ -26,9 +26,11 @@ #include "File.h" #include "LogManager.h" #include "QueueManager.h" +#include "ScopedFunctor.h" #include "SimpleXML.h" #include "StringTokenizer.h" #include "UserConnection.h" +#include "version.h" #include <utility> @@ -91,14 +93,21 @@ } }; - auto checkArch = [&xml] { - auto arch = xml.getChildAttrib("Arch", "x86"); -#if defined(__x86_64__) || defined(_WIN64) - return arch == "x64"; -#elif defined(__i386__) || defined(_M_IX86) - return arch == "x86"; + auto checkPlatform = [&xml](bool emptyAllowed) { + auto platform = xml.getChildAttrib("Platform"); + if(emptyAllowed && platform.empty()) { + return true; + } +#if defined(_WIN32) && defined(_WIN64) + return platform == "pe-x64"; +#elif defined(_WIN32) + return platform == "pe-x86"; +#elif defined(__x86_64__) + return platform == "elf-x64"; +#elif defined(__i386__) + return platform == "elf-x86"; #else -#error Unknown architecture +#error Unknown platform #endif }; @@ -117,7 +126,7 @@ xml.resetCurrentChild(); while(xml.findChild("Plugin")) { - if(checkArch()) { + if(checkPlatform(false)) { info.plugin = xml.getChildData(); } } @@ -127,7 +136,7 @@ xml.stepIn(); while(xml.findChild("File")) { - if(checkArch()) { + if(checkPlatform(true)) { info.files.push_back(xml.getChildData()); } } @@ -138,28 +147,27 @@ xml.stepOut(); } - if(info.uuid.empty() || info.name.empty() || info.version == 0 || info.plugin.empty()) { - throw str(F_("%1% is not a valid DC extension") % Util::getFileName(path)); - } - - { - Lock l(cs); - - if(isLoaded(info.uuid)) { - throw str(F_("%1% is already installed") % Util::getFileName(path)); - } + if(info.uuid.empty() || info.name.empty() || info.version == 0) { + throw Exception(str(F_("%1% is not a valid plugin") % Util::getFileName(path))); + } + if(info.plugin.empty()) { + throw Exception(str(F_("%1% is not compatible with %2%") % Util::getFileName(path) % APPNAME)); + } + + if(isLoaded(info.uuid)) { + throw Exception(str(F_("%1% is already installed") % Util::getFileName(path))); } return info; } -void PluginManager::install(const string& name, const string& plugin, const StringList& files) { - if(name.empty() || plugin.empty()) { +void PluginManager::install(const string& uuid, const string& plugin, const StringList& files) { + if(uuid.empty() || plugin.empty()) { throw Exception(); } const auto source = Util::getTempPath() + "dcext" PATH_SEPARATOR_STR; - const auto target = Util::getPath(Util::PATH_USER_LOCAL) + "Plugins" PATH_SEPARATOR_STR + name + PATH_SEPARATOR_STR; + const auto target = Util::getPath(Util::PATH_USER_LOCAL) + "Plugins" PATH_SEPARATOR_STR + uuid + PATH_SEPARATOR_STR; const auto lib = target + Util::getFileName(plugin); File::ensureDirectory(lib); @@ -170,7 +178,7 @@ File::renameFile(source + file, target + file); } - loadPlugin(lib, [](const string& err) { throw Exception(err); }, true); + loadPlugin(lib, true); } void PluginManager::loadPlugins(function<void (const string&)> f) { @@ -182,73 +190,67 @@ loadSettings(); StringTokenizer<string> st(getPluginSetting("CoreSetup", "Plugins"), ";"); - auto err = [](const string& str) { LogManager::getInstance()->message(str); }; for(auto& i: st.getTokens()) { - if(!loadPlugin(i, err) || !f) continue; - f(Util::getFileName(i)); + if(f) { f(Util::getFileName(i)); } + try { loadPlugin(i); } + catch(const Exception& e) { LogManager::getInstance()->message(e.getError()); } } } -bool PluginManager::loadPlugin(const string& fileName, function<void (const string&)> err, bool install) { +void PluginManager::loadPlugin(const string& fileName, bool install) { Lock l(cs); dcassert(dcCore.apiVersion != 0); PluginHandle hr = LOAD_LIBRARY(fileName); if(!hr) { - err(str(F_("Error loading %1%: %2%") % Util::getFileName(fileName) % GET_ERROR())); - return false; + throw Exception(str(F_("Error loading %1%: %2%") % Util::getFileName(fileName) % GET_ERROR())); } + ScopedFunctor([&hr] { if(hr) FREE_LIBRARY(hr); }); PluginInfo::PLUGIN_INIT pluginInfo = reinterpret_cast<PluginInfo::PLUGIN_INIT>(GET_ADDRESS(hr, "pluginInit")); - - if(pluginInfo != NULL) { - MetaData info = { 0 }; - DCMAIN dcMain; - if((dcMain = pluginInfo(&info))) { - if(checkPlugin(info, err)) { - if(dcMain((install ? ON_INSTALL : ON_LOAD), &dcCore, NULL) != False) { - plugins.emplace_back(new PluginInfo(fileName, hr, info, dcMain)); - return true; - } - } - } - } else err(str(F_("%1% is not a valid plugin") % Util::getFileName(fileName))); - - FREE_LIBRARY(hr); - return false; + MetaData info { }; + DCMAIN dcMain; + if(!pluginInfo || !(dcMain = pluginInfo(&info))) { + throw Exception(str(F_("%1% is not a valid plugin") % Util::getFileName(fileName))); + } + + checkPlugin(info); + + if(dcMain((install ? ON_INSTALL : ON_LOAD), &dcCore, nullptr) == False) { + throw Exception(str(F_("Error loading %1%") % Util::getFileName(fileName))); + } + + plugins.emplace_back(new PluginInfo(fileName, hr, info, dcMain)); + hr = nullptr; // bypass the scoped deleter. } bool PluginManager::isLoaded(const string& guid) { + Lock l(cs); auto pluginComp = [&guid](const unique_ptr<PluginInfo>& p) -> bool { return strcmp(p->getInfo().guid, guid.c_str()) == 0; }; auto i = std::find_if(plugins.begin(), plugins.end(), pluginComp); return (i != plugins.end()); } -bool PluginManager::checkPlugin(const MetaData& info, function<void (const string&)> err) { +void PluginManager::checkPlugin(const MetaData& info) { // Check if user is trying to load a duplicate if(isLoaded(info.guid)) { - err(str(F_("%1% is already installed") % info.name)); - return false; + throw Exception(str(F_("%1% is already installed") % info.name)); } // Check API compatibility (this should only block on absolutely wrecking api changes, which generally should not happen) if(info.apiVersion < DCAPI_CORE_VER) { - err(str(F_("%1% is too old, contact the plugin author for an update") % info.name)); - return false; + throw Exception(str(F_("%1% is too old, contact the plugin author for an update") % info.name)); } // Check that all dependencies are loaded if(info.numDependencies != 0) { for(size_t i = 0; i < info.numDependencies; ++i) { if(!isLoaded(info.dependencies[i])) { - err(str(F_("Missing dependencies for %1%") % info.name)); - return false; + throw Exception(str(F_("Missing dependencies for %1%") % info.name)); } } } - - return true; } void PluginManager::unloadPlugins() { === modified file 'dcpp/PluginManager.h' --- dcpp/PluginManager.h 2013-04-22 22:31:37 +0000 +++ dcpp/PluginManager.h 2013-04-23 15:34:45 +0000 @@ -108,10 +108,10 @@ /** Extract a dcext-packaged plugin. Throws on errors. */ DcextInfo extract(const string& path); - void install(const string& name, const string& plugin, const StringList& files); + void install(const string& uuid, const string& plugin, const StringList& files); void loadPlugins(function<void (const string&)> f); - bool loadPlugin(const string& fileName, function<void (const string&)> err, bool install = false); + void loadPlugin(const string& fileName, bool install = false); bool isLoaded(const string& guid); void unloadPlugins(); @@ -179,8 +179,8 @@ void loadSettings() noexcept; void saveSettings() noexcept; - // Check if plugin can be loaded - bool checkPlugin(const MetaData& info, function<void (const string&)> err); + // Check if the plugin can be loaded; throws if it can't. + void checkPlugin(const MetaData& info); // Listeners void on(TimerManagerListener::Second, uint64_t ticks) noexcept { runHook(HOOK_TIMER_SECOND, NULL, &ticks); } === modified file 'win32/PluginInfoDlg.cpp' --- win32/PluginInfoDlg.cpp 2013-04-22 22:31:37 +0000 +++ win32/PluginInfoDlg.cpp 2013-04-23 15:34:45 +0000 @@ -100,7 +100,7 @@ cur->column(0).align = GridInfo::BOTTOM_RIGHT; cur->setSpacing(grid->getSpacing()); WinUtil::addDlgButtons(cur, - [this, info] { handleOK(info.name, info.plugin, info.files); }, + [this, info] { handleOK(info.name, info.uuid, info.plugin, info.files); }, [this] { endDialog(IDCANCEL); }).first->setText(T_("Install the plugin")); } @@ -112,9 +112,9 @@ return false; } -void PluginInfoDlg::handleOK(const string& name, const string& plugin, const StringList& files) { +void PluginInfoDlg::handleOK(const string& name, const string& uuid, const string& plugin, const StringList& files) { try { - PluginManager::getInstance()->install(name, plugin, files); + PluginManager::getInstance()->install(uuid, plugin, files); endDialog(IDOK); } catch(const Exception& e) { === modified file 'win32/PluginInfoDlg.h' --- win32/PluginInfoDlg.h 2013-04-22 22:31:37 +0000 +++ win32/PluginInfoDlg.h 2013-04-23 15:34:45 +0000 @@ -35,7 +35,7 @@ private: bool handleInitDialog(const string& path); - void handleOK(const string& name, const string& plugin, const StringList& files); + void handleOK(const string& name, const string& uuid, const string& plugin, const StringList& files); void layout(); === modified file 'win32/PluginPage.cpp' --- win32/PluginPage.cpp 2013-04-22 22:31:37 +0000 +++ win32/PluginPage.cpp 2013-04-23 15:34:45 +0000 @@ -248,12 +248,30 @@ } void PluginPage::handleAddPlugin() { - tstring path; - if(LoadDialog(this).addFilter(T_("dcext files"), _T("*.dcext")).open(path) && - PluginInfoDlg(this, Text::fromT(path)).run() == IDOK) + tstring path_t; + if(LoadDialog(this) + .addFilter(str(TF_("%1% files") % _T("dcext")), _T("*.dcext")) + .addFilter(str(TF_("%1% files") % _T("dll")), _T("*.dll")) + .open(path_t)) { - auto pos = plugins->size(); - addEntry(pos, PluginManager::getInstance()->getPlugin(pos)->getInfo()); + auto path = Text::fromT(path_t); + auto added = false; + if(Util::getFileExt(path) == ".dcext") { + added = PluginInfoDlg(this, path).run() == IDOK; + } else { + try { + PluginManager::getInstance()->loadPlugin(path, true); + added = true; + } catch(const Exception& e) { + dwt::MessageBox(this).show(tstring(T_("Cannot install the plugin:")) + _T("\r\n\r\n") + Text::toT(e.getError()), + Text::toT(Util::getFileName(path)), dwt::MessageBox::BOX_OK, dwt::MessageBox::BOX_ICONSTOP); + } + } + + if(added) { + auto pos = plugins->size(); + addEntry(pos, PluginManager::getInstance()->getPlugin(pos)->getInfo()); + } } }
_______________________________________________ Mailing list: https://launchpad.net/~linuxdcpp-team Post to : linuxdcpp-team@lists.launchpad.net Unsubscribe : https://launchpad.net/~linuxdcpp-team More help : https://help.launchpad.net/ListHelp