Example #1
0
bool addons_client::install_addon(config& archive_cfg, const addon_info& info)
{
	const cursor::setter cursor_setter(cursor::WAIT);

	utils::string_map i18n_symbols;
	i18n_symbols["addon_title"] = font::escape_text(info.title);

	if(!check_names_legal(archive_cfg)) {
		gui2::show_error_message(
			VGETTEXT("The add-on <i>$addon_title</i> has an invalid file or directory "
				"name and cannot be installed.", i18n_symbols));
		return false;
	}
	if(!check_case_insensitive_duplicates(archive_cfg)){
		gui2::show_error_message(
			VGETTEXT("The add-on <i>$addon_title</i> has file or directory names "
				"with case conflicts. This may cause problems.", i18n_symbols));
	}

	// Add local version information before unpacking

	config* maindir = &archive_cfg.find_child("dir", "name", info.id);
	if(!*maindir) {
		LOG_ADDONS << "downloaded add-on '" << info.id << "' is missing its directory in the archive; creating it\n";
		maindir = &archive_cfg.add_child("dir");
		(*maindir)["name"] = info.id;
	}

	LOG_ADDONS << "generating version info for add-on '" << info.id << "'\n";

	std::ostringstream info_contents;
	config wml;

	info_contents <<
		"#\n"
		"# File automatically generated by Wesnoth to keep track\n"
		"# of version information on installed add-ons. DO NOT EDIT!\n"
		"#\n";

	info.write_minimal(wml.add_child("info"));
	write(info_contents, wml);

	config file;
	file["name"] = "_info.cfg";
	file["contents"] = info_contents.str();

	maindir->add_child("file", file);

	LOG_ADDONS << "unpacking " << info.id << '\n';

	// Remove any previously installed versions
	if(!remove_local_addon(info.id)) {
		WRN_ADDONS << "failed to uninstall previous version of " << info.id << "; the add-on may not work properly!" << std::endl;
	}

	unarchive_addon(archive_cfg);
	LOG_ADDONS << "unpacking finished\n";

	return true;
}
Example #2
0
/** 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);
		}
Example #3
0
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;
}