linuxdcpp-team team mailing list archive
-
linuxdcpp-team team
-
Mailing list archive
-
Message #06791
[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 3271: plugins: OS differentiation in dcext; name the install dir from the UUID; rework errors
------------------------------------------------------------
revno: 3271
committer: poy <poy@xxxxxxxxxx>
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());
+ }
}
}