Skip to content

Commit 3ed3971

Browse files
committed
Update following uibase changes for extensions.
1 parent ed387d9 commit 3ed3971

File tree

6 files changed

+144
-361
lines changed

6 files changed

+144
-361
lines changed

src/plugin_python_en.ts

Lines changed: 11 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -4,78 +4,35 @@
44
<context>
55
<name>ProxyPython</name>
66
<message>
7-
<location filename="proxy/proxypython.cpp" line="88"/>
8-
<source>Python Initialization failed</source>
7+
<location filename="proxy/proxypython.cpp" line="156"/>
8+
<source>The path to Mod Organizer (%1) contains a semicolon. &lt;br&gt;While this is legal on NTFS drives, many softwares do not handle it correctly.&lt;br&gt;Unfortunately MO depends on libraries that seem to fall into that group.&lt;br&gt;As a result the python plugin cannot be loaded, and the only solution we canoffer is to remove the semicolon or move MO to a path without a semicolon.</source>
99
<translation type="unfinished"></translation>
1010
</message>
1111
<message>
12-
<location filename="proxy/proxypython.cpp" line="89"/>
13-
<source>On a previous start the Python Plugin failed to initialize.
14-
Do you want to try initializing python again (at the risk of another crash)?
15-
Suggestion: Select &quot;no&quot;, and click the warning sign for further help.Afterwards you have to re-enable the python plugin.</source>
16-
<translation type="unfinished"></translation>
17-
</message>
18-
<message>
19-
<location filename="proxy/proxypython.cpp" line="162"/>
20-
<source>Python Proxy</source>
21-
<translation type="unfinished"></translation>
22-
</message>
23-
<message>
24-
<location filename="proxy/proxypython.cpp" line="172"/>
25-
<source>Proxy Plugin to allow plugins written in python to be loaded</source>
26-
<translation type="unfinished"></translation>
27-
</message>
28-
<message>
29-
<location filename="proxy/proxypython.cpp" line="244"/>
30-
<source>ModOrganizer path contains a semicolon</source>
31-
<translation type="unfinished"></translation>
32-
</message>
33-
<message>
34-
<location filename="proxy/proxypython.cpp" line="246"/>
35-
<source>Python DLL not found</source>
36-
<translation type="unfinished"></translation>
37-
</message>
38-
<message>
39-
<location filename="proxy/proxypython.cpp" line="248"/>
40-
<source>Invalid Python DLL</source>
41-
<translation type="unfinished"></translation>
42-
</message>
43-
<message>
44-
<location filename="proxy/proxypython.cpp" line="250"/>
45-
<source>Initializing Python failed</source>
46-
<translation type="unfinished"></translation>
47-
</message>
48-
<message>
49-
<location filename="proxy/proxypython.cpp" line="252"/>
50-
<location filename="proxy/proxypython.cpp" line="281"/>
51-
<source>invalid problem key %1</source>
52-
<translation type="unfinished"></translation>
53-
</message>
54-
<message>
55-
<location filename="proxy/proxypython.cpp" line="260"/>
56-
<source>The path to Mod Organizer (%1) contains a semicolon.&lt;br&gt;While this is legal on NTFS drives, many applications do not handle it correctly.&lt;br&gt;Unfortunately MO depends on libraries that seem to fall into that group.&lt;br&gt;As a result the python plugin cannot be loaded, and the only solution we can offer is to remove the semicolon or move MO to a path without a semicolon.</source>
57-
<translation type="unfinished"></translation>
58-
</message>
59-
<message>
60-
<location filename="proxy/proxypython.cpp" line="270"/>
12+
<location filename="proxy/proxypython.cpp" line="167"/>
6113
<source>The Python plugin DLL was not found, maybe your antivirus deleted it. Re-installing MO2 might fix the problem.</source>
6214
<translation type="unfinished"></translation>
6315
</message>
6416
<message>
65-
<location filename="proxy/proxypython.cpp" line="273"/>
17+
<location filename="proxy/proxypython.cpp" line="170"/>
6618
<source>The Python plugin DLL is invalid, maybe your antivirus is blocking it. Re-installing MO2 and adding exclusions for it to your AV might fix the problem.</source>
6719
<translation type="unfinished"></translation>
6820
</message>
6921
<message>
70-
<location filename="proxy/proxypython.cpp" line="278"/>
22+
<location filename="proxy/proxypython.cpp" line="174"/>
7123
<source>The initialization of the Python plugin DLL failed, unfortunately without any details.</source>
7224
<translation type="unfinished"></translation>
7325
</message>
26+
<message>
27+
<location filename="proxy/proxypython.cpp" line="177"/>
28+
<source>no failure</source>
29+
<translation type="unfinished"></translation>
30+
</message>
7431
</context>
7532
<context>
7633
<name>QObject</name>
7734
<message>
78-
<location filename="runner/error.h" line="76"/>
35+
<location filename="runner/error.h" line="77"/>
7936
<source>An unknown exception was thrown in python code.</source>
8037
<translation type="unfinished"></translation>
8138
</message>

