ACC SHELL

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

{
	/**
	 * 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<string, map<string,string> > repositories = $[];

	/**
	  *	software = 
	  *		$[ name => 
	  *			$[
	  *				summary,
	  *				description,
	  *				recommended
	  *			]
	  *		]
	**/
	map<string, map<string,string> > 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);
		//Load returns false on error
		if (xml == false)
			return;

		//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";


			//Get the name in our language
			string name = YPX::SelectValue(xml,THIS_REPO_XPATH + "name[@lang='" + Language::language + "']");
			//If that failed, try without a language
			if (name == "")
				name = YPX::SelectValue(xml,THIS_REPO_XPATH + "name[not(@lang)]");


			//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<string,string> 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<string,string> 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<string,string> 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<string,string> 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<string,string> 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<string,string> 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<string,string> 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<string,string> 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<string,string> 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<string,string> 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<string,string> 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<string,string> 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<string,string> 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<string,string> 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<string,string> 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<string,string> 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<string,string> 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<string,string> 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<string,string> 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<string,string> 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<string,string> 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<string,string> softwareDetails, software,
		{
			if ((softwareDetails["action"]:"install") == "install")
			{
				haveSoftware = true;
				return haveSoftware;
			}
		});
		return haveSoftware;
	}

	global boolean HavePackagesToInstall()
	{
		boolean have = false;
		foreach (string name, map<string,string> 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<string,string> 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<string,string> repoDetails, repositories,
		{
			if (
			(repoDetails["recommended"]:"false" == "true")
				)
			{
				have = true;
				return have;
			}
		});
		return have;
	}

	global boolean HaveRemovalsToInstall()
	{
		boolean have = false;
		foreach (string name, map<string,string> 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<string,string> softwareDetails, software,
		{
			if ((softwareDetails["action"]:"install") == "remove")
			{
				haveSoftware = true;
				return haveSoftware;
			}
		});
		return haveSoftware;
	}
	
	/**
	 * @return Whether we have anything to do
	 * Determine whether we have a proper metapackage, useful as we can't throw exceptions.
	**/
	global boolean HaveAnythingToDo()
	{
		return ((size(repositories) > 0) && (size(software) > 0));
	}

	/**
	 * @return Whether we have a bundle description for the whole bundle
	 * Build service isn't currently generating one for YMPs for individual packages.
	**/
	global boolean HaveBundleDescription()
	{
		return ((description != "") && (summary != "") && ( name != ""));
	}

	/**
	 * @return Whether we have any recommended repositories or packages
	 * If not we will have to show advanced view.
	**/
	global boolean HaveAnyRecommended()
	{
		boolean rec = false;
		foreach (string name, map<string,string> softwareDetails, software,
		{
			if (
				(softwareDetails["action"]:"install" == "install") && 
				(softwareDetails["recommended"]:"false" == "true")
			)
			rec = true;
			return true;
		});
		foreach (string url, map<string,string> repoDetails, repositories,
		{
			if (
			(repoDetails["recommended"]:"false" == "true")
				)
			{
				rec = true;
				return true;
			}
		});
		return rec;
	}


	/**
	 * Converts our map -> map structure to a list of maps with a "key" element.
	 * This is friendly for yast's XML serialisation support.
	**/
	list<map<string,string> > makeXMLFriendly(map<string,map<string,string> > toFlatten)
	{
		list<map<string,string> > flattened = [];
		foreach(string key,map<string,string> value, toFlatten,
		{
			flattened = add(flattened,add(value,"key",key));
		});
		return flattened;
	}

	/**
	 * Converts back from the above to our original structure
	**/
	map<string,map<string,string> > fromXMLFriendly(list<map<string,string> > toUnFlatten)
	{
		map<string,map<string,string> > unflattened = $[];
		foreach (map<string,string> item, toUnFlatten,
		{
			string key = item["key"]:"nokey";
			unflattened = add(unflattened,key,remove(item,"key"));
		});
		return unflattened;
	}

	/**
	 * Sets up a doctype for YaST's XML serialisation.
	**/
	void SetupXML()
	{
		map doc = $[];
		doc["listEntries"] =
			$[
				"repositories":"repository"
			];
		doc["cdataSections"] = [];
		doc["rootElement"] = "OneClickInstall";
		doc["systemID"] = "/un/defined";
		doc["nameSpace"] = "http://www.suse.com/1.0/yast2ns";
		doc["typeNamespace"] = "http://www.suse.com/1.0/configns";
		XML::xmlCreateDoc(`OneClickInstall,doc);
	}

	/**
	 * Serialises this data structure to XML.
	 * @param filename the file to write the XML to.
	**/
	global void ToXML(string filename)
	{
		SetupXML();
		map<string,any > toSerialise = $[];
		toSerialise = add(toSerialise,"software",makeXMLFriendly(software));
		toSerialise = add(toSerialise,"repositories",makeXMLFriendly(repositories));
		toSerialise = add(toSerialise,"remainSubscribed",remainSubscribed);
		toSerialise = add(toSerialise,"name",name);
		toSerialise = add(toSerialise,"summary",summary);
		toSerialise = add(toSerialise,"description",description);

		boolean success = XML::YCPToXMLFile(`OneClickInstall,toSerialise, filename);
	}

	/**
	 * DeSerialises this data structure from XML.
	 * @param filename the file to read the XML from.
	**/
	global void FromXML(string filename)
	{
		SetupXML();
		map<string,any> deSerialised = (map<string,any >)XML::XMLToYCPFile(filename);
		software = fromXMLFriendly((list<map<string,string> >)deSerialised["software"]:[]);
		repositories = fromXMLFriendly((list<map<string,string> >)deSerialised["repositories"]:[]);
		remainSubscribed = deSerialised["remainSubscribed"]:false;
		summary = deSerialised["summary"]:"";
		description = deSerialised["description"]:"";
		name = deSerialised["name"]:"";
	}
	/** </region> **/
		
}

ACC SHELL 2018