mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Started work on issue #10.
If a circular dependency is detected, sorting should not take place, since it would get stuck in an infinite loop. Consistency checks are unoptimised.
This commit is contained in:
@@ -500,13 +500,9 @@ namespace boss {
|
||||
}
|
||||
|
||||
bool Plugin::MustLoadAfter(const Plugin& plugin) const {
|
||||
for (vector<string>::const_iterator it=masters.begin(), endIt=masters.end(); it != endIt; ++it) {
|
||||
if (boost::iequals(*it, plugin.Name()))
|
||||
return true;
|
||||
}
|
||||
if (find(requirements.begin(), requirements.end(), plugin) != requirements.end())
|
||||
return true;
|
||||
if (find(loadAfter.begin(), loadAfter.end(), plugin) != loadAfter.end())
|
||||
if (find(masters.begin(), masters.end(), plugin) != masters.end()
|
||||
|| find(requirements.begin(), requirements.end(), plugin) != requirements.end()
|
||||
|| find(loadAfter.begin(), loadAfter.end(), plugin) != loadAfter.end())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@@ -530,9 +526,92 @@ namespace boss {
|
||||
return issues;
|
||||
}
|
||||
|
||||
std::map<std::string,bool> Plugin::CheckSelfConsistency(const list<Plugin>& plugins, std::set<std::string> branch, set<std::string> incs, set<std::string> reqs) const {
|
||||
map<string,bool> issues;
|
||||
//Add this plugin and its incompatibilities to the set.
|
||||
if (!branch.insert(boost::to_lower_copy(name)).second) {
|
||||
issues.insert(pair<string, bool>(name, false));
|
||||
return issues; //Prevent infinite recursion.
|
||||
}
|
||||
for (set<File>::const_iterator it=incompatibilities.begin(), endit=incompatibilities.end(); it != endit; ++it) {
|
||||
incs.insert(boost::to_lower_copy(it->Name()));
|
||||
}
|
||||
for (vector<string>::const_iterator it=masters.begin(), endit=masters.end(); it != endit; ++it) {
|
||||
reqs.insert(boost::to_lower_copy(*it));
|
||||
}
|
||||
for (set<File>::const_iterator it=requirements.begin(), endit=requirements.end(); it != endit; ++it) {
|
||||
reqs.insert(boost::to_lower_copy(it->Name()));
|
||||
}
|
||||
for (set<File>::const_iterator it=loadAfter.begin(), endIt=loadAfter.end(); it != endIt; ++it) {
|
||||
reqs.insert(boost::to_lower_copy(it->Name()));
|
||||
}
|
||||
|
||||
//Check 1: None of this plugin's masters or requirements or 'load after' plugins may be in branch.
|
||||
//Check 2: None of this plugin's masters or requirements or 'load after' plugins may be in incs.
|
||||
//Check 3: None of this plugin's incompatibilities may be present in branch.
|
||||
//Check 4: This plugin must not be present in incs.
|
||||
//Check 5: This plugin must not be present in branch (performed above).
|
||||
//Also check the consistency of the plugins this plugin is dependent on.
|
||||
for (vector<string>::const_iterator it=masters.begin(), endit=masters.end(); it != endit; ++it) {
|
||||
if (branch.find(boost::to_lower_copy(*it)) != branch.end())
|
||||
issues.insert(pair<string, bool>(*it, true));
|
||||
if (incs.find(boost::to_lower_copy(*it)) != incs.end())
|
||||
issues.insert(pair<string, bool>(*it, false));
|
||||
list<Plugin>::const_iterator pluginIt = find(plugins.begin(), plugins.end(), *it);
|
||||
if (pluginIt != plugins.end()) {
|
||||
map<string,bool> childIssues = pluginIt->CheckSelfConsistency(plugins, branch, incs, reqs);
|
||||
issues.insert(childIssues.begin(), childIssues.end());
|
||||
}
|
||||
}
|
||||
for (set<File>::const_iterator it=requirements.begin(), endIt=requirements.end(); it != endIt; ++it) {
|
||||
if (branch.find(boost::to_lower_copy(it->Name())) != branch.end())
|
||||
issues.insert(pair<string, bool>(it->Name(), true));
|
||||
if (incs.find(boost::to_lower_copy(it->Name())) != incs.end())
|
||||
issues.insert(pair<string, bool>(it->Name(), false));
|
||||
list<Plugin>::const_iterator pluginIt = find(plugins.begin(), plugins.end(), *it);
|
||||
if (pluginIt != plugins.end()) {
|
||||
map<string,bool> childIssues = pluginIt->CheckSelfConsistency(plugins, branch, incs, reqs);
|
||||
issues.insert(childIssues.begin(), childIssues.end());
|
||||
}
|
||||
}
|
||||
for (set<File>::const_iterator it=loadAfter.begin(), endIt=loadAfter.end(); it != endIt; ++it) {
|
||||
if (branch.find(boost::to_lower_copy(it->Name())) != branch.end())
|
||||
issues.insert(pair<string, bool>(it->Name(), true));
|
||||
if (incs.find(boost::to_lower_copy(it->Name())) != incs.end())
|
||||
issues.insert(pair<string, bool>(it->Name(), false));
|
||||
list<Plugin>::const_iterator pluginIt = find(plugins.begin(), plugins.end(), *it);
|
||||
if (pluginIt != plugins.end()) {
|
||||
map<string,bool> childIssues = pluginIt->CheckSelfConsistency(plugins, branch, incs, reqs);
|
||||
issues.insert(childIssues.begin(), childIssues.end());
|
||||
}
|
||||
}
|
||||
for (set<File>::const_iterator it=incompatibilities.begin(), endIt=incompatibilities.end(); it != endIt; ++it) {
|
||||
if (branch.find(boost::to_lower_copy(it->Name())) != branch.end())
|
||||
issues.insert(pair<string, bool>(it->Name(), false));
|
||||
if (reqs.find(boost::to_lower_copy(it->Name())) != reqs.end())
|
||||
issues.insert(pair<string, bool>(it->Name(), false));
|
||||
}
|
||||
if (incs.find(boost::to_lower_copy(name)) != incs.end())
|
||||
issues.insert(pair<string, bool>(name, false));
|
||||
|
||||
return issues;
|
||||
}
|
||||
|
||||
bool operator == (const File& lhs, const Plugin& rhs) {
|
||||
return boost::iequals(lhs.Name(), rhs.Name());
|
||||
}
|
||||
|
||||
bool operator == (const Plugin& lhs, const File& rhs) {
|
||||
return rhs == lhs;
|
||||
}
|
||||
|
||||
bool operator == (const std::string& lhs, const Plugin& rhs) {
|
||||
return boost::iequals(lhs, rhs.Name());
|
||||
}
|
||||
|
||||
bool operator == (const Plugin& lhs, const std::string& rhs) {
|
||||
return rhs == lhs;
|
||||
}
|
||||
|
||||
bool alpha_sort(const Plugin& lhs, const Plugin& rhs) {
|
||||
return boost::ilexicographical_compare(lhs.Name(), rhs.Name());
|
||||
|
||||
@@ -164,6 +164,7 @@ namespace boss {
|
||||
|
||||
//Validity checks.
|
||||
std::map<std::string,bool> CheckInstallValidity(const Game& game) const; //Checks that reqs and masters are all present, and that no incs are present. Returns a map of filenames and whether they are missing (if bool is true, then filename is a req or master, otherwise it's an inc).
|
||||
std::map<std::string,bool> CheckSelfConsistency(const std::list<Plugin>& plugins, std::set<std::string> branch, std::set<std::string> incs, std::set<std::string> reqs) const;
|
||||
private:
|
||||
std::string name;
|
||||
bool enabled; //Default to true.
|
||||
@@ -181,6 +182,10 @@ namespace boss {
|
||||
};
|
||||
|
||||
bool operator == (const File& lhs, const Plugin& rhs);
|
||||
|
||||
bool operator == (const Plugin& lhs, const File& rhs);
|
||||
|
||||
bool operator == (const std::string& lhs, const Plugin& rhs);
|
||||
|
||||
bool alpha_sort(const Plugin& lhs, const Plugin& rhs);
|
||||
|
||||
|
||||
+12
-1
@@ -437,8 +437,19 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
|
||||
|
||||
progDia->Pulse();
|
||||
|
||||
//Check that the metadata is self-consistent.
|
||||
set<string> dependencies, incompatibilities, reqs;
|
||||
map<string, bool> issues;
|
||||
issues = it->CheckSelfConsistency(plugins, dependencies, incompatibilities, reqs);
|
||||
for (map<string,bool>::const_iterator jt=issues.begin(), endJt=issues.end(); jt != endJt; ++jt) {
|
||||
if (jt->second)
|
||||
messages.push_back(boss::Message(boss::MESSAGE_ERROR, "For \"" + it->Name() + "\", \"" + jt->first + "\" is a circular dependency."));
|
||||
else
|
||||
messages.push_back(boss::Message(boss::MESSAGE_ERROR, "For \"" + it->Name() + "\", \"" + jt->first + "\" is given as a dependency and an incompatibility."));
|
||||
}
|
||||
|
||||
//Also check install validity.
|
||||
map<string, bool> issues = it->CheckInstallValidity(_game);
|
||||
issues = it->CheckInstallValidity(_game);
|
||||
list<boss::Message> messages = it->Messages();
|
||||
for (map<string,bool>::const_iterator jt=issues.begin(), endJt=issues.end(); jt != endJt; ++jt) {
|
||||
if (jt->second)
|
||||
|
||||
Reference in New Issue
Block a user