src/proxy/CMakeLists.txt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cmake_minimum_required(VERSION 3.16)
22

3-
set(PLUGIN_NAME "plugin_python")
3+
set(PROXY_NAME "python")
44

55
add_library(proxy SHARED)
66
mo2_configure_plugin(proxy
@@ -12,14 +12,14 @@ mo2_configure_plugin(proxy
1212
${CMAKE_CURRENT_SOURCE_DIR}/../mobase
1313
${CMAKE_CURRENT_SOURCE_DIR}/../pybind11-qt)
1414
target_link_libraries(proxy PRIVATE runner)
15-
set_target_properties(proxy PROPERTIES OUTPUT_NAME ${PLUGIN_NAME})
16-
mo2_install_target(proxy FOLDER)
15+
set_target_properties(proxy PROPERTIES OUTPUT_NAME "python_proxy")
16+
mo2_install_target(proxy INSTALLDIR "bin/proxies/python")
1717

18-
set(PLUGIN_PYTHON_DIR ${MO2_INSTALL_PATH}/bin/plugins/${PLUGIN_NAME})
18+
set(PROXY_PYTHON_DIR ${MO2_INSTALL_PATH}/bin/proxies/python)
1919

2020
# install runner
2121
target_link_options(proxy PRIVATE "/DELAYLOAD:runner.dll")
22-
mo2_install_target(runner INSTALLDIR ${PLUGIN_PYTHON_DIR}/dlls)
22+
mo2_install_target(runner INSTALLDIR ${PROXY_PYTHON_DIR}/dlls)
2323

2424
# translations (custom location)
2525
mo2_add_translations(proxy
@@ -31,14 +31,14 @@ mo2_add_translations(proxy
3131
${CMAKE_CURRENT_SOURCE_DIR}/../pybind11-qt)
3232

3333
# install DLLs files needed
34-
set(DLL_DIRS ${PLUGIN_PYTHON_DIR}/dlls)
34+
set(DLL_DIRS ${PROXY_PYTHON_DIR}/dlls)
3535
file(GLOB dlls_to_install
3636
${PYTHON_BUILD_PATH}/libffi*.dll
3737
${PYTHON_BUILD_PATH}/python${Python_VERSION_SHORT}*.dll)
3838
install(FILES ${dlls_to_install} DESTINATION ${DLL_DIRS})
3939

4040
# install Python files
41-
set(PYLIB_DIR ${PLUGIN_PYTHON_DIR}/libs)
41+
set(PYLIB_DIR ${PROXY_PYTHON_DIR}/libs)
4242
file(GLOB libs_to_install ${PYTHON_BUILD_PATH}/pythoncore/*.pyd)
4343
install(FILES ${libs_to_install} DESTINATION ${PYLIB_DIR})
4444
install(FILES ${PYTHON_BUILD_PATH}/pythoncore/python${Python_VERSION_SHORT}.zip

src/proxy/proxypython.cpp

Lines changed: 43 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -53,59 +53,26 @@ fs::path getPluginFolder()
5353
return fs::path(path).parent_path();
5454
}
5555

56-
ProxyPython::ProxyPython()
57-
: m_MOInfo{nullptr}, m_RunnerLib{nullptr}, m_Runner{nullptr},
58-
m_LoadFailure(FailureType::NONE)
59-
{
60-
}
56+
ProxyPython::ProxyPython() : m_RunnerLib{nullptr}, m_Runner{nullptr} {}
6157

62-
bool ProxyPython::init(IOrganizer* moInfo)
58+
bool ProxyPython::initialize(QString& errorMessage)
6359
{
64-
m_MOInfo = moInfo;
65-
66-
if (m_MOInfo && !m_MOInfo->isPluginEnabled(this)) {
67-
return false;
68-
}
60+
errorMessage = "";
6961

7062
if (QCoreApplication::applicationDirPath().contains(';')) {
71-
m_LoadFailure = FailureType::SEMICOLON;
63+
errorMessage = failureMessage(FailureType::SEMICOLON);
7264
return true;
7365
}
7466

7567
const auto pluginFolder = getPluginFolder();
76-
7768
if (pluginFolder.empty()) {
78-
DWORD error = ::GetLastError();
79-
m_LoadFailure = FailureType::DLL_NOT_FOUND;
69+
DWORD error = ::GetLastError();
70+
errorMessage = failureMessage(FailureType::DLL_NOT_FOUND);
8071
log::error("failed to resolve Python proxy directory ({}): {}", error,
8172
qUtf8Printable(windowsErrorString(::GetLastError())));
8273
return false;
8374
}
8475

85-
if (m_MOInfo && m_MOInfo->persistent(name(), "tryInit", false).toBool()) {
86-
m_LoadFailure = FailureType::INITIALIZATION;
87-
if (QMessageBox::question(
88-
parentWidget(), tr("Python Initialization failed"),
89-
tr("On a previous start the Python Plugin failed to initialize.\n"
90-
"Do you want to try initializing python again (at the risk of "
91-
"another crash)?\n "
92-
"Suggestion: Select \"no\", and click the warning sign for further "
93-
"help.Afterwards you have to re-enable the python plugin."),
94-
QMessageBox::Yes | QMessageBox::No,
95-
QMessageBox::No) == QMessageBox::No) {
96-
// we force enabled here (note: this is a persistent settings since MO2 2.4
97-
// or something), plugin
98-
// usually should not handle enabled/disabled themselves but this is a base
99-
// plugin so...
100-
m_MOInfo->setPersistent(name(), "enabled", false, true);
101-
return true;
102-
}
103-
}
104-
105-
if (m_MOInfo) {
106-
m_MOInfo->setPersistent(name(), "tryInit", true);
107-
}
108-
10976
// load the pythonrunner library, this is done in multiple steps:
11077
//
11178
// 1. we set the dlls/ subfolder (from the plugin) as the DLL directory so Windows
@@ -114,8 +81,8 @@ bool ProxyPython::init(IOrganizer* moInfo)
11481
//
11582
const auto dllPaths = pluginFolder / "dlls";
11683
if (SetDllDirectoryW(dllPaths.c_str()) == 0) {
117-
DWORD error = ::GetLastError();
118-
m_LoadFailure = FailureType::DLL_NOT_FOUND;
84+
DWORD error = ::GetLastError();
85+
errorMessage = failureMessage(FailureType::DLL_NOT_FOUND);
11986
log::error("failed to add python DLL directory ({}): {}", error,
12087
qUtf8Printable(windowsErrorString(::GetLastError())));
12188
return false;
@@ -129,21 +96,16 @@ bool ProxyPython::init(IOrganizer* moInfo)
12996

13097
if (m_Runner) {
13198
const auto libpath = pluginFolder / "libs";
132-
const std::vector<fs::path> paths{
133-
libpath / "pythoncore.zip", libpath,
134-
std::filesystem::path{IOrganizer::getPluginDataPath().toStdWString()}};
99+
const std::vector<fs::path> paths{libpath / "pythoncore.zip", libpath};
135100
m_Runner->initialize(paths);
136101
}
137102

138-
if (m_MOInfo) {
139-
m_MOInfo->setPersistent(name(), "tryInit", false);
140-
}
141-
142103
// reset DLL directory
143104
SetDllDirectoryW(NULL);
144105

145106
if (!m_Runner || !m_Runner->isInitialized()) {
146-
m_LoadFailure = FailureType::INITIALIZATION;
107+
errorMessage = failureMessage(FailureType::INITIALIZATION);
108+
return false;
147109
}
148110
else {
149111
m_Runner->addDllSearchPath(pluginFolder / "dlls");
@@ -152,110 +114,57 @@ bool ProxyPython::init(IOrganizer* moInfo)
152114
return true;
153115
}
154116

155-
QString ProxyPython::name() const
156-
{
157-
return "Python Proxy";
158-
}
159-
160-
QString ProxyPython::localizedName() const
161-
{
162-
return tr("Python Proxy");
163-
}
164-
165-
QString ProxyPython::author() const
166-
{
167-
return "AnyOldName3, Holt59, Silarn, Tannin";
168-
}
169-
170-
QString ProxyPython::description() const
171-
{
172-
return tr("Proxy Plugin to allow plugins written in python to be loaded");
173-
}
174-
175-
VersionInfo ProxyPython::version() const
176-
{
177-
return VersionInfo(3, 0, 0, VersionInfo::RELEASE_FINAL);
178-
}
179-
180-
QList<PluginSetting> ProxyPython::settings() const
181-
{
182-
return {};
183-
}
184-
185-
QStringList ProxyPython::pluginList(const QDir& pluginPath) const
117+
QList<QList<QObject*>> ProxyPython::load(const PluginExtension& extension)
186118
{
187-
QDir dir(pluginPath);
188-
dir.setFilter(dir.filter() | QDir::NoDotAndDotDot);
189-
QDirIterator iter(dir);
190-
191-
// Note: We put python script (.py) and directory names, not the __init__.py
192-
// files in those since it is easier for the runner to import them.
193-
QStringList result;
194-
while (iter.hasNext()) {
195-
QString name = iter.next();
196-
QFileInfo info = iter.fileInfo();
197-
198-
if (info.isFile() && name.endsWith(".py")) {
199-
result.append(name);
200-
}
201-
else if (info.isDir() && QDir(info.absoluteFilePath()).exists("__init__.py")) {
202-
result.append(name);
203-
}
119+
if (!m_Runner) {
120+
return {};
204121
}
205122

206-
return result;
207-
}
208-
209-
QList<QObject*> ProxyPython::load(const QString& identifier)
210-
{
211-
if (!m_Runner) {
123+
// currently, only handle __init__.py directly in the folder
124+
const auto pyIniFile = extension.directory() / "__init__.py";
125+
if (!exists(pyIniFile)) {
212126
return {};
213127
}
214-
return m_Runner->load(identifier);
215-
}
216128

217-
void ProxyPython::unload(const QString& identifier)
218-
{
219-
if (m_Runner) {
220-
return m_Runner->unload(identifier);
129+
m_ExtensionModules[&extension] = {pyIniFile};
130+
131+
QList<QList<QObject*>> plugins;
132+
for (auto&& pythonModule : m_ExtensionModules[&extension]) {
133+
plugins.append(m_Runner->load(pythonModule));
221134
}
135+
136+
return plugins;
222137
}
223138

224-
std::vector<unsigned int> ProxyPython::activeProblems() const
139+
void ProxyPython::unload(const PluginExtension& extension)
225140
{
226-
auto failure = m_LoadFailure;
227-
228-
// don't know how this could happen but wth
229-
if (m_Runner && !m_Runner->isInitialized()) {
230-
failure = FailureType::INITIALIZATION;
141+
if (!m_Runner) {
142+
return;
231143
}
232144

233-
if (failure != FailureType::NONE) {
234-
return {static_cast<std::underlying_type_t<FailureType>>(failure)};
145+
if (auto it = m_ExtensionModules.find(&extension); it != m_ExtensionModules.end()) {
146+
for (auto&& pythonModule : it->second) {
147+
m_Runner->unload(pythonModule);
148+
}
149+
m_ExtensionModules.erase(it);
235150
}
236-
237-
return {};
238151
}
239152

240-
QString ProxyPython::shortDescription(unsigned int key) const
153+
void ProxyPython::unloadAll()
241154
{
242-
switch (static_cast<FailureType>(key)) {
243-
case FailureType::SEMICOLON:
244-
return tr("ModOrganizer path contains a semicolon");
245-
case FailureType::DLL_NOT_FOUND:
246-
return tr("Python DLL not found");
247-
case FailureType::INVALID_DLL:
248-
return tr("Invalid Python DLL");
249-
case FailureType::INITIALIZATION:
250-
return tr("Initializing Python failed");
251-
default:
252-
return tr("invalid problem key %1").arg(key);
155+
if (m_Runner) {
156+
for (auto& [ext, modules] : m_ExtensionModules) {
157+
for (auto& pythonModule : modules) {
158+
m_Runner->unload(pythonModule);
159+
}
160+
}
253161
}
162+
m_ExtensionModules.clear();
254163
}
255164

256-
QString ProxyPython::fullDescription(unsigned int key) const
165+
QString ProxyPython::failureMessage(FailureType key)
257166
{
258-
switch (static_cast<FailureType>(key)) {
167+
switch (key) {
259168
case FailureType::SEMICOLON:
260169
return tr("The path to Mod Organizer (%1) contains a semicolon.<br>"
261170
"While this is legal on NTFS drives, many applications do not "
@@ -278,13 +187,6 @@ QString ProxyPython::fullDescription(unsigned int key) const
278187
return tr("The initialization of the Python plugin DLL failed, unfortunately "
279188
"without any details.");
280189
default:
281-
return tr("invalid problem key %1").arg(key);
190+
return tr("no failure");
282191
}
283192
}
284-
285-
bool ProxyPython::hasGuidedFix(unsigned int) const
286-
{
287-
return false;
288-
}
289-
290-
void ProxyPython::startGuidedFix(unsigned int) const {}

0 commit comments

Comments
 (0)