void read_addons_list(const config& cfg, addons_list& dest) { dest.clear(); unsigned order = 0; /** @todo FIXME: get rid of this legacy "campaign"/"campaigns" silliness */ const config::const_child_itors &addon_cfgs = cfg.child_range("campaign"); for(const config& addon_cfg : addon_cfgs) { const std::string& id = addon_cfg["name"].str(); if(dest.find(id) != dest.end()) { ERR_AC << "add-ons list has multiple entries for '" << id << "', not good; ignoring them" << std::endl; continue; } dest[id].read(addon_cfg); dest[id].order = order++; } }
/** Warns the user about unresolved dependencies and installs them if they choose to do so. * Returns: outcome: ABORT in case the user chose to abort because of an issue * SUCCESS otherwise * wml_change: indicates if new wml content was installed */ addon_op_result do_resolve_addon_dependencies(display& disp, addons_client& client, const addons_list& addons, const addon_info& addon) { addon_op_result result; result.outcome = SUCCESS; result.wml_changed = false; boost::scoped_ptr<cursor::setter> cursor_setter(new cursor::setter(cursor::WAIT)); // TODO: We don't currently check for the need to upgrade. I'll probably // work on that when implementing dependency tiers later. const std::set<std::string>& deps = addon.resolve_dependencies(addons); std::vector<std::string> missing_deps; std::vector<std::string> broken_deps; BOOST_FOREACH(const std::string& dep, deps) { if(!is_addon_installed(dep)) { if(addons.find(dep) != addons.end()) { missing_deps.push_back(dep); } else { broken_deps.push_back(dep); } } } cursor_setter.reset(); if(!broken_deps.empty()) { std::string broken_deps_report; broken_deps_report = _n( "The selected add-on has the following dependency, which is not currently installed or available from the server. Do you wish to continue?", "The selected add-on has the following dependencies, which are not currently installed or available from the server. Do you wish to continue?", broken_deps.size()); broken_deps_report += "\n"; BOOST_FOREACH(const std::string& broken_dep_id, broken_deps) { broken_deps_report += "\n " + utils::unicode_bullet + " " + make_addon_title(broken_dep_id); }
std::string make_display_dependencies( const std::string& addon_id, const addons_list& addons_list, const addons_tracking_list& addon_states) { const addon_info& addon = const_at(addon_id, addons_list); std::string str; const std::set<std::string>& deps = addon.resolve_dependencies(addons_list); for(const auto& dep_id : deps) { addon_info dep; addon_tracking_info depstate; addons_list::const_iterator ali = addons_list.find(dep_id); addons_tracking_list::const_iterator tli = addon_states.find(dep_id); if(ali == addons_list.end()) { dep.id = dep_id; // Build dummy addon_info. } else { dep = ali->second; } if(tli == addon_states.end()) { depstate = get_addon_tracking_info(dep); } else { depstate = tli->second; } if(!str.empty()) { str += ", "; } str += addon_list::colorize_addon_state_string(dep.display_title(), depstate.state); } return str; }
addons_client::install_result addons_client::do_resolve_addon_dependencies(const addons_list& addons, const addon_info& addon) { install_result result; result.outcome = install_outcome::success; result.wml_changed = false; auto cursor_setter = std::make_unique<cursor::setter>(cursor::WAIT); // TODO: We don't currently check for the need to upgrade. I'll probably // work on that when implementing dependency tiers later. const std::set<std::string>& deps = addon.resolve_dependencies(addons); std::vector<std::string> missing_deps; std::vector<std::string> broken_deps; for(const std::string& dep : deps) { try { addon_tracking_info info = get_addon_tracking_info(addons.at(dep)); // ADDON_NONE means not installed. if(info.state == ADDON_NONE) { missing_deps.push_back(dep); } else if(info.state == ADDON_INSTALLED_UPGRADABLE) { // Tight now, we don't need to distinguish the lists of missing // and outdated addons, so just add them to missing. missing_deps.push_back(dep); } } catch(const std::out_of_range&) { // Dependency wasn't found on server, check locally directly. if(!is_addon_installed(dep)) { broken_deps.push_back(dep); } } } cursor_setter.reset(); if(!broken_deps.empty()) { std::string broken_deps_report; broken_deps_report = _n( "The selected add-on has the following dependency, which is not currently installed or available from the server. Do you wish to continue?", "The selected add-on has the following dependencies, which are not currently installed or available from the server. Do you wish to continue?", broken_deps.size()); broken_deps_report += "\n"; for(const std::string& broken_dep_id : broken_deps) { broken_deps_report += "\n " + font::unicode_bullet + " " + make_addon_title(broken_dep_id); } if(gui2::show_message(_("Broken Dependencies"), broken_deps_report, gui2::dialogs::message::yes_no_buttons) != gui2::retval::OK) { result.outcome = install_outcome::abort; return result; // canceled by user } } if(missing_deps.empty()) { // No dependencies to install, carry on. return result; } { addons_list options; for(const std::string& dep : missing_deps) { options[dep] = addons.at(dep); } gui2::dialogs::install_dependencies dlg(options); bool cont = dlg.show(); if(!cont) { return result; // the user has chosen to continue without installing anything. } } // // Install dependencies now. // std::vector<std::string> failed_titles; for(const std::string& dep : missing_deps) { const addon_info& missing_addon = addons.at(dep); if(!try_fetch_addon(missing_addon)) { failed_titles.push_back(missing_addon.title); } else { result.wml_changed = true; } } if(!failed_titles.empty()) { const std::string& failed_deps_report = _n( "The following dependency could not be installed. Do you still wish to continue?", "The following dependencies could not be installed. Do you still wish to continue?", failed_titles.size()) + std::string("\n\n") + utils::bullet_list(failed_titles); result.outcome = gui2::show_message(_("Dependencies Installation Failed"), failed_deps_report, gui2::dialogs::message::yes_no_buttons) == gui2::retval::OK ? install_outcome::success : install_outcome::abort; // If the user cancels, return abort. Otherwise, return success, since the user chose to ignore the failure. return result; } return result; }