ACC SHELL

Path : /usr/share/YaST2/modules/
File Upload :
Current File : //usr/share/YaST2/modules/PackageSystem.ycp

/**
 * File:	modules/PackageSystem.ycp
 * Package:	yast2
 * Summary:	Packages manipulation (system)
 * Authors:	Martin Vidner <mvidner@suse.cz>
 *		Michal Svec <msvec@suse.cz>
 * Flags:	Stable
 *
 * $Id: PackageSystem.ycp 57294 2009-05-22 08:54:19Z mvidner $
 *
 * The documentation is maintained at
 * <a href="../index.html">.../docs/index.html</a>.
 */

{

module "PackageSystem";
textdomain "base";

import "Mode";
import "PackageCallbacks";
import "PackageLock";
import "Report";
import "Stage";
import "CommandLine";

/**
 * Was last operation canceled?
 *
 * Used to enhance the exit status to distinguish between package
 * installation fail and installation canceled by user, as in the second
 * case doesn't make much sense to display any error
 * Is set to true when user canceled package installation, from
 * PackageSystem::* functions
 */
boolean last_op_canceled = false;

/**
 * Has Pkg::TargetInit run?
 */
boolean target_initialized = false;

/**
 * Has Pkg::SourceStartCache run?
 */
boolean source_initialized = false;


include "packages/common.ycp";


/**
 * Ensure that Pkg:: calls work.
 * This may become superfluous.
 */
global void EnsureTargetInit() {
    PackageLock::Check ();
    // always initizalize target, it should be cheap according to #45356
    target_initialized = Pkg::TargetInit ("/", false);
}

/**
 * Ensure that Pkg:: calls working with the installation sources work
 */
global void EnsureSourceInit() {
    PackageLock::Check ();

    if(source_initialized) 
    {
	// this way, if somebody closed the cache outside of Package
	// (typically in installation), we will reinitialize
	// it's cheap if cache is already initialized
	Pkg::SourceStartCache (true);
	return;
    }

    if(! target_initialized)
    {
	// make sure we have the RPM keys imported
        EnsureTargetInit();
    }

    list sources = Pkg::SourceStartCache (true);

    if (size (sources) > 0)
    {
	source_initialized = true;
    }
    else
    {
	// all repositories are disabled or no repository defined
	y2warning("No package repository available");
    }
}

global boolean DoInstall(list<string> packages) {
    return DoInstallAndRemove(packages, []);
}

global boolean DoRemove(list<string> packages) {
    return DoInstallAndRemove([], packages);
}

boolean SelectPackages(list<string> toinstall, list<string> toremove)
{
    boolean ok = true;

    foreach (string p, toinstall, {
	if(ok == true)
	    if(Pkg::PkgInstall(p) != true) {
		y2error("Package %1 install failed: %2", p, Pkg::LastError());
		ok = false;
	    }
    });
    if(ok != true) return false;

    foreach (string p, toremove, {
	if(ok == true)
	    if(Pkg::PkgDelete(p) != true) {
		y2error("Package %1 delete failed: %2", p, Pkg::LastError());
		ok = false;
	    }
    });

    return ok;
}

boolean DoInstallAndRemoveInt(list<string> toinstall, list<string> toremove) {
    y2debug ("toinstall: %1, toremove: %2", toinstall, toremove);
    if (!PackageLock::Check ())
    {
	return false;
    }

    EnsureSourceInit ();
    EnsureTargetInit ();
    boolean ok = true;

    import "Label";
    import "Popup";
    import "PackagesUI";

    // licenses: #35250
    map<string, string> licenses = Pkg::PkgGetLicensesToConfirm (toinstall);
    if (size (licenses) > 0)
    {
	list<string> rt_licenses_l = maplist ( string p, string l, licenses, {
	    return Mode::commandline()
		? sformat ("%1\n%2", p, l)
		: sformat ("<p><b>%1</b></p>\n%2", p, l);
	});

	boolean accepted = false;

	if (Mode::commandline())
	{
	    // print the licenses
	    CommandLine::Print(mergestring (rt_licenses_l, "\n"));
	    // print the question
	    CommandLine::Print(_("Do you accept this license agreement?",
		"Do you accept these license agreements?",
		size (licenses)));

	    accepted = !CommandLine::YesNo();
	}
	else
	{
	    accepted = !Popup::AnyQuestionRichText (
		// popup heading, with rich text widget and Yes/No buttons
		_("Do you accept this license agreement?",
		  "Do you accept these license agreements?",
		  size (licenses)),
		mergestring (rt_licenses_l, "\n"),
		70, 20,
		Label::YesButton (), Label::NoButton (),
		`focus_none);
	}

	y2milestone("Licenses accepted: %1", accepted);

	if (!accepted)
	{
	    y2milestone("License not accepted: %1", toinstall);
	    last_op_canceled = true;
	    return false;
	}

	// mark licenses as confirmed
	foreach (string p, string l, licenses, {
	    Pkg::PkgMarkLicenseConfirmed (p);
	});
	last_op_canceled = false;
    }


    // check if the database is consistent before packages are added
    boolean packages_consistent = Pkg::PkgSolveCheckTargetOnly();
    boolean transact = Pkg::IsAnyResolvable(`any, `to_install) || Pkg::IsAnyResolvable(`any, `to_remove);

    y2internal("Target solved: %1, something to transact: %2", packages_consistent, transact);

    if (!SelectPackages(toinstall, toremove))
    {
	return false;
    }

    boolean packager_displayed = false;

    // display an error message and advice to manually fix the system
    if (!packages_consistent || transact)
    {
	y2warning("The current system is not consistent");

	string message = _("The current system is not consistent,
some packages have unresolved dependencies.");

	if (!packages_consistent)
	{
	    message = message + "\n\n" + _("Automatic resolving failed, manual dependency resolving is needed.");
	}

	if (transact)
	{
	    message = message + "\n\n" + _("Yast has automatically added or removed some packages,
check the changes scheduled to fix the system
in the package manager.");
	}


	message = message + "\n\n" + _("Start the package manager and fix the problems
or skip fixing and install the already confirmed packages only?");

	symbol fixsystem = Popup::AnyQuestion3(Label::WarningMsg(), message, Label::ContinueButton(),
	    Label::SkipButton(), Label::AbortButton(), `focus_yes);

	y2milestone("Fixsystem answer: %1", fixsystem);

	// the 3rd button ("Abort" label in this case)
	if (fixsystem == `retry)
	{
	    y2milestone("Aborting package installation");
	    // do not install anything, abort
	    return false;
	}
	else if (fixsystem == `yes)
	{
	    // disable repomanagement during installation
	    boolean repomgmt = !Mode::installation();
	    // start the package selector
	    symbol ret = PackagesUI::RunPackageSelector($[ "enable_repo_mgr" : repomgmt, "mode" : `summaryMode ]);

	    y2internal("Package selector returned: %1", ret);

	    // do not install anything
	    if (ret == `cancel || ret == `close)
	    {
		y2milestone("Aborting package installation");
		return false;
	    }

	    packager_displayed = true;
	}
	// `no = do not fix the system, install the required packages only
	// and ignore the inconsistencies
	else if (fixsystem == `no)
	{
	    y2milestone("Resetting the preselected packages");
	    // reset the solver - disable the fixsystem solver mode (bnc#439373)
	    Pkg::SetSolverFlags($["reset":true]);
	    // reset the preselected transactions to fix the problems
	    Pkg::PkgApplReset();

	    // reselect the packages again after the reset
	    if (!SelectPackages(toinstall, toremove))
	    {
		return false;
	    }
	}
	else
	{
	    y2internal("Unknown result %1, aborting", fixsystem);
	    return false;
	}
    }

    boolean solved = Pkg::PkgSolve(false);

    if(solved != true)
    {
	y2error("Package solve failed: %1", Pkg::LastError());

	// error message, after pressing [OK] the package manager is displayed
	Report::Error(_("There are unresolved dependencies which need
to be solved manually in the package manager."));

	// disable repomanagement during installation
	boolean repomgmt = !Mode::installation();
	// start the package selector
	symbol ret = PackagesUI::RunPackageSelector($[ "enable_repo_mgr" : repomgmt, "mode" : `summaryMode ]);

	y2internal("Package selector returned: %1", ret);

	// do not fix the system
	if (ret == `cancel || ret == `close)
	{
	    return false;
	}

	packager_displayed = true;
    }

    // is a package or a patch selected for installation?
    boolean any_to_install = Pkg::IsAnyResolvable(`package, `to_install) || Pkg::IsAnyResolvable(`patch, `to_install);

    //[int successful, list failed, list remaining, list srcremaining]
    list result = Pkg::PkgCommit (0);
    y2debug ("PkgCommit: %1", result);
    if(result == nil || result[1]:[] != []) {
	y2error("Package commit failed: %1", result[1]:[]);
	return false;
    }

    foreach (string remaining, (list<string>) (result[2]:[]), {
	if(ok == true)
	    if(contains(toinstall, remaining)) {
		y2error("Package remain: %1", remaining);
		ok = false;
	    }
    });
    if(ok != true) return false;

    // Only run SUSEconfig if any packages were installed?
    // No, deleted packages are not covered by this.
    // if (true || result[0]:-1 > 0)

    // But omit it during installation, one is run at its end.
    // #25071
    if (!Stage::initial () && !Stage::cont ())
    {
	RunSUSEconfig ();
    }

    // a package or a patch was installed, may be that there is a new yast agent
    if (any_to_install)
    {
	// register the new agents
	SCR::RegisterNewAgents();
    }

    // check if the required packages have been installed
    // (user could deselect or uninstall them in the packager widget)
    if (packager_displayed && !InstalledAll(toinstall))
    {
	y2error("Required packages have not been installed");
	return false;
    }

    return true;
}

global boolean DoInstallAndRemove(list<string> toinstall, list<string> toremove)
{
    // remember the current solver flags
    map<string,any> solver_flags = Pkg::GetSolverFlags();

    // do not install recommended packages for already installed packages (bnc#445476)
    Pkg::SetSolverFlags($["ignoreAlreadyRecommended":true]);

    boolean ret = DoInstallAndRemoveInt(toinstall, toremove);

    // restore the original flags
    Pkg::SetSolverFlags(solver_flags);

    return ret;
}


/**
 * Is a package available?
 * @return true if yes (nil = no package source available)
 */
global boolean Available(string package) {
    EnsureSourceInit();

    if (!source_initialized)
    {
	// error no source initialized
	return nil;
    }

    return Pkg::IsAvailable(package);
}

boolean _rpm_query_binary_initialized = false;
string _rpm_query_binary = "rpm";

void InitRPMQueryBinary () {
    if (_rpm_query_binary_initialized) return;

    // rpmqpack is a way faster
    if (SCR::Read (.target.size, "/usr/bin/rpmqpack") > -1) {
	_rpm_query_binary = "/usr/bin/rpmqpack ";
    // than rpm itself
    } else if (SCR::Read (.target.size, "/bin/rpm") > -1) {
	_rpm_query_binary = "/bin/rpm -q ";
    }

    _rpm_query_binary_initialized = true;
}

/**
 * Is a package provided in the system? Is there any installed package providing 'package'?
 * @return true if yes
 */
global boolean Installed(string package) {
    // This is a most commonly called function and so it's
    // important that it's fast, especially in the common
    // case, where all dependencies are satisfied.
    // Unfortunately, initializing Pkg reads the RPM database...
    // so we must avoid it.
    // added --whatprovides due to bug #76181
    return 0 == (integer) SCR::Execute(.target.bash, "rpm -q --whatprovides " + package);
    // return Pkg::IsProvided (package);
}

/**
 * Is a package installed? Checks only the package name in contrast to Installed() function.
 * @return true if yes
 */
global boolean PackageInstalled(string package) {
    InitRPMQueryBinary();

    // This is commonly called function and so it's
    // important that it's fast, especially in the common
    // case, where all dependencies are satisfied.
    return 0 == (integer) SCR::Execute (.target.bash, _rpm_query_binary + package);
}

/**
 * Is a package available? Checks only package name, not list of provides.
 * @return true if yes (nil = no package source available)
 */
global boolean PackageAvailable(string package) {
    EnsureSourceInit();

    if (!source_initialized)
    {
	// error no source initialized
	return nil;
    }

    return Pkg::PkgAvailable(package);
}

/**
 * @short Check if packages are installed
 * @descr Install them if they are not and user approves installation
 *
 * @param a list of packages to check (and install)
 * @return boolean true if installation succeeded or packages were installed,
 * false otherwise
 */
global boolean CheckAndInstallPackages (list<string> packages) {
    if (Mode::config ())
	return true;
    if (InstalledAll (packages))
	return true;
    return InstallAll (packages);
}

/**
 * @short Check if packages are installed
 *
 * @descr Install them if they are not and user approves installation
 * If installation fails (or wasn't allowed), ask user if he wants to continue
 *
 * @param packages a list of packages to check (and install)
 * @return boolean true if installation succeeded, packages were installed
 * before or user decided to continue, false otherwise
 */
global boolean CheckAndInstallPackagesInteractive (list<string> packages) {
    boolean success = CheckAndInstallPackages (packages);
    if (! success)
    {
	if (! LastOperationCanceled ())
	{
	    if (Mode::commandline ())
	    {
		// error report
		Report::Error (_("Installing required packages failed."));
	    }
	    else
	    {
		success = Popup::ContinueCancel (
		    // continue/cancel popup
		    _("Installing required packages failed. If you continue
without installing required packages,
YaST may not work properly.
"));
	    }
	}
	else
	{
	    if (Mode::commandline ())
	    {
		Report::Error (
		    // error report
		    _("Cannot continue without installing required packages."));
	    }
	    else
	    {
		success = Popup::ContinueCancel (
		    // continue/cancel popup
		    _("If you continue without installing required 
packages, YaST may not work properly.
"));
	    }
	}
    }
    return success;
}

global boolean InstallKernel (list<string> kernel_modules) {
    // this function may be responsible for the horrible startup time
    y2milestone ("want: %1", kernel_modules);
    if (kernel_modules == [])
    {
	return true;		// nothing to do
    }

    // check whether tag "kernel" is provided
    // do not initialize the package manager if it's not necessary
    string rpm_command = "/bin/rpm -q --whatprovides kernel";
    y2milestone("Starting RPM query: %1", rpm_command);
    map output = (map)SCR::Execute(.target.bash_output, rpm_command);
    y2debug("result of the query: %1", output);

    if (output["exit"]:-1 == 0)
    {
	list<string> packages = splitstring(output["stdout"]:"", "\n");
	packages = filter(string pkg, packages, {return pkg != "";});
	y2milestone("Packages providing tag 'kernel': %1", packages);

	if (size(packages) > 0)
	{
	    return true;
	}

	y2milestone("Huh? Kernel is not installed??");
    }
    else
    {
	y2warning("RPM query failed, quering the package manager...");
    }


    EnsureTargetInit ();

    list <list> provides = Pkg::PkgQueryProvides ("kernel");
    y2milestone ("provides: %1", provides);

    list <list> kernels = filter (list l, provides, {
        return l[1]:`NONE == `BOTH || l[1]:`NONE == l[2]:`NONE;
    });

    if (size (kernels) != 1)
        y2error ("not exactly one package provides tag kernel");

    string kernel = kernels[0,0]:"none";
    list<string> packs = [kernel];

    if (! Pkg::IsProvided(kernel))
    {
	EnsureSourceInit ();
    }

    // TODO: for 9.2, we always install all packages, but
    // we could only install those really needed (#44394)
    return InstallAll ( packs );
}

/* EOF */
}

ACC SHELL 2018