ACC SHELL
/**
* File: Packages.ycp
* Package: Package selections
* Authors: Anas Nashif <nashif@suse.de>
*
* $Id: Packages.ycp 60363 2010-01-14 13:57:12Z lslezak $
*/
{
module "Packages";
textdomain "packager";
import "AddOnProduct";
import "WorkflowManager";
import "Arch";
import "Directory";
import "InstURL";
import "Kernel";
import "Mode";
import "Stage";
import "Linuxrc";
import "Language";
import "ProductFeatures";
import "ProductControl";
import "Report";
import "Slides";
import "SlideShow";
import "SpaceCalculation";
import "String";
import "Popup";
import "Label";
import "Wizard";
import "PackageCallbacks";
import "Product";
import "DefaultDesktop";
import "SourceDialogs";
import "FileUtils";
import "PackageCallbacks";
import "Installation";
import "URL";
import "PackagesProposal";
include "packager/load_release_notes.ycp";
/**
* Force full proposal routine next run
*/
boolean full_repropose = false;
/**
* repository has been initialized?
*/
boolean init_called = false;
/**
* repository initialization is WIP
*/
boolean init_in_progress = false;
/**
* Error which occurred during repository initialization
*/
string init_error = nil;
// cache for the proposed summary
map cached_proposal = nil;
// the selection used for the cached proposal
// the default values 'nil' say that the proposal hasn't been called yet
list <string> cached_proposal_packages = nil;
list <map> cached_proposal_patterns = nil;
list <map> cached_proposal_products = nil;
list <map> cached_proposal_patches = nil;
list <map> cached_proposal_selections = nil;
list <string> cached_proposal_languages = nil;
global boolean install_sources = false; // Installing source packages ?
global integer timestamp = 0; // last time of getting the target map
global string metadir = "/yast-install";
global boolean metadir_used = false; // true if meta data and inst-sys is in ramdisk
global list<integer> theSources = []; // id codes of repositories in priority order
global list<string> theSourceDirectories = []; // product directories on repositories
global map<integer,integer> theSourceOrder = $[]; // installation order
string servicepack_metadata = "/servicepack.tar.gz";
// to remember if warning should occurre if switching base selection
global boolean base_selection_modified = false;
global boolean base_selection_changed = false;
// Local variables
string choosen_base_selection = "";
// count of errors during packages solver
global integer solve_errors = 0;
/**
* Packages to be selected when proposing the list
*/
list<string> additional_packages = [];
boolean system_packages_selected = false;
// DefaultDesktop::PrefferedWindowManager
// global string window_manager = nil;
global boolean using_patterns = false;
global string add_on_products_list = nil;
global string add_on_products_type = nil;
// summary functions
global void ResetProposalCache () {
y2milestone ("Reseting the software proposal cache");
cached_proposal_packages = nil;
cached_proposal_patterns = nil;
cached_proposal_products = nil;
cached_proposal_patches = nil;
cached_proposal_selections = nil;
cached_proposal_languages = nil;
}
/**
* List selected resolvables of specified kind
* @param what symbol specifying the kind of resolvables to select
* @param format string format string to print summaries in
* @return a list of selected resolvables
*/
global list<string> ListSelected (symbol what, string format) {
if (format == "" || format == nil)
format = "%1";
list<map<string,any> > selected = Pkg::ResolvableProperties ("", what, "");
// ignore hidden patterns
if (what == `pattern)
{
selected = filter (map<string,any> r, selected, {
return r["user_visible"]:nil == true;
});
// order patterns according to "order" flag
selected = sort(map<string,any> x, map<string,any> y, selected,
{
integer xo = tointeger(x["order"]:"");
integer yo = tointeger(y["order"]:"");
if (xo == nil || yo == nil)
{
// order is not an integer, compare as strings
return x["order"]:"" < y["order"]:"";
}
else
{
return xo < yo;
}
}
);
}
selected = filter (map<string,any> r, selected, {
return r["status"]:nil == `selected;
});
list<string> ret = maplist (map<string,any> r, selected, {
string disp = r["summary"]:r["name"]:"";
return sformat (format, disp);
});
return ret;
}
/**
* Count the total size of packages to be installed
* @return string formatted size of packages to be installed
*/
global string CountSizeToBeInstalled () {
integer sz = 0;
list<list<integer> > media_sizes = Pkg::PkgMediaSizes();
foreach (list<integer> inst_sizes, media_sizes,
{
foreach (integer inst_size, inst_sizes,
{
sz = sz + inst_size;
}
);
}
);
y2milestone ("Total size of packages to install %1 (%2kB)", sz, sz / 1024 );
return String::FormatSizeWithPrecision (sz, 1, true);
}
map<integer,integer> SrcMapping()
{
map<integer,integer> srcid_to_current_src_no = $[];
integer index = 0;
list< list > src_list = Pkg::PkgMediaNames();
y2debug("source names: %1", src_list);
srcid_to_current_src_no = listmap( list src, src_list, {
index = index + 1;
return $[src[1]:-1 : index];
});
y2milestone ("Repository mapping information: %1", srcid_to_current_src_no );
return srcid_to_current_src_no;
}
/**
* Count the total size of packages to be installed
* @return integer size of packages to be installed (in bytes)
*/
global integer CountSizeToBeDownloaded() {
integer ret = 0;
// get list of remote repositories
// consider only http(s) and ftp protocols as remote
// all enabled sources
list<integer> repos = Pkg::SourceGetCurrent(true);
list<integer> remote_repos = [];
foreach(integer repo, repos,
{
string url = Pkg::SourceGeneralData(repo)["url"]:"";
string scheme = tolower(URL::Parse(url)["scheme"]:"");
if (scheme == "http" || scheme == "https" || scheme == "ftp")
{
y2milestone("Found remote repository %1: %2", repo, url);
remote_repos = add(remote_repos, repo);
}
}
);
// shortcut, no remote repository found
if (size(remote_repos) == 0)
{
y2milestone("No remote repository found");
return 0;
}
map<integer,integer> repo_mapping = SrcMapping();
list<list<integer> > media_sizes = Pkg::PkgMediaPackageSizes();
y2debug("Media sizes: %1", media_sizes);
foreach(integer repoid, remote_repos,
{
list<integer> repo_media_sizes = media_sizes[(repo_mapping[repoid]:-1) - 1]:[];
foreach(integer media_size, repo_media_sizes,
{
ret = ret + media_size;
}
);
}
);
y2milestone("Total size of packages to download: %1 (%2kB)", ret, ret / 1024);
return ret;
}
/**
* Return information about suboptimal distribution if relevant
* @return string the information string or empty string
*/
global string InfoAboutSubOptimalDistribution () {
// warn about suboptimal distribution
// this depends on the kernel
string dp = (string) SCR::Read(.content.DISTPRODUCT);
if (dp==nil)
dp = "";
if (ProductFeatures::GetBooleanFeature ("software",
"inform_about_suboptimal_distribution") &&
Arch::i386 () && issubstring(dp, "DVD"))
{
string tmp = (string) SCR::Read(.proc.cpuinfo.value."0"."flags");
list flags = (size (tmp) > 0) ? splitstring (tmp, " ") : [];
// this depends on the cpu (lm = long mode)
if (contains (flags, "lm"))
{
// warning text
return _("Your computer is a 64-bit x86-64 system. However, you are trying to install a 32-bit distribution.");
}
}
return "";
}
string SummaryHelp(list<symbol> flags)
{
string ret = "";
if (contains(flags, `pattern))
{
// help text for software proposal
ret = ret + _("<P>The pattern list states which functionality will be available after installing the system.</P>");
}
if (contains(flags, `size))
{
ret = ret +
// (see bnc#178357 why these numbers)
// translators: help text for software proposal
_("<P>The proposal reports the total size of files which will be installed to the system. However, the system will contain some other files (temporary and working files) so the used space will be slighltly larger than the proposed value. Therefore it is a good idea to have at least 25% (or 300MB) free space before starting the installation.</P>") +
// help text for software proposal
_("<P>The total 'size to download' is the size of the packages which will be downloaded from remote (network) repositories.\n This value is important when the connection is slow or when there is a data limit for downloading.</P>");
}
// add a header if the result is not empty
if (ret != "")
{
// help text for software proposal - header
ret = _("<P><B>Software Proposal</B></P>") + ret;
}
return ret;
}
/**
* Return the summary output lines
* @param flags a list of flags, allowed are `product, `pattern, `selection,
* `size, `desktop
* @return a list of the output lines
*/
global list<string> SummaryOutput (list<symbol> flags) {
list<string> output = [ InfoAboutSubOptimalDistribution () ];
if (contains (flags, `product))
// installation proposal - SW summary, %1 is name of the installed product
// (e.g. openSUSE 10.3, SUSE Linux Enterprise ...)
output = (list<string>)merge (output, ListSelected (`product, _("Product: %1")));
if (contains (flags, `desktop)) {
// BNC #422077, Desktop doesn't need to be defined, e.g. in SLED
// BNC #431336 ... and even if it is defined, it needn't be visible
string ddd = DefaultDesktop::Description();
if (ddd != "") {
// installation proposal - SW summary, %1 is name of the selected desktop or system type (e.g. KDE)
output = (list<string>)add (output, sformat(_("System Type: %1"), ddd));
}
}
if (contains (flags, `pattern))
{
list<string> patterns = ListSelected (`pattern, "+ %1");
if (size(patterns) > 0)
{
output = (list<string>) add (output, _("Patterns:<br>") + mergestring (patterns, "<br>"));
}
}
if (contains (flags, `selection))
{
list<string> selections = ListSelected (`selection, "+ %1");
if (size(selections) > 0)
{
output = (list<string>) add (output, _("Selections:<br>") + mergestring (selections, "<br>"));
}
}
if (contains (flags, `size))
{
output = (list<string>)add (output,
// installation proposal - SW summary, %1 is size of the selected packages (in MB or GB)
sformat (_("Size of Packages to Install: %1"),
CountSizeToBeInstalled ()));
// add download size
integer download_size = CountSizeToBeDownloaded();
if (download_size > 0)
{
output = (list<string>)add (output,
// installation proposal - SW summary, %1 is download size of the selected packages
// which will be installed from an ftp or http repository (in MB or GB)
sformat (_("Downloading from Remote Repositories: %1"),
String::FormatSizeWithPrecision(download_size, 1, true))
);
}
}
output = filter (string o, output, {
return o != "" && o != nil;
});
return output;
}
/**
* Check if selected software fits on the partitions
* @param init boolean true if partition sizes have changed
* @return boolean true if selected software fits, false otherwise
*/
global boolean CheckDiskSize (boolean init) {
if (init)
{
y2milestone ("Resetting space calculation");
SpaceCalculation::GetPartitionInfo();
}
return SpaceCalculation::CheckDiskSize();
}
/**
* Checks which products have been selected for removal and modifies
* the warning messages accordingly.
*
* @param reference to map MakeProposal->Summary
*/
global void CheckOldAddOns (map & ret) {
list <map <string, any> > products = Pkg::ResolvableProperties ("", `product, "");
products = filter (map <string, any> one_product, products, {
// inform about these products only
return (one_product["status_detail"]:`unknown == `S_AutoDel);
});
// no such products
if (size (products) == 0) {
y2milestone ("No products marked for auto-removal");
return;
}
y2warning ("Product marked for auto-removal: %1", products);
string warning = "";
foreach (map <string, any> one_product, products, {
warning = warning + "<li>" + one_product["display_name"]:one_product["name"]:one_product["NCL"]:_("Unknown Product") + "</li>\n";
});
warning = sformat (
_("These Add-On products have been marked for auto-removal: %1"),
"<ul>\n" + warning + "</ul>\n"
);
// raising warning level if needed
if (ret["warning_level"]:nil == nil || contains ([`notice, `ok], ret["warning_level"]:`warning)) {
ret["warning_level"] = `warning;
}
if (size (ret["warning"]:"") > 0) {
ret["warning"] = ret["warning"]:"" + "<br>\n" + (size (products) > 1 ?
// Warning message when some add-ons are marked to be removed automatically
_("Please, contact the vendors of these add-ons to provide you with new the installation media.")
:
// Warning message when some add-ons are marked to be removed automatically
_("Please, contact the vendor of the add-on to provide you with the new installation media.")
);
}
ret["warning"] = ret["warning"]:"" + warning;
}
/**
* Print the installatino proposal summary
* @param flags a list of symbols, see above
* @param boolean use_cache if true, use previous proposal if possible
* @returnu a map proposal summary
*/
global map Summary (list<symbol> flags, boolean use_cache) {
if (init_error != nil)
{
return $[
"warning" : init_error,
"warning_level" : `blocker,
];
}
map ret = $[];
if (! CheckDiskSize (! use_cache))
{
ret = $[
"warning" : ProductFeatures::GetFeature ("software","selection_type") == `fixed
// summary warning
? _("Not enough disk space.")
// summary warning
: _("Not enough disk space. Remove some packages in the single selection."),
"warning_level" : Mode::update() ? `warning : `blocker,
];
}
else
{
// check available free space (less than 25% and less than 750MB) (see bnc#178357)
list<map> free_space = SpaceCalculation::CheckDiskFreeSpace(25, 750*1024);
if (size(free_space) > 0)
{
string warning = "";
foreach(map df, free_space,
{
string partition = df["dir"]:"";
// add a backslash if it's missing
if (partition == "" || substring(partition, 0, 1) != "/")
{
partition = "/" + partition;
}
integer free_pct = df["free_percent"]:0;
integer free_kB = df["free_size"]:0;
string w = sformat(_("Only %1 (%2%%) free space available on partition %3.<BR>"), String::FormatSize(free_kB*1024), free_pct, partition);
warning = warning + w;
}
);
if (warning != "")
{
ret["warning"] = warning;
ret["warning_level"] = `warning;
}
}
}
// FATE #304488
if (Mode::update()) CheckOldAddOns (ret);
ret["raw_proposal"] = SummaryOutput (flags);
ret["help"] = SummaryHelp(flags);
return ret;
}
// proposal control functions
global void ForceFullRepropose () {
full_repropose = true;
}
global boolean SelectProduct ();
/**
* Reset package selection, but keep objects of specified type
* @param keep a list of symbols specifying type of objects to be kept
*/
global void Reset (list<symbol> keep) {
list<map<string,any> > restore = [];
foreach (symbol type, keep, {
list<map<string,any> > selected = Pkg::ResolvableProperties ("", type, "");
foreach (map<string,any> s, selected, {
restore = add (restore, $[
"type" : type,
"name" : s["name"]:""
]);
});
});
// This reset keep user-made changes
// BNC #446406
Pkg::PkgApplReset();
foreach (map<string,any> res, restore, {
Pkg::ResolvableInstall (res["name"]:"", (symbol)(res["type"]:nil));
});
system_packages_selected = false;
}
/**
* Initialize add-on products provided by the repository
*/
global void InitializeAddOnProducts() {
Packages::SelectProduct ();
PackageCallbacks::SetMediaCallbacks();
// Set the base workflow before adding more AddOnProducts using the add_on_products file
// Do not force "base workflow" if there is already any base one stored
// bugzilla #269625
WorkflowManager::SetBaseWorkflow (false);
if (Packages::add_on_products_list != nil) {
y2milestone ("Found list of add-on products to preselect: %1", Packages::add_on_products_list);
AddOnProduct::SetPreselectedAddOnProductsType (Packages::add_on_products_type);
AddOnProduct::AddPreselectedAddOnProducts (Packages::add_on_products_list);
Packages::add_on_products_list = nil; // do not select them any more
}
}
/*-----------------------------------------------------------------------
* LOCALE FUNCTIONS
*-----------------------------------------------------------------------*/
/**
* Add a package to list to be selected before proposal
* Can be called only before the installation proposal, later doesn't
* have any effect.
* OBSOLETE! Please, use PackagesProposal::AddResolvables() instead.
*
* @param package string package to be selected
*/
global void addAdditionalPackage(string package)
{
y2warning ("OBSOLETE! Please, use PackagesProposal::AddResolvables() instead");
additional_packages = add (additional_packages, package);
}
/**
* Compute architecture packages
* @return list(string)
*/
define list<string> architecturePackages ()
{
list<string> packages = [];
// remove unneeded / add needed packages for ppc
if (Arch::ppc ())
{
if (Arch::board_mac ())
{
packages = add (packages, "mouseemu");
}
if (Arch::board_mac_new ()
|| Arch::board_mac_old ())
{
string pmac_board = "";
list<map> pmac_compatible = (list<map>) SCR::Read(.probe.cpu);
foreach (map pmac_compatible_tmp, pmac_compatible, {
pmac_board = pmac_compatible_tmp["system"]:"";
});
// install pbbuttonsd on PowerBooks and iMacs
if (issubstring (pmac_board, "PowerBook")
|| issubstring (pmac_board, "PowerMac2,1")
|| issubstring (pmac_board, "PowerMac2,2")
|| issubstring (pmac_board, "PowerMac4,1")
|| issubstring (pmac_board, "iMac,1"))
{
packages = add (packages, "pbbuttonsd");
packages = add (packages, "powerprefs");
}
}
if (Arch::ppc64 () && (Arch::board_chrp () || Arch::board_iseries ()))
{
packages = add (packages, "iprutils");
}
}
if (Arch::ia64 ())
{
// install fpswa if the firmware has an older version
if (SCR::Execute(.target.bash, "/sbin/fpswa_check_version") != 0)
{
packages = add (packages, "fpswa");
}
}
if (Arch::is_xenU())
{
// xen-tools-domU are required for registration of a Xen VM (domU)
packages = add (packages, "xen-tools-domU");
}
// add numactl on x86_64 with SMP
if (Arch::has_smp () && Arch::x86_64 ())
{
packages = add (packages, "numactl");
packages = add (packages, "irqbalance");
}
return packages;
}
/**
* graphicPackages ()
* Compute graphic (x11) packages
* @return list(string) list of rpm packages needed
*/
define list<string> graphicPackages ()
{
list<string> packages = [];
// don't setup graphics if running via serial console
if (!Linuxrc::serial_console ())
{
packages = [ "xorg-x11", "xorg-x11-server", "xorg-x11-server-glx",
"libusb", "sax2", "sax2-gui", "sax2-ident", "sax2-tools",
"sax2-libsax", "sax2-libsax-perl"];
}
y2milestone ("X11 Packages to install: %1", packages);
return packages;
}
/**
* Compute special packages
* @return list(string)
*/
define list<string> modePackages ()
{
list<string> packages = [];
if (Linuxrc::vnc ())
{
packages = add (packages, "tightvnc");
packages = add (packages, "yast2-qt");
packages = add (packages, "xorg-x11");
packages = add (packages, "xorg-x11-fonts");
packages = add (packages, "icewm");
packages = add (packages, "sax2-tools");
packages = add (packages, "xinetd");
}
//this means we have a remote X server
if (Linuxrc::display_ip ())
{
packages = add (packages, "yast2-qt");
packages = add (packages, "xorg-x11");
packages = add (packages, "xorg-x11-fonts");
packages = add (packages, "icewm");
packages = add (packages, "sax2-tools");
}
if (Linuxrc::braille ())
{
packages = add (packages, "sbl");
}
if (Linuxrc::usessh())
{
packages = add (packages, "openssh");
}
y2milestone ("Installation mode packages: %1", packages);
return packages;
}
/**
* Compute special java packages
* @return list(string)
*/
define list<string> javaPackages ()
{
if (!Arch::alpha ())
return [];
list<string> packages = [];
list cpus = (list) SCR::Read (.probe.cpu);
string model = cpus[0, "model"]:"EV4";
string cputype = substring (model, 2, 1);
if ((cputype == "6") || (cputype == "7") || (cputype == "8"))
{
packages = ["cpml_ev6"];
}
else
{
packages = ["cpml_ev5"];
}
return packages;
}
/**
* Compute board (vendor) dependant packages
* @return list(string)
*/
define list<string> boardPackages ()
{
list<string> packages = [];
list <map <string, any> > probe = (list <map <string, any> >)SCR::Read (.probe.system);
packages = (list<string>)probe[0,"requires"]:[];
y2milestone ("Board/Vendor specific packages: %1", packages);
return packages;
}
/**
* Compute packages required to access the repository
* @return list(string) list of the required packages
*/
list<string> sourceAccessPackages()
{
// TODO: rather check all registered repositories...
list<string> ret = [];
string instmode = Linuxrc::InstallInf("InstMode");
y2milestone("Installation mode: %1", instmode);
if (instmode == "smb" || instmode == "cifs")
{
// /sbin/mount.cifs is required to mount a SMB/CIFS share
ret = ["cifs-mount"];
}
else if (instmode == "nfs")
{
// portmap is required to mount an NFS export
ret = ["nfs-client"];
}
y2milestone("Packages for accessing the repository: %1", ret);
return ret;
}
/*
* Additional kernel packages from control file
* @return list<string> Additional Kernel packages
*/
define list<string> ComputeAdditionalKernelPackages ()
{
string final_kernel = Kernel::GetFinalKernel ();
integer pos = findfirstof(final_kernel, "-");
string extension = substring(final_kernel, pos, size(final_kernel));
list<string> akp = [];
if (extension!="")
{
list<string> kernel_packages = (list<string>)
ProductFeatures::GetFeature ("software", "kernel_packages");
if (size(kernel_packages) > 0 && kernel_packages != nil)
{
akp = maplist(string p , kernel_packages, {
return (p + "-" + extension);
});
}
}
return akp;
}
/*-----------------------------------------------------------------------
* GLOBAL FUNCTIONS
*-----------------------------------------------------------------------*/
global list<string> ComputeSystemPatternList () {
list<string> pattern_list = [];
// also add the 'laptop' selection if PCMCIA detected
if (Arch::is_laptop () || Arch::has_pcmcia ())
{
foreach (string pat_name, ["laptop", "Laptop"], {
list<map<string, any> > pat_list = Pkg::ResolvableProperties (pat_name, `pattern, "");
if (size (pat_list) > 0)
pattern_list = add (pattern_list, pat_name);
});
}
// FATE #302116
// BNC #431580
list <string> required_patterns = PackagesProposal::GetAllResolvables (`pattern);
if (required_patterns != nil && required_patterns != []) {
y2milestone ("Patterns required by PackagesProposal: %1", required_patterns);
pattern_list = (list <string>) merge (pattern_list, required_patterns);
}
y2milestone ("System patterns: %1", pattern_list);
return pattern_list;
}
/**
* Build and return list of packages which depends on the
* the current target system and the preselected packages
* (architecture, X11....)
* @return list<string> packages
*/
global define list<string> ComputeSystemPackageList ()
{
list<string> install_list = architecturePackages ();
install_list = (list<string>) union (install_list, modePackages ());
// No longer needed - partitions_proposal uses PackagesProposal now
// to gather the list of pkgs needed by y2-storage (#433001)
//list<string> storage_packages = (list<string>)WFM::call("wrapper_storage", ["AddPackageList"]);
if (size (additional_packages) > 0) {
y2warning ("Additional packages are still in use, please, change it to use PackagesProposal API");
y2milestone ("Additional packages: %1", additional_packages);
install_list = (list<string>) union (install_list, additional_packages);
}
// bnc #431580
// New API for packages selected by other modules
list <string> packages_proposal_all_packages = PackagesProposal::GetAllResolvables (`package);
if (size (packages_proposal_all_packages) > 0) {
y2milestone ("PackagesProposal::GetAllResolvables returned: %1", packages_proposal_all_packages);
install_list = (list<string>) union (install_list, packages_proposal_all_packages);
} else {
y2milestone ("No packages required by PackagesProposal");
}
// Kernel is added in autoinstPackages () if autoinst is enabled
if (!Mode::update () || !Mode::autoinst ())
{
list <string> kernel_pkgs = Kernel::ComputePackages ();
list <string> kernel_pkgs_additional = ComputeAdditionalKernelPackages();
install_list = (list <string>) union (install_list, kernel_pkgs);
if (size(kernel_pkgs_additional) > 0 && kernel_pkgs_additional != nil)
{
install_list = (list <string>) union (install_list, kernel_pkgs_additional);
}
}
if (Pkg::IsSelected("xorg-x11") && Linuxrc::vnc ())
{
install_list = (list<string>) union (install_list, graphicPackages ());
}
else
{
y2milestone ("Not selecting graphic packages");
}
if (Pkg::IsSelected("java"))
{
install_list = (list<string>) union (install_list, javaPackages ());
}
else
{
y2milestone ("Not selecting java packages");
}
install_list = (list<string>) union (install_list, boardPackages ());
// add packages required to access the repository in the 2nd stage and at run-time
install_list = (list<string>) union (install_list, sourceAccessPackages());
// and the most flexible enhancement for other products
// NOTE: not really flexible, because it requires the client
// in the instsys, instead use <kernel-packages> in the control file.
if (ProductFeatures::GetFeature ("software", "packages_transmogrify") != "")
{
list<string> tmp_list = (list<string>)
WFM::CallFunction (ProductFeatures::GetStringFeature ("software", "packages_transmogrify"),
[ install_list ]);
// Make sure we did not get a nil from calling the client, i.e.
// if the client does not exist at all..
if (tmp_list != nil)
{
install_list = tmp_list;
}
}
list<string> packages = (list<string>)
ProductFeatures::GetFeature ("software", "packages");
if (size(packages) > 0 && packages != nil )
{
y2milestone("Adding packages from control file: %1", packages);
install_list = (list<string>) union (install_list, packages);
}
install_list = toset (install_list);
y2milestone ("auto-adding packages: %1", install_list);
return install_list;
}
/**
* Check whether content file in the specified repository is the same
* as the one in the ramdisk
* @param source integer the repository ID to check
* @return boolean true if content files match
*/
global boolean CheckContentFile (integer source) {
y2milestone ("Checking content file");
string instmode = Linuxrc::InstallInf("InstMode");
if (! (instmode == nil || instmode == "cd" || instmode == "dvd"))
{
y2milestone ("Installing via network, not checking the content file");
return true;
}
string media_content = Pkg::SourceProvideSignedFile(source, 1, "/content", false);
string media = (string)SCR::Read (.target.string, media_content);
string ramdisk = (string)SCR::Read (.target.string, "/content");
boolean ret = (media == ramdisk);
y2milestone ("Content files are the same: %1", ret);
return ret;
}
/**
* Import GPG keys found in the inst-sys
*/
void ImportGPGKeys () {
map out = (map) SCR::Execute (.target.bash_output, "/bin/ls -d /*.gpg");
foreach (string file, splitstring (out["stdout"]:"", "\n"), {
if (file != "")
Pkg::ImportGPGKey (file, true);
});
}
string UpdateSourceURL (string url) {
string ret = "";
while (ret == "")
{
string msg = sformat( _("Unable to create repository
from URL '%1'."), URL::HidePassword(url) ) + "\n\n" + _("Details:")
+ "\n" + Pkg::LastError() + "\n\n" + _("Try again?");
if (Popup::YesNo (msg))
{
ret = SourceDialogs::EditPopup (url);
}
else
{
// error in proposal, %1 is URL
init_error = sformat (_("No repository found at '%1'."),
URL::HidePassword (url));
return "";
}
}
return ret;
}
list<string> LocaleVersions (string lang) {
list<string> ret = [ lang ];
list<string> components = splitstring (lang, ".");
if (components[0]:"" != lang && components[0]:"" != "")
{
lang = components[0]:"";
ret = add (ret, lang);
}
components = splitstring (lang, "_");
if (components[0]:"" != lang && components[0]:"" != "")
{
lang = components[0]:"";
ret = add (ret, lang);
}
return ret;
}
string ContentFileProductLabel () {
string language = Language::language;
list<string> locales = LocaleVersions (Language::language);
string ret = "";
foreach (string loc, locales, {
if (ret == "")
{
string val = (string)SCR::Read (add (.content, "LABEL." + loc));
if (val != "" && val != nil)
{
ret = val;
return ret;
}
}
});
return (string)SCR::Read (.content.LABEL);
}
integer base_source_id = nil;
/**
* Returns ID of the base product repository.
*
* @return integer base source ID
*/
global integer GetBaseSourceID () {
return base_source_id;
}
boolean FindAndCopySlideDir (string our_slidedir, integer source, string search_for_dir,
string lang_long, string lang_short, string fallback_lang) {
// directory used as a source of texts
string providedir = nil;
// one of the localizations (long or short)
string used_loc_dir = "";
foreach (string try_this_lang, [lang_long, lang_short, fallback_lang], {
if (try_this_lang == nil || try_this_lang == "")
return;
string test_dir = sformat ("%1/txt/%2", search_for_dir, try_this_lang);
y2milestone ("Checking '%1'", test_dir);
providedir = Pkg::SourceProvideSignedDirectory (source, 1, test_dir, true, true);
if (providedir != nil) {
y2milestone ("%1 lang found", try_this_lang);
used_loc_dir = try_this_lang;
// don't check for other langs
break;
}
});
// no wanted localization found
if (providedir == nil) {
y2milestone ("Neither %1 nor %2 localization found", lang_long, lang_short);
return false;
}
// where texts are stored later
string loc_slidedir = sformat ("%1/txt/%2/", our_slidedir, used_loc_dir);
WFM::Execute (.local.bash, sformat ("mkdir -p '%1'", String::Quote (loc_slidedir)));
// copy all files to our own cache
string copy_command = sformat("cp -r '%1/%2/txt/%3'/* '%4'",
String::Quote(providedir), String::Quote(search_for_dir),
String::Quote(used_loc_dir), String::Quote(loc_slidedir));
y2milestone ("Copying: %1", copy_command);
WFM::Execute (.local.bash, copy_command);
// where images are stored
string imagesdir = sformat ("%1/pic", search_for_dir);
imagesdir = Pkg::SourceProvideSignedDirectory (source, 1, imagesdir, true, true);
if (imagesdir != nil) {
// where images should be cached
string our_imagesdir = sformat ("%1/pic/", our_slidedir);
WFM::Execute (.local.bash, sformat ("mkdir -p '%1'", String::Quote (our_imagesdir)));
copy_command = sformat("cp -r '%1/%2/pic'/* '%3'",
String::Quote(imagesdir), String::Quote(search_for_dir), String::Quote (our_imagesdir));
y2milestone ("Copying: %1", copy_command);
WFM::Execute (.local.bash, copy_command);
} else {
y2error ("No such dir: %1", imagesdir);
}
return true;
}
boolean FindAndCopySlideDirWithoutCallbacks(string our_slidedir, integer source, string search_for_dir,
string lang_long, string lang_short, string fallback_lang)
{
// disable callbacks
PackageCallbacks::RegisterEmptyProgressCallbacks();
boolean ret = FindAndCopySlideDir (our_slidedir, source, search_for_dir, lang_long, lang_short, fallback_lang);
// restore callbacks
PackageCallbacks::RestorePreviousProgressCallbacks();
return ret;
}
global void Init(boolean unused);
global void SlideShowSetUp (string wanted_language) {
// bnc #432668
// Do not call init
if (Mode::live_installation()) {
y2milestone ("live_installation, not calling Init");
// bnc #427935
// Initialize the base_source_id first
} else {
Init (true);
}
// Do not reinitialize the SlideShow if not needed
// bnc #444612
if (size (SlideShow::GetSetup()) > 0) {
y2milestone ("SlideShow has been already set, skipping...");
return;
}
integer source = base_source_id;
string lang_long = "";
string lang_short = "";
// de_DE.UTF-8 -> de_DE
// es_ES -> es_ES
// blah -> ""
if (wanted_language != nil && wanted_language != "") {
y2milestone ("Selected language: %1", wanted_language);
if (regexpmatch (wanted_language, "^.+_.+$")) {
lang_long = wanted_language;
} else if (wanted_language != nil && wanted_language != "" && regexpmatch (wanted_language, "^.+_.+\..*$")) {
lang_long = regexpsub (wanted_language, "^(.+)_(.+)\..*", "\\1_\\2");
}
if (lang_long != nil && lang_long != "" && regexpmatch (lang_long, ".*_.*")) {
lang_short = regexpsub (lang_long, "(.*)_.*", "\\1");
} else if (wanted_language != nil && wanted_language != "") {
lang_short = wanted_language;
}
y2milestone ("Slide Show lang_long: %1, lang_short: %2", lang_long, lang_short);
} else {
y2error ("Wrong language definition: %1", wanted_language);
}
// setup slidedir
map productmap = Pkg::SourceProductData (source);
string datadir = productmap["datadir"]:"suse";
// target slideshow directory
string our_slidedir = sformat ("%1/slidedir/", (string) WFM::Read (.local.tmpdir, ""));
WFM::Execute (.local.bash, sformat ("mkdir -p '%1'", our_slidedir));
// media directory
// bugzilla #305097
//
// bugzilla #326327
// try to download only slides that are needed (by selected language)
// no images are cached
string search_for_dir = sformat ("/%1/setup/slide/", datadir);
FindAndCopySlideDirWithoutCallbacks(our_slidedir, source, search_for_dir, lang_long, lang_short, Slides::fallback_lang);
// Language has to be set otherwise it uses a fallback language
// BNC #444612 comment #2
SlideShow::SetLanguage (Language::language);
// fallback solution disabled
/*
if (success != true) {
y2milestone ("Using fallback solution, language is not supported");
string fallback_slidedir = Pkg::SourceProvideDirectory (source, 1, search_for_dir, true, true);
if (fallback_slidedir == nil) {
y2milestone ("No slide directory '%1' found in repository '%2'.",
search_for_dir, source);
} else {
// copy all files to our own cache
y2milestone ("Copying %1/* to %2/", fallback_slidedir, String::Quote (our_slidedir));
WFM::Execute (.local.bash, sformat ("cp -r %1/* '%2/'", fallback_slidedir, String::Quote (our_slidedir)));
}
}
*/
y2milestone ("Setting up the slide directory local copy: %1", our_slidedir);
Slides::SetSlideDir (our_slidedir);
if (load_release_notes (source))
{
// TRANSLATORS: beginning of the rich text with the release notes
SlideShow::relnotes = _("<p><b>These are the release notes made for the first initial release. They are
part of the installation media. During the configuration steps, if a connection
to the Internet is available, you can download updated release notes
from the SUSE Linux Web server.</b></p>") + media_text;
}
}
integer IntegrateServicePack (boolean show_popup, string base_url) {
/* Check for Service Pack */
boolean servicepack_available = false;
if ((integer)WFM::Read(.local.size, servicepack_metadata) > 0)
{
y2milestone("Service Pack data available");
boolean popup_open = false;
if (show_popup)
{
UI::OpenDialog(`opt(`decorated ),
// popup - information label
`Label(_("Integrating booted media...")));
popup_open = true;
}
string spdir = metadir + "/Service-Pack/CD1";
WFM::Execute (.local.mkdir, spdir);
y2milestone ("Filling %1", spdir);
WFM::Execute(.local.bash, "tar -zxvf " +
servicepack_metadata + " -C " + spdir);
string sp_url = "dir:" + spdir;
// close the popup in order to be able to ask about the license
if (popup_open)
{
popup_open = false;
UI::CloseDialog ();
}
integer sp_source = Pkg::SourceCreate (sp_url, "");
if (sp_source == -1)
{
Report::Error (_("Failed to integrate the service pack repository."));
return nil;
}
if (! AddOnProduct::AcceptedLicenseAndInfoFile(sp_source))
{
y2milestone ("service pack license rejected");
Pkg::SourceDelete (sp_source);
return nil;
}
if (FileUtils::Exists (spdir + "/installation.xml"))
{
WorkflowManager::AddWorkflow (`addon, sp_source, "");
WorkflowManager::MergeWorkflows();
}
if (FileUtils::Exists (spdir + "/y2update.tgz"))
{
AddOnProduct::UpdateInstSys (spdir + "/y2update.tgz");
}
theSources = add (theSources, sp_source);
y2internal ("Service pack repository: %1, changing to URL: %2",
sp_source, base_url);
Pkg::SourceChangeUrl (sp_source, base_url);
}
}
boolean Initialize_BaseInit (boolean show_popup, string & base_url, string & log_url) {
boolean popup_open = false;
if (show_popup)
{
UI::OpenDialog(`opt(`decorated ),
// popup - information label
`Label(_("Initializing repositories...")));
popup_open = true;
}
PackageCallbacks::InitPackageCallbacks ();
// Initialize package manager
init_error = nil;
y2milestone ("Packages::Initialize()");
if (Mode::test ())
{
// Fake values for testing purposes
base_url = "dir:///dist/next-i386";
}
else
{
base_url = InstURL::installInf2Url ("");
}
// hide password from URL if present
log_url = URL::HidePassword(base_url);
y2milestone ("Initialize Package Manager: %1", log_url);
// Set languages for packagemanager. Always set the UI language. Set
// language for additional packages only in Stage::initial ().
Pkg::SetTextLocale (Language::language);
if (popup_open)
{
UI::CloseDialog ();
popup_open = false;
}
return true;
}
/**
* Adjusts repository name according to LABEL in content file
* or a first product found on the media (as a fallback).
*
* @param integer repository ID
* @return boolean if successful
*
* @see BNC #481828
*/
global boolean AdjustSourcePropertiesAccordingToProduct (integer src_id) {
// This function is used from several places (also YaST Add-On)
if (src_id == nil || src_id < 0) {
y2error ("Wrong source ID: %1", src_id);
return nil;
}
y2milestone ("Trying to adjust repository name for: %1", src_id);
string new_name = nil;
// At first, try LABEL from content file
string contentfile = Pkg::SourceProvideSignedFile (src_id, 1, "/content", true /* optional */);
if (contentfile != nil) {
map contentmap = (map) SCR::Read (.content_file, contentfile);
if (haskey (contentmap, "LABEL") && contentmap["LABEL"]:nil != nil && contentmap["LABEL"]:"" != "") {
new_name = contentmap["LABEL"]:"";
if (regexpmatch (new_name, "^\[ \t\]\+"))
new_name = regexpsub (new_name, "^\[ \t\]\+(.*)", "\\1");
if (regexpmatch (new_name, "\[ \t\]\+$"))
new_name = regexpsub (new_name, "(.*)\[ \t\]\+$", "\\1");
y2milestone ("Using LABEL from content file: %1", new_name);
} else {
y2warning ("No (useful) LABEL in product content file");
}
}
// As a fallback,
if (new_name == nil || new_name == "") {
y2milestone ("Trying to get repository name from products");
list <map <string, any> > all_products = Pkg::ResolvableProperties ("", `product, "");
foreach (map <string, any> one_product, all_products, {
// source ID matches
if (one_product["source"]:-1 == src_id) {
if (haskey (one_product, "name") && one_product["name"]:nil != nil && one_product["name"]:"" != "") {
new_name = one_product["name"]:"";
y2milestone ("Product name found: %1", new_name);
break;
}
}
});
}
// Finally, some (new) name has been adjusted
if (new_name != nil && new_name != "") {
y2milestone ("Adjusting repository name");
list <map <string, any> > sources_got = Pkg::SourceEditGet();
list <map <string, any> > sources_set = [];
foreach (map <string, any> one_source, sources_got, {
if (one_source["SrcId"]:-1 == src_id) {
one_source["name"] = new_name;
}
sources_set = add (sources_set, one_source);
});
return Pkg::SourceEditSet (sources_set);
// Bad luck, nothing useful found
} else {
y2warning ("No name found");
return false;
}
}
global void Initialize_StageInitial (boolean show_popup, string base_url, string log_url) {
integer initial_source = nil;
ImportGPGKeys ();
while (initial_source == nil)
{
initial_source = Pkg::SourceCreateBase (base_url, "");
if (initial_source == -1 || initial_source == nil)
{
y2error ("No repository in '%1'", log_url);
base_url = UpdateSourceURL (base_url);
if (base_url != "")
{
initial_source = nil;
}
else
{
init_in_progress = false;
return;
}
}
if (! CheckContentFile (initial_source))
{
string label = ContentFileProductLabel ();
// bug #159754, release the mounted CD
Pkg::SourceReleaseAll();
Pkg::SourceDelete (initial_source);
initial_source = nil;
if (! Popup::ContinueCancel (
// message popup, %1 is product name
sformat (_("Insert %1 CD 1"), label)))
{
init_error = sformat (_("%1 CD 1 not found"), label);
init_in_progress = false;
return;
}
}
}
// BNC #481828: Using LABEL from content file as a repository name
AdjustSourcePropertiesAccordingToProduct (base_source_id);
base_source_id = initial_source;
y2milestone ("Base source ID: %1", base_source_id);
// Set the product before setting up add-on products
// In the autoyast mode it could be that the proposal
// screen will not be displayed. So the product will
// not be set. Bug 178831
SelectProduct ();
theSources = [ initial_source ];
integer sp_source = IntegrateServicePack (show_popup, base_url);
if (sp_source != nil)
theSources = add (theSources, sp_source);
if (ProductFeatures::GetFeature ("software", "selection_type") == `fixed)
{
Pkg::SetSelection (ProductFeatures::GetStringFeature ("software", "base_selection"));
}
string tmp_add_on_products = nil;
add_on_products_list = nil;
// #303675: Support several AddOns on standard SLE medium
// at first, try to find XML configuration
// then as a fallback/backward compatibility the old plain configuration
foreach (list <string> one_aop, [["/add_on_products.xml", "xml"], ["/add_on_products", "plain"]], {
string file = one_aop[0]:"";
string type = one_aop[1]:"";
// BNC #496404: These files should not be checked for signatures
tmp_add_on_products = Pkg::SourceProvideOptionalFile (initial_source, 1, file);
if (tmp_add_on_products != nil) {
add_on_products_list = sformat ("%1/add_on_products", SCR::Read (.target.tmpdir));
WFM::Execute (.local.bash, sformat ("cp %1 %2", tmp_add_on_products, add_on_products_list));
add_on_products_type = type;
y2milestone ("Found add_on_products %1 type %2", tmp_add_on_products, type);
break;
}
});
}
global void Initialize_StageNonInitial (boolean show_popup, string base_url, string log_url) {
if (theSources == nil || size (theSources) <= 0)
{
y2error ("Pkg::SourceStartCache failed");
theSources = [];
}
else if ( Stage::cont () // rewrite URL if cd/dvd since ide-scsi might have changed it
&& ((substring (base_url, 0, 2) == "cd")
|| (substring (base_url, 0, 3) == "dvd")))
{
foreach (integer source, theSources, {
map data = Pkg::SourceGeneralData (source); // get repository data
string url = data["url"]:"";
if ((substring (url, 0, 2) == "cd") // repository comes from cd/dvd
|| (substring (url, 0, 3) == "dvd"))
{
string new_url = InstURL::RewriteCDUrl(url);
y2milestone ("rewrite url: '%1'->'%2'", url, URL::HidePassword(new_url));
Pkg::SourceChangeUrl (source, new_url);
}
});
}
}
// lock some packages if needed
void LockPackages()
{
// currently there is no need to lock any package...
}
/**
* Initialize the repositories
* @param show_popup boolean true to display information about initialization
*/
global void Initialize(boolean show_popup) {
if (init_called || init_in_progress)
{
y2milestone ("Packages::Initialize() already called");
return;
}
init_in_progress = true;
// usual mountpoint for the medium
string base_url = "";
// url with hidden password for logging purpose
string log_url = "";
Initialize_BaseInit (show_popup, base_url, log_url);
theSources = Stage::initial() ? [] : Pkg::SourceStartCache (true); // dummy in 1st stage
boolean again = true;
while (again)
{
if (Stage::initial ())
{
Initialize_StageInitial (show_popup, base_url, log_url);
}
else // cont or normal mode
{
Initialize_StageNonInitial (show_popup, base_url, log_url);
}
y2milestone ("theSources %1", theSources);
y2milestone ("theSourceDirectories %1", theSourceDirectories);
if (size (theSources) >= 0)
{
init_called = true;
again = false;
}
else
{
// an error message
string errortext = sformat (_("Error while initializing package descriptions.
Check the log file %1 for more details."), Directory::logdir + "/y2log") +
"\n" + Pkg::LastError();
// FIXME somewhere get correct current_label and wanted_label
string result = PackageCallbacks::MediaChange ("NO_ERROR", errortext, base_url, "",
0, "", 1, "", false, [], 0);
}
}
// FATE #302123
AddOnProduct::SetBaseProductURL (base_url);
LockPackages();
init_in_progress = false;
}
global void Init(boolean unused) {
Initialize (true);
}
/**
* Select the base product on the media for installation
* @return boolean true on success
*/
global boolean SelectProduct () {
Packages::Initialize (true);
list<map<string,any> > products = Pkg::ResolvableProperties ("", `product, "");
if (size (products) == 0)
{
y2milestone ("No product found on media");
return true;
}
list<map<string,any> >selected_products = filter (map<string,any> p, products, {
return p["status"]:nil == `selected;
});
// no product selected -> select them all
boolean ret = true;
if (size (selected_products) == 0)
{
y2milestone ("No product selected so far...");
foreach (map<string,any> p, products, {
y2milestone ("Selecting product %1", p["name"]:"");
ret = Pkg::ResolvableInstall (p["name"]:"", `product) && ret;
});
}
return ret;
}
/**
* Select system patterns
* @param reselect boolean true to select only those which are alrady selected
*/
void SelectSystemPatterns (boolean reselect) {
list<string> system_patterns = ComputeSystemPatternList ();
// autoinstallation has patterns specified in the profile
if (! Mode::autoinst ())
{
system_patterns = (list<string>)
toset (merge (system_patterns, Product::patterns));
}
if (! reselect)
{
y2milestone ("Selecting system patterns %1", system_patterns);
foreach (string p, system_patterns, {
map prop = Pkg::ResolvableProperties(p, `pattern, "")[0]:$[];
if (prop["status"]:nil == `available && prop["transact_by"]:nil == `user)
{
y2milestone("Ignoring deselected pattern '%1'", p);
}
else
{
Pkg::ResolvableInstall (p, `pattern);
}
});
}
else
{
y2milestone ("Re-selecting system patterns %1", system_patterns);
list<string>pats = filter (string p, system_patterns, {
list<map<string,any> > descrs = Pkg::ResolvableProperties (p, `pattern, "");
descrs = filter (map<string,any> descr, descrs, {
return descr["status"]:nil == `selected;
});
return size (descrs) > 0;
});
y2milestone ("Selected patterns to be reselected: %1", pats);
foreach (string p, pats, {
Pkg::ResolvableRemove (p, `pattern);
Pkg::ResolvableInstall (p, `pattern);
});
}
}
/**
* Select system packages
* @param reselect boolean true to select only those which are alrady selected
*/
void SelectSystemPackages (boolean reselect) {
list<string> system_packages = ComputeSystemPackageList();
if (! reselect)
{
y2milestone ("Selecting system packages %1", system_packages);
}
else
{
y2milestone ("Re-selecting new versions of system packages %1", system_packages);
// first deselect the package (and filter selected ones)
system_packages = filter (string p, system_packages, {
if (Pkg::IsProvided (p) || Pkg::IsSelected (p))
{
Pkg::PkgDelete (p);
return true;
}
return false;
});
y2milestone ("System packages to be reselected: %1", system_packages);
}
map <string, any> res = Pkg::DoProvide (system_packages);
if (size (res) > 0)
{
foreach (string s, any a, res, {
y2warning ("Pkg::DoProvide failed for %1: %2", s, a);
});
}
}
any old_packages_proposal = nil;
/**
* Make a proposal for package selection
*
* @param force reset (fully resets the proposal and creates a new one)
* @param re-initialize (soft-reset, doesn't reset resolbavle manually selected by user)
*
* @return map for the API proposal
*/
global map Proposal (boolean force_reset, boolean reinit, boolean simple) {
// Handle the default desktop
DefaultDesktop::Init();
// If anything has changed
any new_packages_proposal = PackagesProposal::GetAllResolvablesForAllTypes();
// Force reinit
if (new_packages_proposal != old_packages_proposal) {
y2milestone ("PackagesProposal have changed");
old_packages_proposal = new_packages_proposal;
reinit = true;
}
// Reinit forced by application, see ForceFullRepropose
if (full_repropose == true) {
y2milestone ("Fully reproposing");
force_reset = true;
full_repropose = false;
}
if (force_reset) {
y2milestone ("Forcing full reset");
// Full reset has been forced, bnc #446406
// It resets even the user-selected/removed resolvables
Pkg::PkgReset();
ResetProposalCache();
reinit = true;
}
// if the cache is valid and reset or reinitialization is not required
// then the cached proposal can be used
if (cached_proposal != nil && force_reset == false && reinit == false)
{
// selected packages
list<string> selected_packages = Pkg::GetPackages(`selected, false);
// selected patterns
list<map> selected_patterns = filter(map p, Pkg::ResolvableProperties("", `pattern, ""), {return p["status"]:`unknown == `selected;});
// selected products
list<map> selected_products = filter(map p, Pkg::ResolvableProperties("", `product, ""), {return p["status"]:`unknown == `selected;});
// selected patches
list<map> selected_patches = filter(map p, Pkg::ResolvableProperties("", `patch, ""), {return p["status"]:`unknown == `selected;});
// selected selections
list<map> selected_selections = filter(map s, Pkg::ResolvableProperties("", `selection, ""), {return s["status"]:`unknown == `selected;});
// selected languages
list<string> selected_languages = (list<string>)union([Pkg::GetPackageLocale()], Pkg::GetAdditionalLocales());
// if the package selection has not been changed the cache is up to date
if (selected_packages == cached_proposal_packages && selected_patterns == cached_proposal_patterns
&& selected_products == cached_proposal_products && selected_patches == cached_proposal_patches
&& selected_selections == cached_proposal_selections && selected_languages == cached_proposal_languages)
{
y2milestone("using cached software proposal");
return cached_proposal;
}
// do not show the error message during the first proposal
// (and the only way to change to software selection manually -> software_proposal/AskUser)
//
// 'nil' is the default value
// See also ResetProposalCache()
else if (cached_proposal_packages != nil && cached_proposal_patterns != nil
&& cached_proposal_products != nil && cached_proposal_patches != nil
&& cached_proposal_selections != nil && cached_proposal_languages != nil)
{
y2error("invalid cache: the software selection has been chaged");
// bnc #436925
Report::Message(_("The software selection has been changed externally.
Software proposal will be called again."));
}
}
else
{
y2milestone("the cached proposal is empty or reset is required");
}
UI::OpenDialog(`opt(`decorated ),
// popup label
`Label (_("Evaluating package selection...")));
y2milestone ("Packages::Proposal: force_reset %1, reinit %2, lang '%3'",
force_reset, reinit, Language::language);
// Soft proposal reset
if ( !Mode::autoinst() && reinit )
{
y2milestone ("Re/Proposing software selection");
Kernel::ProbeKernel();
Packages::Reset ([`product]);
reinit = true;
LockPackages();
}
boolean initial_run = reinit || ! init_called;
Initialize (true);
if (init_error != nil)
{
UI::CloseDialog();
return Summary ([], false);
}
if (initial_run)
{
// autoyast can configure AdditionalLocales
// we don't want to overwrite this
if( ! Mode::autoinst ())
{
Pkg::SetAdditionalLocales ([Language::language]);
}
}
SelectProduct ();
if (ProductFeatures::GetFeature ("software", "selection_type") == `auto)
{
y2milestone ("Doing pattern-based software selection");
SelectSystemPackages (system_packages_selected && ! initial_run);
SelectSystemPatterns (system_packages_selected && ! initial_run);
system_packages_selected = true;
}
else if (ProductFeatures::GetFeature ("software","selection_type") == `fixed)
{
y2milestone ("Selection type: fixed");
}
else
{
y2error ("unknown value %1 for ProductFeatures::GetFeature (software, selection_type)",
(symbol)ProductFeatures::GetFeature ("software", "selection_type"));
}
if (! Pkg::PkgSolve (false))
{
solve_errors = Pkg::PkgSolveErrors ();
}
// Question: is `desktop appropriate for SLE?
map ret = Summary (
[ `product, `pattern, `selection, `size, `desktop ],
false);
// TODO simple proposal
// cache the proposal
cached_proposal = ret;
// remember the status
cached_proposal_packages = Pkg::GetPackages(`selected, false);
cached_proposal_patterns = filter(map p, Pkg::ResolvableProperties("", `pattern, ""), {return p["status"]:`unknown == `selected;});
cached_proposal_products = filter(map p, Pkg::ResolvableProperties("", `product, ""), {return p["status"]:`unknown == `selected;});
cached_proposal_patches = filter(map p, Pkg::ResolvableProperties("", `patch, ""), {return p["status"]:`unknown == `selected;});
cached_proposal_selections = filter(map s, Pkg::ResolvableProperties("", `selection, ""), {return s["status"]:`unknown == `selected;});
cached_proposal_languages = (list<string>)union([Pkg::GetPackageLocale()], Pkg::GetAdditionalLocales());
UI::CloseDialog();
y2milestone ("Software proposal: %1", ret);
return ret;
}
/**
* Initialize the repositories with popup feedback
* Use Packages::Initialize (true) instead
*/
global void InitializeCatalogs() {
Packages::Initialize (true);
}
global boolean InitFailed () {
boolean ret = init_error != nil;
y2milestone ("Package manager initialization failed: %1", ret);
return ret;
}
// see bug 302398
global define void SelectKernelPackages () {
list <list> provides = Pkg::PkgQueryProvides ("kernel");
// // e.g.: [["kernel-bigsmp", `CAND, `NONE], ["kernel-default", `CAND, `CAND], ["kernel-default", `BOTH, `INST]]
y2milestone ("provides: %1", provides);
// these kernels would be installed
list <list> kernels = filter (list l, provides, {
return l[1]:`NONE == `BOTH || l[1]:`NONE == l[2]:`NONE;
});
if (size (kernels) != 1)
y2warning ("not exactly one package provides tag kernel");
string selected_kernel = kernels[0,0]:"none";
list <string> recom_kernel = Kernel::ComputePackages ();
string recommended_kernel = recom_kernel[0]:"";
y2milestone ("Selected kernel: %1, recommended kernel: %2",
selected_kernel, recom_kernel);
// when the recommended Kernel is not available (installable)
if (recommended_kernel != "" && ! Pkg::IsAvailable (recommended_kernel)) {
recommended_kernel = selected_kernel;
}
// recommended package is different to the selected one
// select the recommended one
if (recommended_kernel != "" && recommended_kernel != selected_kernel) {
// list of kernels to be installed
list <string> kernels_to_be_installed = (list <string>) maplist (list one_kernel, kernels, {
return one_kernel[0]:nil;
});
kernels_to_be_installed = filter (string one_kernel, kernels_to_be_installed, {
return (one_kernel != nil && one_kernel != "");
});
// remove all kernels (with some exceptions)
foreach (string one_kernel, kernels_to_be_installed, {
// XEN can be installed in parallel
if (one_kernel == "kernel-xen") return;
if (one_kernel == "kernel-xenpae") return;
// don't remove the recommended one
if (one_kernel == recommended_kernel) return;
// remove all packages of that kernel
list <string> packages_to_remove = Kernel::ComputePackagesForBase (one_kernel, false);
if (packages_to_remove != nil && size (packages_to_remove) > 0) {
y2milestone ("Removing installed packages %1", packages_to_remove);
Pkg::DoRemove (packages_to_remove);
}
});
// compute recommended kernel packages
list<string> kernel_packs = Kernel::ComputePackages ();
y2milestone("Install kernel packages: %1", kernel_packs);
// installing all recommended packages
foreach (string p, kernel_packs, {
if (Pkg::PkgAvailable(p)) {
y2milestone ("Selecting package %1 for installation", p);
Pkg::PkgInstall (p);
}
else
{
y2error("Package %1 is not available", p);
}
});
}
}
/* EOF */
}
ACC SHELL 2018