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:
WrinklyNinja
2013-06-06 08:26:23 +01:00
parent b4096b65de
commit 6302e8e739
3 changed files with 103 additions and 8 deletions
+86 -7
View File
@@ -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());
+5
View File
@@ -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
View File
@@ -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)