ACC SHELL

Path : /usr/share/YaST2/clients/
File Upload :
Current File : //usr/share/YaST2/clients/update_proposal.ycp

/**
 * Module:	update_proposal.ycp
 *
 * Author:	Arvin Schnell <arvin@suse.de>
 *
 * Purpose:	Let user choose update settings.
 *
 * $Id: update_proposal.ycp 60593 2010-01-28 10:12:45Z locilka $
 */
{
    textdomain "update";

    import "HTML";
    import "Update";
    import "RootPart";
    import "Packages";
    import "PackageCallbacks";
    import "SpaceCalculation";

    import "Installation";
    import "Popup";
    import "ProductFeatures";
    import "Product";
    import "FileUtils";
    import "Label";
    import "Stage";


    string func = (string) WFM::Args(0);
    map param = (map) WFM::Args(1);
    map <string, any> ret = $[];
    
    boolean rpm_db_existency_checked_already = false;

    /**
     * Function returns map of upgrade-configuration.
     * Some keys might be missing. In that case, the default libzypp
     * values will be used. See FATE #301990 and bnc #238488.
     * The keys should be matching keys for Pkg::PkgUpdateAll().
     * "keep_installed_patches" were removed by bnc #349533.
     *
     * @return map <string, any> with a configuration
     *
     * @struct $[
     *     "delete_unmaintained" : boolean,
     *     "silent_downgrades" : boolean,
     * ]
     */
    map <string, any> GetUpdateConf () {
	// 'nil' values are skipped, in that case, ZYPP uses own default values
	map <string, boolean> ret = $[];

// not supported by libzypp anymore
//	if (Update::deleteOldPackages != nil) {
//	    ret["delete_unmaintained"] = Update::deleteOldPackages;
//	}

	if (Update::silentlyDowngradePackages != nil) {
	    ret["silent_downgrades"] = Update::silentlyDowngradePackages;
	}

	y2milestone ("Using update configuration: %1", ret);
	
	return ret;
    }

    // bugzilla #148105
    // Check the current RPM Database if exists
    //
    // RPM DB found -> return true
    // RPM DB not found & skipped -> return true
    // RPM DB not found & aborted -> return false
    //
    boolean CheckRPMDBforExistency () {
	y2milestone ("Checking the current RPM Database in '%1'...", Installation::destdir);

	// at least one must be there, the second one is for RPM v3
	list <string> rpm_db_files = [ "/var/lib/rpm/Packages", "/var/lib/rpm/packages.rpm" ];
	boolean ret = false;
	boolean file_found_or_error_skipped = false;
	
	while (! file_found_or_error_skipped) {
	    foreach (string check_file, rpm_db_files, {
		if (Installation::destdir != "/")
		    check_file = sformat("%1%2", Installation::destdir, check_file);
		if (FileUtils::Exists (check_file)) {
		    y2milestone ("RPM Database '%1' found", check_file);
		    ret = true;
		    file_found_or_error_skipped = true;
		    break;
		}
	    });
	    
	    // file not found
	    if (! ret) {
		y2error ("None of files %1 exist in '%2'",
		    rpm_db_files, Installation::destdir
		);
	    
		string missing_files = "";
		foreach (string check_file, rpm_db_files, {
		    if (Installation::destdir != "/")
			check_file = sformat("%1%2", Installation::destdir, check_file);
		    missing_files = missing_files + "\n" + check_file;
		});

		UI::OpenDialog (
		    `opt(`decorated),
		    `VBox (
			// popup error
			`Label (
			    // part of error popup message
			    _("Cannot read the current RPM Database.") + "\n\n" +
			    // part of error popup message, %1 stands for newline-separated list of files
			    sformat (_("None of these files exist:%1"), missing_files) + "\n\n"
			),
			`HBox (
			    `PushButton (`id(`abort),  Label::AbortButton()),
			    `PushButton (`id(`retry),  Label::RetryButton())
			    // disabled button - bugzilla #148105, comments #22 - #28
			    // `PushButton (`id(`ignore), Label::IgnoreButton())
			)
		    )
		);
	    
		any ui_r = UI::UserInput();
	    
		if (ui_r == `cancel || ui_r == `abort) {
		    ret = false;
		    file_found_or_error_skipped = true;
		    y2milestone ("Check failed, returning error.");
		} else if (ui_r == `retry) {
		    file_found_or_error_skipped = false;
		    y2milestone ("Trying again...");
		//} else if (ui_r == `ignore) {
		//    ret = true;
		//    file_found_or_error_skipped = true;
		//    y2warning ("Skipping missing RPM Database, problems might occur...");
		} else {
		    file_found_or_error_skipped = false;
		    y2error ("Unexpected return: %1", ui_r);
		}

		UI::CloseDialog();
	    }
	}
	
	y2milestone ("CheckRPMDBforExistency - returning: %1", ret);
	return ret;
    }

    define void init_stuff ()
    {
	// initialize package manager
	Packages::Init(true);

	// initialize target
	if (true)
	{
	    PackageCallbacks::SetConvertDBCallbacks ();

	    Pkg::TargetInit (Installation::destdir, false);

	    Update::GetProductName ();
	}

	// FATE #301990, Bugzilla #238488
	// Set initial update-related (packages/patches) values from control file
	Update::InitUpdate();
	
	// some products are listed in media control file and at least one is compatible
	// with system just being updated
	boolean update_not_possible = false;

	// FATE #301844
	y2milestone ("Previous '%1', New '%2' RootPart",
	    RootPart::previousRootPartition, RootPart::selectedRootPartition);
	if (RootPart::previousRootPartition != RootPart::selectedRootPartition) {
	    RootPart::previousRootPartition = RootPart::selectedRootPartition;
	    
	    // check whether update is possible
	    // reset deleteOldPackages and onlyUpdateInstalled in respect to the selected system
	    Update::Reset();
	    if (! Update::IsProductSupportedForUpgrade()) {
		y2milestone ("Upgrade is not supported");
		update_not_possible = true;
	    }
	}

	// connect target with package manager
	if (!Update::did_init1)
	{
	    Update::did_init1 = true;

	    if (size (Pkg::ResolvableProperties ("", `pattern, "")) > 0)
	    {
		y2milestone ("No base selection found, but patterns found...");
		Packages::using_patterns = true;
	    }

	    list<string> restore = [];
	    list<map<string,any> > selected = Pkg::ResolvableProperties ("", `product, "");
	    foreach (map<string,any> s, selected, {
	        restore = add (restore, s["name"]:"");
	    });

	    Pkg::PkgApplReset ();

	    // bnc #300540
	    // bnc #391785
	    // Drops packages after PkgApplReset, not before (that would null that)
	    Update::DropObsoletePackages();

	    foreach (string res, restore, {
	        Pkg::ResolvableInstall (res, `product);
	    });
	    if (! Update::onlyUpdateInstalled)
	    {
		    if (Packages::using_patterns)
		    {
			Update::SetDesktopPattern ();
		    }
		    else
		    {
			Update::ProposeSelection ();
		    }
	    }

	    if (Update::onlyUpdateInstalled)			// just consider already installed packages
	    {
		Pkg::SetSelection ("");				// -> don't select any additional selections
	    }
	    else if (Packages::using_patterns)
	    {
		if (! ProductFeatures::GetBooleanFeature ("software",
		    "only_update_installed"))
		{
		    foreach (string pat, Product::patterns, {
			y2milestone("Pre-select pattern %1", pat);
			Pkg::ResolvableInstall( pat, `pattern );
		    });
		}

	    }
	    else						// update selections too
	    {
		Pkg::SetSelection (Update::selected_selection);	// -> set the base selection (minimal, default, ....)

		if (!Update::manual_interaction)
		{
		    // now compare installed (old) selections against available (new) selections
		    //  and set all selections which are installed (old) and available (new)
		    //  as 'to be installed' -> UI will show "to be updated" for these selections

		    list<string> available_addons = Pkg::GetSelections (`available, "");
		    list<string> installed_addons = Pkg::GetSelections (`installed, "");

		    foreach (string installed, installed_addons,
		    {
			if (contains (available_addons, installed))	// we have a newer selection for an installed one
			{
			    Pkg::SetSelection (installed);		// update this selection too (selection solving included)
			}
		    });
		}
	    }

	    Packages::SelectProduct();
	    Pkg::ActivateSelections ();					// now go through all selected selections and select their packages
	    // bnc #382208
	    Packages::SelectKernelPackages ();

	    // FATE #301990, Bugzilla #238488
	    // Control the upgrade process better
	    map <symbol, integer> update_sum
		= Pkg::PkgUpdateAll (GetUpdateConf());
	    y2milestone ("Update summary: %1", update_sum);
	    Update::unknown_packages = update_sum[`ProblemListSze]:0;

	    list<string> sys_patterns = Packages::ComputeSystemPatternList ();
	    foreach (string pat, sys_patterns, {
		Pkg::ResolvableInstall (pat, `pattern);
	    });

	    if (Pkg::PkgSolve (!Update::onlyUpdateInstalled))
		Update::solve_errors = 0;
	    else
		 Update::solve_errors = Pkg::PkgSolveErrors ();
	}
	// check product compatibility
	if (! (Update::ProductsCompatible () || Update::products_incompatible) || update_not_possible)
	{
	    if (Popup::ContinueCancel (
// continue-cancel popup
_("The installed product is not compatible with the product
on the installation media. If you try to update using the
current installation media, the system may not start or
some applications may not run properly.")))
	    {
		Update::IgnoreProductCompatibility ();
	    }
	    else
	    {
		Update::products_incompatible = true;
	    }
	}
    }


    if ( func == "MakeProposal" )
    {
	boolean force_reset      = param["force_reset"     ]:false;
	boolean language_changed = param["language_changed"]:false;

	// call some function that makes a proposal here:
	//
	// DummyMod::MakeProposal( force_reset );

	if (force_reset)
	{
	    Update::Reset ();
	    Packages::Reset ([`product]);
	    Update::did_init1 = false;
	    rpm_db_existency_checked_already = false;
	}

	// bugzilla #148105
	if (! rpm_db_existency_checked_already) {
	    rpm_db_existency_checked_already = true;

	    // if it doesn't exist, user can still confirm to continue
	    // packager will then suggest some set of packages
	    if (! CheckRPMDBforExistency()) {
		return $[
		    // error message in proposal
		    "warning" : _("Cannot read the current RPM Database."),
		    "warning_level" : `fatal,
		    "raw_proposal" : [],
		];
	    }
	}

	// Fill return map

	init_stuff ();

	if (Update::products_incompatible)
	{
	    return $[
		// error message in proposal
		"warning" : _("The installed product is not compatible with the product on the installation media."),
		"warning_level" : `fatal,
		"raw_proposal" : [],
	    ];
	}

	list available_base_selections = Update::GetBaseSelections ();
	if ((! Packages::using_patterns) && size (available_base_selections) == 0) {
	    y2error ("No base selections available");
	    // Can't find any software data, probably a installation media error
	    // error message
	    return $[ "warning" : _("Cannot read package data from installation media. Media error?"),
		"warning_level" : `blocker,
		"raw_proposal" : [] ];
	}

	// TRANSLATORS: unknown product (label)
	string update_from = _("Unknown product");
	if (Installation::installedVersion["show"]:"" != "" && Installation::installedVersion["show"]:"?" != "?") {
	    update_from = Installation::installedVersion["show"]:"";
	} else if (Installation::installedVersion["version"]:"" != "" && Installation::installedVersion["version"]:"?" != "?") {
	    update_from = Installation::installedVersion["name"]:"";
	}

	// TRANSLATORS: unknown product (label)
	string update_to = _("Unknown product");
	if (Installation::updateVersion["show"]:"" != "") {
	    update_to = Installation::updateVersion["show"]:"";
	} else if (Installation::updateVersion["version"]:"" != "") {
	    update_to = Installation::updateVersion["name"]:"";
	}

	// when versions don't match and upgrade is not allowed (running system)
	if ((Installation::installedVersion["version"]:"A" != Installation::updateVersion["version"]:"B") && Update::disallow_upgrade) {
	    return $[ "warning" : sformat(
		    // TRANSLATORS: proposal error, %1 is the version of installed system
		    // %2 is the version being installed
		    _("Updating system to another version (%1 -> %2) is not supported on the running system.<br>
Please, boot from the installation media and use a normal upgrade
or disable software repositories of products with different versions."),
		    update_from, update_to
		),
		"warning_level" : `fatal,
		"raw_proposal" : [] ];
	}

	string warning_message = nil;

	// when labels don't match
	if (!Stage::initial() && (Installation::installedVersion["show"]:"A" != Installation::updateVersion["show"]:"B")) {
	    warning_message = sformat(
		// TRANSLATORS: proposal warning, both %1 and %2 are replaced with product names
		_("Warning: Updating from '%1' to '%2', products do not exactly match."),
		// TRANSLATORS: unknown product name
		Installation::installedVersion["show"]:_("Unknown product"),
		// TRANSLATORS: unknown product name
		Installation::updateVersion["show"]:_("Unknown product")
	    );
	}

	// stores the proposal text output
	string summary_text = "";

	list <string> products = Update::SelectedProducts ();
	list <string> already_printed = [];

	if (products != nil) {
	    foreach (string one_product, products, {
		// never print duplicates, bugzilla #331560
		// 'toset' could be used but we want to keep sorting
		if (contains (already_printed, one_product)) {
		    return;
		} else {
		    already_printed = add (already_printed, one_product);
		}

		// TRANSLATORS: proposal summary item, %1 is a product name
		summary_text = summary_text + "<li><b>" + sformat (_("Update to %1"), one_product) + "</b></li>\n";
	    });
	}

//	if (Update::deleteOldPackages) {
//	    // Proposal for removing packages which are not maintained any more
//	    summary_text = summary_text + "<li>" + _("Delete unmaintained packages") + "</li>\n";
//	}

	if (Update::onlyUpdateInstalled) {
	    // Proposal for backup during update
	    summary_text = summary_text + "<li>" + _("Only update installed packages") + "</li>\n";
	} else {
	    if (Packages::using_patterns) {
		list<map<string,any> > patterns = Pkg::ResolvableProperties ("", `pattern, "");
		patterns = filter (map<string,any> p, patterns, {
		    return p["status"]:nil == `selected && p["user_visible"]:true && p["summary"]:p["name"]:"" != "";
		});
		// proposal string
		summary_text = summary_text + "<li>" + _("Update based on patterns") + "</li>\n";

		if (patterns != nil && size (patterns) > 0) {
		    summary_text = summary_text + HTML::ListStart();

		    foreach (map <string, any> p, patterns, {
			summary_text = summary_text + "<li>" + p["summary"]:p["name"]:"" + "</li>\n";
		    });
		    
		    summary_text = summary_text + HTML::ListEnd();
		}
	    } else {
		map selection_data = Pkg::SelectionData (Update::selected_selection);
		string selection_summary = selection_data["summary"]:"error";

		// Proposal for selection during update, %1 stands for selection name
		summary_text = summary_text + "<li>" + sformat (_("Update based on selection \"%1\""),
		    selection_summary) + "</li>\n";
	    }
	}

	// recalculate the disk space usage data
	SpaceCalculation::GetPartitionInfo();

	// TRANSLATORS: proposal dialog help
	string update_options_help = _("<p><b><big>Update Options</big></b>
Here you can choose how your system is going to be updated.
Choose whether only installed packages should be updated or whether new ones should be installed also 
(the default selection), and whether unmaintained packages should be deleted.</p>");

	ret = $[
	    "preformatted_proposal" : HTML::ListStart() + summary_text + HTML::ListEnd(),
	    "help" : update_options_help,
	];
	
	if (warning_message != nil) {
	    ret["warning"] = warning_message;
	    ret["warning_level"] = `warning;
	}
    }
    else if ( func == "AskUser" )
    {
	boolean has_next = param["has_next"]:false;

	// call some function that displays a user dialog
	// or a sequence of dialogs here:
	//
	// sequence = DummyMod::AskUser( has_next );

	symbol result = (symbol) WFM::CallFunction ("inst_update", [true, has_next]);

	if (result == `next)
	{
	    Update::did_init1 = false;
	}

	// Fill return map

	ret = $[ "workflow_sequence" : result ];
    }
    else if ( func == "Description" )
    {
	// Fill return map.
	//
	// Static values do just nicely here, no need to call a function.

	ret =
	    $[
	      // this is a heading
	      "rich_text_title"	:	_("Update Options"),
	      // this is a menu entry
	      "menu_title"	:	_("&Update Options"),
	      "id"		:	"update_stuff"
	    ];
    }

    return ret;
}

ACC SHELL 2018