Author: mvidner
Date: Mon Jul 30 14:56:09 2007
New Revision: 39786
URL: http://svn.opensuse.org/viewcvs/yast?rev=39786&view=rev
Log:
Implementing http://en.opensuse.org/Standards/One_Click_Install
- Added http://benjiweber.co.uk/OCI/deploy.tar.gz
- see http://lists.opensuse.org/yast-devel/2007-07/msg00082.html
Added:
trunk/metapackage/OneClickInstall.ycp (with props)
trunk/metapackage/OneClickInstallUI.ycp (with props)
trunk/metapackage/OneClickInstallUrlHandler.ycp (with props)
trunk/metapackage/OneClickInstallWorker.ycp (with props)
trunk/metapackage/OneClickInstallWorkerResponse.ycp (with props)
trunk/metapackage/YPX.pm
Added: trunk/metapackage/OneClickInstall.ycp
URL: http://svn.opensuse.org/viewcvs/yast/trunk/metapackage/OneClickInstall.ycp?rev=39786&view=auto
==============================================================================
--- trunk/metapackage/OneClickInstall.ycp (added)
+++ trunk/metapackage/OneClickInstall.ycp Mon Jul 30 14:56:09 2007
@@ -0,0 +1,739 @@
+{
+ /**
+ * Module to provide simple API for working with the One Click Install metapackages.
+ * Enables removal of non-UI logic from UI module.
+ **/
+ textdomain "OneClickInstall";
+ module "OneClickInstall";
+
+ import "XML";
+ import "Product";
+ import "Language";
+
+ import "YPX";
+
+ /**
+ * repositories =
+ * $[ url =>
+ * $[
+ * name,
+ * summary,
+ * description,
+ * recommended
+ * ]
+ *
+ * ]
+ **/
+ map > repositories = $[];
+
+ /**
+ * software =
+ * $[ name =>
+ * $[
+ * summary,
+ * description,
+ * recommended
+ * ]
+ * ]
+ **/
+ map > software = $[];
+
+ //Whether the user should remain subscribed to these repositories post installation.
+ boolean remainSubscribed = true;
+
+ //The name of this software bundle.
+ string name = "";
+
+ //The summary of this software bundle.
+ string summary = "";
+
+ //The description of this software bundle.
+ string description = "";
+
+ /**
+ *
+ * Load the Metapackage from the URL supplied for further processing.
+ * Converts from original form into a simple two lists, one of repositories, other of software.
+ * Uses the Product.ycp to obtain the correct version for our product.
+ * Uses the Language.ycp to obtain correct strings for our language.
+ *
+ * Picks the strings, mirror, and product at evaluation time.
+
+ * N.B. This must be called before any of the rest of the methods.
+ *
+ * Internally the following format is used:
+ * repositories =
+ * $[ url =>
+ * $[
+ * name,
+ * summary,
+ * description,
+ * recommended
+ * ]
+ *
+ * ]
+ *
+ * software =
+ * $[ name =>
+ * $[
+ * summary,
+ * description,
+ * action,
+ * type,
+ * recommended
+ * ]
+ * ]
+ * @param url The file to load the xml from.
+ **/
+ global void Load(string url)
+ {
+ //Load the XML from file.
+ any xml = YPX::Load(url);
+
+ //Try and load the name.
+ name = YPX::SelectValue(xml,"/metapackage/group[@distversion='" + Product::name + "']/name");
+ if (name == "")
+ name = YPX::SelectValue(xml,"/metapackage/group[not(@distversion)]/name");
+
+ string rs = YPX::SelectValue(xml,"/metapackage/group[@distversion='" + Product::name + "']/remainSubscribed");
+ if (rs == "")
+ rs = YPX::SelectValue(xml,"/metapackage/group[not(@distversion)]/remainSubscribed");
+ if (rs == "false")
+ remainSubscribed = false;
+ else
+ remainSubscribed = true;
+
+
+ //Try and load the summary.
+ summary = YPX::SelectValue(xml,"/metapackage/group[@distversion='" + Product::name + "']/summary[@lang='" + Language::language + "']");
+ if (summary == "")
+ summary = YPX::SelectValue(xml,"/metapackage/group[@distversion='" + Product::name + "']/summary[not(@lang)]");
+ if (summary == "")
+ summary = YPX::SelectValue(xml,"/metapackage/group[not(@distversion)]/summary[@lang='" + Language::language + "']");
+ if (summary == "")
+ summary = YPX::SelectValue(xml,"/metapackage/group[not(@distversion)]/summary[not(@lang)]");
+
+ //Try and load the description.
+ description = YPX::SelectValue(xml,"/metapackage/group[@distversion='" + Product::name + "']/description[@lang='" + Language::language + "']");
+ if (description == "")
+ description = YPX::SelectValue(xml,"/metapackage/group[@distversion='" + Product::name + "']/description[not(@lang)]");
+ if (description == "")
+ description = YPX::SelectValue(xml,"/metapackage/group[not(@distversion)]/description[@lang='" + Language::language + "']");
+ if (description == "")
+ description = YPX::SelectValue(xml,"/metapackage/group[not(@distversion)]/description[not(@lang)]");
+
+ //Load the repository details into our internal format from xml.
+ //We want to load details for our specific version.
+ string REPO_XPATH = "/metapackage/group[@distversion='" + Product::name + "']/repositories/repository";
+ //If that fails, use any.
+ string FALLBACK_REPO_XPATH = "/metapackage/group[not(@distversion)]/repositories/repository";
+
+
+ //Select the repository URLs from the XML.
+ list<string> repoURLs = YPX::SelectValues(xml,REPO_XPATH + "/url");
+ //If we didn't have any try fallback xpath.
+ if (size(repoURLs) == 0)
+ {
+ REPO_XPATH = FALLBACK_REPO_XPATH;
+ repoURLs = YPX::SelectValues(xml,REPO_XPATH + "/url");
+ }
+ //Loop through the repo URLs and query the other details from the XML.
+ foreach (string url, repoURLs,
+ {
+ //Construct xpath to query details of this specific repository
+ string THIS_REPO_XPATH = REPO_XPATH + "[url='" + url + "']/";
+ string recommended = YPX::SelectValue(xml,THIS_REPO_XPATH + "@recommended");
+
+ //If recommended not specified we default to true.
+ if (recommended != "false")
+ recommended = "true";
+
+ //Find the name of this repository
+ string name = YPX::SelectValue(xml,THIS_REPO_XPATH + "name");
+ //Find the summary of this repository, in our language.
+ string summary = YPX::SelectValue(xml,THIS_REPO_XPATH + "summary[@lang='"+ Language::language +"']");
+ //If that failed, try without a language.
+ if (summary == "")
+ summary = YPX::SelectValue(xml,THIS_REPO_XPATH + "summary[not(@lang)]");
+ //Find the description of this repository, in our language.
+ string description = YPX::SelectValue(xml,THIS_REPO_XPATH + "description[@lang='"+ Language::language +"']");
+ //If that failed, try without a language.
+ if (description == "")
+ description = YPX::SelectValue(xml,THIS_REPO_XPATH + "description[not(@lang)]");
+ //Store this repository details in our list.
+ map repoDetails =
+ $[
+ "name":name,
+ "summary":summary,
+ "description":description,
+ "recommended":recommended
+ ];
+ repositories = add(repositories,url,repoDetails);
+ });
+
+ //Load package names for this distversion.
+ string SOFTWARE_XPATH = "/metapackage/group[@distversion='" + Product::name + "']/software/item";
+ //Incase that isn't specified use any where distversion is not specified.
+ string FALLBACK_SOFTWARE_XPATH = "/metapackage/group[not(@distversion)]/software/item";
+ list<string> softwareNames = YPX::SelectValues(xml,SOFTWARE_XPATH+ "/name");
+ //If we didn't have any try fallback xpath.
+ if (size(softwareNames) == 0)
+ {
+ SOFTWARE_XPATH = FALLBACK_SOFTWARE_XPATH;
+ softwareNames = YPX::SelectValues(xml,SOFTWARE_XPATH + "/name");
+ }
+ foreach (string name, softwareNames,
+ {
+ //Construct xpath to query details of this specific software.
+ string THIS_SOFTWARE_XPATH = SOFTWARE_XPATH + "[name='" + name + "']/";
+ //Check whether it was recommended.
+ string recommended = YPX::SelectValue(xml,THIS_SOFTWARE_XPATH + "@recommended");
+ //If recommended not specified we default to true.
+ if (recommended != "false")
+ recommended = "true";
+ string action = YPX::SelectValue(xml,THIS_SOFTWARE_XPATH + "@action");
+ //If action not specified we default to install.
+ if (action != "remove")
+ action = "install";
+ string type = YPX::SelectValue(xml,THIS_SOFTWARE_XPATH + "@type");
+ //If action not specified we default to install.
+ if (type != "pattern")
+ type = "package";
+ //Find the summary for this software, preferably in our language.
+ string summary = YPX::SelectValue(xml,THIS_SOFTWARE_XPATH + "summary[@lang='"+ Language::language +"']");
+ if (summary == "")
+ summary = YPX::SelectValue(xml,THIS_SOFTWARE_XPATH + "summary[not(@lang)]");
+ //Find the description of this software, preferably in our language.
+ string description = YPX::SelectValue(xml,THIS_SOFTWARE_XPATH + "description[@lang='"+ Language::language +"']");
+ if (description == "")
+ description = YPX::SelectValue(xml,THIS_SOFTWARE_XPATH + "description[not(@lang)]");
+ //Store these software details in our list.
+ map softwareDetails =
+ $[
+ "summary":summary,
+ "description":description,
+ "action":action,
+ "type":type,
+ "recommended":recommended
+ ];
+ software = add(software,name,softwareDetails);
+ });
+ }
+
+ /** <region name="Repositories"> **/
+
+ /**
+ * @return a list of the URLs of the repositories currently selected for addition.
+ **/
+ global list<string> GetRequiredRepositories()
+ {
+ list<string> repoURLs = [];
+ foreach (string repoURL, map repoDetails, repositories,
+ {
+ if (repoDetails["recommended"]:"false" == "true")
+ repoURLs = add(repoURLs, repoURL);
+ });
+ return repoURLs;
+ }
+
+ /**
+ * Ensures that the repository with the specified URL is selected for addition.
+ * @param url the url of the repository to ensure is selected for addition.
+ **/
+ global void SetRequiredRepository(string url)
+ {
+ map repoDetails = repositories[url]:nil;
+ if (repoDetails == nil)
+ return;
+ repoDetails = add(repoDetails,"recommended","true");
+ repositories = add(repositories,url,repoDetails);
+ }
+
+ /**
+ * @return a list of the URLs of the repositories currently NOT selected for addition.
+ **/
+ global list<string> GetNonRequiredRepositories()
+ {
+ list<string> repoURLs = [];
+ foreach (string repoURL, map repoDetails, repositories,
+ {
+ if (repoDetails["recommended"]:"false" == "false")
+ repoURLs = add(repoURLs, repoURL);
+ });
+ return repoURLs;
+ }
+
+ /**
+ * Ensures that the repository with the specified URL is NOT selected for addition.
+ * @param url the url to ensure is not selected for addition
+ **/
+ global void SetNonRequiredRepository(string url)
+ {
+ map repoDetails = repositories[url]:nil;
+ if (repoDetails == nil)
+ return;
+ repoDetails = add(repoDetails,"recommended","false");
+ repositories = add(repositories,url,repoDetails);
+ }
+
+
+ /**
+ * Ensures that the repositories with specified URLs are selected for addition, and all others are not.
+ * @param urls the urls to ensure are selected.
+ **/
+ global void SetRequiredRepositories(list<string> urls)
+ {
+ foreach (string url, map repoDetails, repositories,
+ {
+ if (contains(urls,url))
+ {
+ SetRequiredRepository(url);
+ } else
+ {
+ SetNonRequiredRepository(url);
+ }
+ });
+ }
+
+
+ /**
+ * @return the name of the repository with the specified name.
+ **/
+ global string GetRepositoryName(string url)
+ {
+ map repoDetails = repositories[url]:nil;
+ if (repoDetails == nil)
+ return "";
+ return repoDetails["name"]:"";
+ }
+
+ /**
+ * @return the summary of the repository with the specified name.
+ * This will be in the user's current language if there was a localised summary available.
+ **/
+ global string GetRepositorySummary(string url)
+ {
+ map repoDetails = repositories[url]:nil;
+ if (repoDetails == nil)
+ return "";
+ return repoDetails["summary"]:"";
+ }
+
+ /**
+ * @return the description of the repository with the specified name.
+ * This will be in the user's current language if there was a localised description available.
+ **/
+ global string GetRepositoryDescription(string url)
+ {
+ map repoDetails = repositories[url]:nil;
+ if (repoDetails == nil)
+ return "";
+ return repoDetails["description"]:"";
+ }
+
+ /** </region> **/
+
+ /** <region name="Software"> **/
+
+ /**
+ * @return a list of the names of the software currently selected for installation.
+ **/
+ global list<string> GetRequiredSoftware()
+ {
+ list<string> names = [];
+ foreach (string name, map softwareDetails, software,
+ {
+ if ((softwareDetails["recommended"]:"false" == "true") && (softwareDetails["action"]:"install" == "install"))
+ names = add(names, name);
+ });
+ return names;
+ }
+
+ global list<string> GetRequiredPackages()
+ {
+ list<string> names = [];
+ foreach (string name, map softwareDetails, software,
+ {
+ if (
+ (softwareDetails["recommended"]:"false" == "true") &&
+ (softwareDetails["action"]:"install" == "install") &&
+ (softwareDetails["type"]:"package" == "package")
+ )
+ {
+ names = add(names, name);
+ }
+ });
+ return names;
+ }
+
+ global list<string> GetRequiredPatterns()
+ {
+ list<string> names = [];
+ foreach (string name, map softwareDetails, software,
+ {
+ if (
+ (softwareDetails["recommended"]:"false" == "true") &&
+ (softwareDetails["action"]:"install" == "install") &&
+ (softwareDetails["type"]:"package" == "pattern")
+ )
+ {
+ names = add(names, name);
+ }
+ });
+ return names;
+ }
+
+ /**
+ * @return a list of the names of the software currently selected for removal.
+ **/
+ global list<string> GetRequiredRemoveSoftware()
+ {
+ list<string> names = [];
+ foreach (string name, map softwareDetails, software,
+ {
+ if ((softwareDetails["recommended"]:"false" == "true") && (softwareDetails["action"]:"install" == "remove"))
+ names = add(names, name);
+ });
+ return names;
+ }
+
+ /**
+ * Ensures the software with the specified name is selected for installation or removal.
+ * @param the name of the software to ensure is selected for installation.
+ **/
+ global void SetRequiredSoftware(string name)
+ {
+ map softwareDetails = software[name]:nil;
+ if (softwareDetails == nil)
+ return;
+ softwareDetails = add(softwareDetails,"recommended","true");
+ software = add(software,name,softwareDetails);
+ }
+
+ /**
+ * @return a list of the names of the software currently NOT selected for installation.
+ **/
+ global list<string> GetNonRequiredSoftware()
+ {
+ list<string> names = [];
+ foreach (string name, map softwareDetails, software,
+ {
+ if ((softwareDetails["recommended"]:"false" == "false") && (softwareDetails["action"]:"install" == "install"))
+ names = add(names, name);
+ });
+ return names;
+ }
+
+ /**
+ * @return a list of the names of the software currently selected for removal.
+ **/
+ global list<string> GetNonRequiredRemoveSoftware()
+ {
+ list<string> names = [];
+ foreach (string name, map softwareDetails, software,
+ {
+ if ((softwareDetails["recommended"]:"false" == "false") && (softwareDetails["action"]:"install" == "remove"))
+ names = add(names, name);
+ });
+ return names;
+ }
+
+ /**
+ * Ensures the software with the specified name is NOT selected for installation or removal.
+ * @param the name of the software to ensure is NOT selected for installation.
+ **/
+ global void SetNonRequiredSoftware(string name)
+ {
+ map softwareDetails = software[name]:nil;
+ if (softwareDetails == nil)
+ return;
+ softwareDetails = add(softwareDetails,"recommended","false");
+ software = add(software,name,softwareDetails);
+ }
+
+ /**
+ * Ensures that the repositories with specified URLs are selected for addition, and all others are not.
+ * Invalid pluralisation due to lack of proper overloading :(
+ * @param the names of the software to ensure is selected for installation.
+ **/
+ global void SetRequiredSoftwares(list<string> names)
+ {
+ foreach (string name, map softwareDetails, software,
+ {
+ if (contains(names,name))
+ {
+ SetRequiredSoftware(name);
+ } else
+ {
+ SetNonRequiredSoftware(name);
+ }
+ });
+ }
+
+ /**
+ * @return the summary for the software with specified name.
+ * This will be in the user's current language if there was a localised summary available.
+ **/
+ global string GetSoftwareSummary(string name)
+ {
+ map softwareDetails = software[name]:nil;
+ if (softwareDetails == nil)
+ return "";
+ return softwareDetails["summary"]:"";
+ }
+
+ /**
+ * @return the description for the software with specified name.
+ * This will be in the user's current language if there was a localised description available.
+ **/
+ global string GetSoftwareDescription(string name)
+ {
+ map softwareDetails = software[name]:nil;
+ if (softwareDetails == nil)
+ return "";
+ return softwareDetails["description"]:"";
+ }
+
+ /** </region> **/
+
+ /** <region name="Processing"> **/
+
+ /**
+ * Specify whether the user should remain subscribed to the repositories after installation of this software is complete.
+ * @param the boolean value indicating whether the user should remain subscribed.
+ **/
+ global void SetRemainSubscribed(boolean value)
+ {
+ remainSubscribed = value;
+ }
+
+ /**
+ * @return the current setting of whether the user should remain subscribed to repositories after installation.
+ **/
+ global boolean GetRemainSubscribed()
+ {
+ return remainSubscribed;
+ }
+
+ /**
+ * @return the name for this software bundle.
+ **/
+ global string GetName()
+ {
+ return name;
+ }
+
+ /**
+ * @return the summary for this software bundle.
+ * This will be in the user's current language if there was a localised summary available.
+ **/
+ global string GetSummary()
+ {
+ return summary;
+ }
+
+ /**
+ * @return the description for this software bundle.
+ * This will be in the user's current language if there was a localised description available.
+ **/
+ global string GetDescription()
+ {
+ return description;
+ }
+
+ /**
+ * @return Find out whether we have any repositories that need to be added for this installation.
+ * Useful to find out whether to display this wizard step.
+ **/
+ global boolean HaveRepositories()
+ {
+ return (size(repositories) > 0);
+ }
+
+ /**
+ * @return Find out whether we have any software that needs to be installed for this installation.
+ * Useful to find out whether to display this wizard step.
+ **/
+ global boolean HaveSoftware()
+ {
+ boolean haveSoftware = false;
+ foreach (string name, map softwareDetails, software,
+ {
+ if ((softwareDetails["action"]:"install") == "install")
+ {
+ haveSoftware = true;
+ return haveSoftware;
+ }
+ });
+ return haveSoftware;
+ }
+
+ global boolean HavePackagesToInstall()
+ {
+ boolean have = false;
+ foreach (string name, map softwareDetails, software,
+ {
+ if (
+ (softwareDetails["recommended"]:"false" == "true") &&
+ (softwareDetails["action"]:"install" == "install") &&
+ (softwareDetails["type"]:"package" == "package")
+ )
+ {
+ have = true;
+ return have;
+ }
+ });
+ return have;
+ }
+
+ global boolean HavePatternsToInstall()
+ {
+ boolean have = false;
+ foreach (string name, map softwareDetails, software,
+ {
+ if (
+ (softwareDetails["recommended"]:"false" == "true") &&
+ (softwareDetails["action"]:"install" == "install") &&
+ (softwareDetails["type"]:"package" == "pattern")
+ )
+ {
+ have = true;
+ return have;
+ }
+ });
+ return have;
+ }
+
+ global boolean HaveRepositoriesToInstall()
+ {
+ boolean have = false;
+ foreach (string url, map repoDetails, repositories,
+ {
+ if (
+ (repoDetails["recommended"]:"false" == "true")
+ )
+ {
+ have = true;
+ return have;
+ }
+ });
+ return have;
+ }
+
+ global boolean HaveRemovalsToInstall()
+ {
+ boolean have = false;
+ foreach (string name, map softwareDetails, software,
+ {
+ if (
+ (softwareDetails["action"]:"install" == "remove") &&
+ (softwareDetails["recommended"]:"false" == "true")
+ )
+ {
+ have = true;
+ return have;
+ }
+ });
+ return have;
+ }
+
+ /**
+ * @return Find out whether we have any software that needs to be removed for this installation.
+ * Useful to find out whether to display this wizard step.
+ **/
+ global boolean HaveRemovals()
+ {
+ boolean haveSoftware = false;
+ foreach (string name, map softwareDetails, software,
+ {
+ if ((softwareDetails["action"]:"install") == "remove")
+ {
+ haveSoftware = true;
+ return haveSoftware;
+ }
+ });
+ return haveSoftware;
+ }
+
+ /**
+ * Converts our map -> map structure to a list of maps with a "key" element.
+ * This is friendly for yast's XML serialisation support.
+ **/
+ list