From a84cbe8f695e395e4eafb39158c7fc870403fe31 Mon Sep 17 00:00:00 2001 From: Don Ho Date: Tue, 8 Mar 2022 05:19:01 +0100 Subject: [PATCH] Add new ability for filtering incompatible plugins In commit https://github.com/notepad-plus-plus/notepad-plus-plus/commit/f9118dd13c637a4054c101e685c9030115f790c8 **"npp-compatible-versions"** has been added in plugin list for helping not only Plugin Admin, but also Plugin Manager (Plugin Loader) to check the compatibility with the latest version of plugin (if the version of installed plugin is the latest one). However, if the version of installed plugin is the previous one, there's no info to know if this plugin with old version is compatible with running Notepad++. In order to filter better old version plugins, **"old-versions-compatibility"** is added in plugin list, so Plugin Manager can use it to check the compatibility to decide load it or not. The value of "old-versions-compatibility" is a string made by 2 interval versions as following: `"old-versions-compatibility": "[,2.6][,8.2.1]"` The first interval versions are for old plugin versions: [,2.6] means from all the versions to v2.6 included. The second interval versions are for Notepad++ versions: [,8.2.1] means from all the versions to v8.2.1 included. Both interval versions together means: the plugin in question from the 1st version to v2.6 is compatible with Notepad++ v8.2.1 and all Notepad++ previous versions. Here is the sample: ```json { "folder-name": "mimeTools", "display-name": "Mime tools", "version": "2.7", "npp-compatible-versions": "[8.3,]", "old-versions-compatibility": "[,2.6][,8.2.1]", "id": "b65fbfaa15b443131eb69188069cacbff04eca66e0cb84130631303a1d3895f8", "repository": "https://github.com/npp-plugins/mimetools/releases/download/v2.7/mimetools.v2.7.zip", "description": "Implements several main functionalities defined in MIME.", "author": "Don HO", "homepage": "https://github.com/npp-plugins/mimetools" }, ``` Considering these 2 scenarios: 1. The current distributed plugin version is v2.7 (the latest one normally), and it is compatible with all Notepad++ version from v8.3. If installed MineTools plugin is v2.7 and running Notepad++ is v8.3.3 then it's OK, and MineTools v2.7 will be loaded. 2. If installed MineTools plugin is v2.6 and running Notepad++ is v8.3.3 then Plugin Manager learns it's a previous version (v2.6 < v2.7), so it will check "old-versions-compatibility" - it will find v2.6 is in the 1st interval [,2.6] - it's matched, then Plugin Manager keep checking the running Notepad++'s compatibility: v8.3.3 is not in the 2nd interval [,8.2.1] - it's not compatible, then MineTools plugin v2.6 won't be loaded. Here are the test instructions for this PR: 1. download x64 debug binary here: https://ci.appveyor.com/api/buildjobs/5ba501ecu21k28i7/artifacts/Notepad%2B%2B.x64.Debug.exe 2. Create an empty file "nppPluginList.json" in your `npp\plugins\Config\` and copy the following content https://github.com/notepad-plus-plus/nppPluginList/blob/5e23fce86813ae434dd123bb33b1dcd7db346050/src/pl.x64.json and paste into `npp\plugins\Config\nppPluginList.json` You have to copy "updater" folder (which contains GUP.exe) to enable plugin list. 3. Download DSpellCheck plugin v1.4.22 which is not compatible with Notepad++ from v8.3 and later version here: https://github.com/Predelnik/DSpellCheck/releases/download/v1.4.22/DSpellCheck_x64.zip Install it into plugin folder manually. 4. Now launch Notepad++ x64 debug binary and watch it crash. 5. Edit "nppPluginList.json" by adding `"old-versions-compatibility": "[,1.4.22][,8.2.1]",` into DSpellCheck section. 6. Startup Notepad++. Notepad++ doesn't crash. and now you can check DSpellCheck plugin is not loaded on the startup. Fix #11358, fix #11349, close #11356 --- .../MISC/PluginsManager/PluginsManager.cpp | 22 +++++++++++-- .../WinControls/PluginsAdmin/pluginsAdmin.cpp | 31 ++++++++++++++++++- .../WinControls/PluginsAdmin/pluginsAdmin.h | 7 +++++ 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/PowerEditor/src/MISC/PluginsManager/PluginsManager.cpp b/PowerEditor/src/MISC/PluginsManager/PluginsManager.cpp index 9ddd15cd1..ed39c9fbc 100644 --- a/PowerEditor/src/MISC/PluginsManager/PluginsManager.cpp +++ b/PowerEditor/src/MISC/PluginsManager/PluginsManager.cpp @@ -355,11 +355,20 @@ bool PluginsManager::loadPluginsV2(const TCHAR* dir, const PluginViewList* plugi // Find plugin version Version v; v.setVersionFrom(pluginsFullPathFilter); - if (pui->_version == v) + if (v == pui->_version) { // Find compatible Notepad++ versions isCompatible = nppVer.isCompatibleTo(pui->_nppCompatibleVersions.first, pui->_nppCompatibleVersions.second); } + else if (v < pui->_version && // If dll version is older, and _oldVersionCompatibility is valid (not empty), we search in "_oldVersionCompatibility" + !(pui->_oldVersionCompatibility.first.first.empty() && pui->_oldVersionCompatibility.first.second.empty()) && // first version interval is valid + !(pui->_oldVersionCompatibility.first.second.empty() && pui->_oldVersionCompatibility.second.second.empty())) // second version interval is valid + { + if (v.isCompatibleTo(pui->_oldVersionCompatibility.first.first, pui->_oldVersionCompatibility.first.second)) // dll older version found + { + isCompatible = nppVer.isCompatibleTo(pui->_oldVersionCompatibility.second.first, pui->_oldVersionCompatibility.second.second); + } + } } } @@ -404,11 +413,20 @@ bool PluginsManager::loadPluginsV2(const TCHAR* dir, const PluginViewList* plugi // Find plugin version Version v2; v2.setVersionFrom(pluginsFullPathFilter2); - if (pui2->_version == v2) + if (v2 == pui2->_version) { // Find compatible Notepad++ versions isCompatible2 = nppVer.isCompatibleTo(pui2->_nppCompatibleVersions.first, pui2->_nppCompatibleVersions.second); } + else if (v2 < pui2->_version && // If dll version is older, and _oldVersionCompatibility is valid (not empty), we search in "_oldVersionCompatibility" + !(pui2->_oldVersionCompatibility.first.first.empty() && pui2->_oldVersionCompatibility.first.second.empty()) && // first version interval is valid + !(pui2->_oldVersionCompatibility.first.second.empty() && pui2->_oldVersionCompatibility.second.second.empty())) // second version interval is valid + { + if (v2.isCompatibleTo(pui2->_oldVersionCompatibility.first.first, pui2->_oldVersionCompatibility.first.second)) // dll older version found + { + isCompatible2 = nppVer.isCompatibleTo(pui2->_oldVersionCompatibility.second.first, pui2->_oldVersionCompatibility.second.second); + } + } } } diff --git a/PowerEditor/src/WinControls/PluginsAdmin/pluginsAdmin.cpp b/PowerEditor/src/WinControls/PluginsAdmin/pluginsAdmin.cpp index f86b90c14..8a091ad1f 100644 --- a/PowerEditor/src/WinControls/PluginsAdmin/pluginsAdmin.cpp +++ b/PowerEditor/src/WinControls/PluginsAdmin/pluginsAdmin.cpp @@ -558,6 +558,27 @@ std::pair getIntervalVersions(generic_string intervalVerStr) return result; } +// twoIntervalVerStr format: +// "[4.2,6.6.6][6.4,8.9]" : The 1st interval from version 4.2 to 6.6.6 inclusive, the 2nd interval from version 6.4 to 8.9 +// "[8.3,][6.9,6.9]" : The 1st interval any version from 8.3 to the latest version, the 2nd interval present only version 6.9 +// "[,8.2.1][4.4,]" : The 1st interval 8.2.1 and any previous version, , the 2nd interval any version from 4.4 to the latest version +std::pair, std::pair> getTwoIntervalVersions(generic_string twoIntervalVerStr) +{ + std::pair, std::pair> r; + generic_string sep = TEXT("]["); + generic_string::size_type pos = twoIntervalVerStr.find(sep, 0); + if (pos == string::npos) + return r; + + generic_string intervalStr1 = twoIntervalVerStr.substr(0, pos + 1); + generic_string intervalStr2 = twoIntervalVerStr.substr(pos + 1, twoIntervalVerStr.length() - pos + 1); + + r.first = getIntervalVersions(intervalStr1); + r.second = getIntervalVersions(intervalStr2); + + return r; +} + bool loadFromJson(std::vector& pl, const json& j) { if (j.empty()) @@ -602,13 +623,21 @@ bool loadFromJson(std::vector& pl, const json& j) pi->_nppCompatibleVersions = getIntervalVersions(nppCompatibleVersionStr); } + if (i.contains("old-versions-compatibility")) + { + json jOldVerCompatibility = i["old-versions-compatibility"]; + + string versionsStr = jOldVerCompatibility.get(); + generic_string oldVerCompatibilityStr(versionsStr.begin(), versionsStr.end()); + pi->_oldVersionCompatibility = getTwoIntervalVersions(oldVerCompatibilityStr); + } + valStr = i.at("repository").get(); pi->_repository = wmc.char2wchar(valStr.c_str(), CP_ACP); valStr = i.at("homepage").get(); pi->_homepage = wmc.char2wchar(valStr.c_str(), CP_ACP); - pl.push_back(pi); } #ifdef DEBUG diff --git a/PowerEditor/src/WinControls/PluginsAdmin/pluginsAdmin.h b/PowerEditor/src/WinControls/PluginsAdmin/pluginsAdmin.h index 798d22565..d92c9beaf 100644 --- a/PowerEditor/src/WinControls/PluginsAdmin/pluginsAdmin.h +++ b/PowerEditor/src/WinControls/PluginsAdmin/pluginsAdmin.h @@ -40,6 +40,13 @@ struct PluginUpdateInfo // <4.2, 6.6.6>: from v4.2 (included) to v6.6.6 (included) // <0.0.0.0, 8.2.1> all until v8.2.1 (included) // <8.3, 0.0.0.0> from v8.3 (included) to all + + // Optional + std::pair, std::pair> _oldVersionCompatibility; // Used only by Plugin Manager to filter plugins while loading plugins + // The 1st interval versions are for old plugins' versions + // The 2nd interval versions are for Notepad++ versions + // which are compatible with the old plugins' versions given in the 1st interval + generic_string _homepage; generic_string _sourceUrl; generic_string _description;