Hello community, here is the log from the commit of package yast2-packager for openSUSE:Factory checked in at 2016-08-18 10:20:21 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/yast2-packager (Old) and /work/SRC/openSUSE:Factory/.yast2-packager.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "yast2-packager" Changes: -------- --- /work/SRC/openSUSE:Factory/yast2-packager/yast2-packager.changes 2016-08-10 19:54:28.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.yast2-packager.new/yast2-packager.changes 2016-08-18 10:20:22.000000000 +0200 @@ -1,0 +2,36 @@ +Tue Aug 16 14:16:01 UTC 2016 - [email protected] + +- Remove the icon from the add-on selection popup (bsc#875201) +- 3.1.114 + +------------------------------------------------------------------- +Tue Aug 16 08:31:23 CEST 2016 - [email protected] + +- Added lazy loading of licenses into AcceptanceNeeded in case of + base product in the initial installation to fix a problem when + explicit acceptance of the product license was always required + (bnc#993285) +- 3.1.113 + +------------------------------------------------------------------- +Mon Aug 15 13:59:58 CEST 2016 - [email protected] + +- Fixed parameter error while logging errors. It belongs to + bnc#991935. +- 3.1.112 + +------------------------------------------------------------------- +Thu Aug 11 12:23:47 UTC 2016 - [email protected] + +- Fix automatic add-on handling when using CD/DVD medias as source + (bsc#991935) +- 3.1.111 + +------------------------------------------------------------------- +Wed Aug 10 16:39:10 UTC 2016 - [email protected] + +- List addons below base product in Software proposal during + installation. (bsc#992304) +- 3.1.110 + +------------------------------------------------------------------- Old: ---- yast2-packager-3.1.109.tar.bz2 New: ---- yast2-packager-3.1.114.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ yast2-packager.spec ++++++ --- /var/tmp/diff_new_pack.0r9TKd/_old 2016-08-18 10:20:23.000000000 +0200 +++ /var/tmp/diff_new_pack.0r9TKd/_new 2016-08-18 10:20:23.000000000 +0200 @@ -17,7 +17,7 @@ Name: yast2-packager -Version: 3.1.109 +Version: 3.1.114 Release: 0 BuildRoot: %{_tmppath}/%{name}-%{version}-build ++++++ yast2-packager-3.1.109.tar.bz2 -> yast2-packager-3.1.114.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-packager-3.1.109/package/yast2-packager.changes new/yast2-packager-3.1.114/package/yast2-packager.changes --- old/yast2-packager-3.1.109/package/yast2-packager.changes 2016-08-09 20:55:13.000000000 +0200 +++ new/yast2-packager-3.1.114/package/yast2-packager.changes 2016-08-16 16:51:47.000000000 +0200 @@ -1,4 +1,40 @@ ------------------------------------------------------------------- +Tue Aug 16 14:16:01 UTC 2016 - [email protected] + +- Remove the icon from the add-on selection popup (bsc#875201) +- 3.1.114 + +------------------------------------------------------------------- +Tue Aug 16 08:31:23 CEST 2016 - [email protected] + +- Added lazy loading of licenses into AcceptanceNeeded in case of + base product in the initial installation to fix a problem when + explicit acceptance of the product license was always required + (bnc#993285) +- 3.1.113 + +------------------------------------------------------------------- +Mon Aug 15 13:59:58 CEST 2016 - [email protected] + +- Fixed parameter error while logging errors. It belongs to + bnc#991935. +- 3.1.112 + +------------------------------------------------------------------- +Thu Aug 11 12:23:47 UTC 2016 - [email protected] + +- Fix automatic add-on handling when using CD/DVD medias as source + (bsc#991935) +- 3.1.111 + +------------------------------------------------------------------- +Wed Aug 10 16:39:10 UTC 2016 - [email protected] + +- List addons below base product in Software proposal during + installation. (bsc#992304) +- 3.1.110 + +------------------------------------------------------------------- Thu Jul 28 10:40:32 UTC 2016 - [email protected] - allow KDE to use packager for opening rpms (boo#954143) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-packager-3.1.109/package/yast2-packager.spec new/yast2-packager-3.1.114/package/yast2-packager.spec --- old/yast2-packager-3.1.109/package/yast2-packager.spec 2016-08-09 20:55:13.000000000 +0200 +++ new/yast2-packager-3.1.114/package/yast2-packager.spec 2016-08-16 16:51:47.000000000 +0200 @@ -17,7 +17,7 @@ Name: yast2-packager -Version: 3.1.109 +Version: 3.1.114 Release: 0 BuildRoot: %{_tmppath}/%{name}-%{version}-build diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-packager-3.1.109/src/modules/AddOnProduct.rb new/yast2-packager-3.1.114/src/modules/AddOnProduct.rb --- old/yast2-packager-3.1.109/src/modules/AddOnProduct.rb 2016-08-09 20:55:14.000000000 +0200 +++ new/yast2-packager-3.1.114/src/modules/AddOnProduct.rb 2016-08-16 16:51:47.000000000 +0200 @@ -1370,11 +1370,8 @@ UI.OpenDialog( VBox( - HBox( - HSquash(MarginBox(0.5, 0.2, Icon.Simple("yast-addon"))), - # TRANSLATORS: popup heading - Left(Heading(Id(:search_heading), _("Additional Products"))) - ), + # TRANSLATORS: popup heading + Left(Heading(Id(:search_heading), _("Additional Products"))), VSpacing(0.5), # TRANSLATORS: additional dialog information Left( @@ -1572,27 +1569,21 @@ new_repo = { "enabled" => true, "base_urls" => [url], "prod_dir" => pth } # BNC #714027: Possibility to adjust repository priority (usually higher) - Ops.set(new_repo, "priority", priority) if Ops.greater_than(priority, -1) + new_repo["priority"] = priority if priority > -1 - Builtins.y2milestone( - "Adding Repository: %1, product path: %2", - URL.HidePassword(url), - pth - ) + log.info "Adding Repository: #{URL.HidePassword(url)}, product path: #{pth}" new_repo_id = Pkg.RepositoryAdd(new_repo) + log.info "New repository id: #{new_repo_id}" - if new_repo_id == nil || Ops.less_than(new_repo_id, 0) - Builtins.y2error("Unable to add product: %1", URL.HidePassword(url)) + if new_repo_id == nil || new_repo_id < 0 + log.error "Unable to add product: #{URL.HidePassword(url)}" # TRANSLATORS: error message, %1 is replaced with product URL - Report.Error( - Builtins.sformat( - _("Unable to add product %1."), - URL.HidePassword(url) - ) - ) + Report.Error(format(_("Unable to add product %s."), URL.HidePassword(url))) return nil end + # Make sure all changes are refreshed + Pkg.SourceSaveAll # download metadata, build repo cache Pkg.SourceRefreshNow(new_repo_id) # load resolvables to zypp pool @@ -1601,6 +1592,12 @@ new_repo_id end + + # Repository network schemes + NETWORK_SCHEMES = ["http", "https", "ftp", "nfs", "cifs", "slp"] + # Repository CD/DVD schemes + CD_SCHEMES = ["cd", "dvd"] + # Auto-integrate add-on products in specified file (usually add_on_products or # add_on_products.xml file) # @@ -1620,6 +1617,11 @@ # <product_item> # <!-- Product name visible in UI when offered to user (optional item) --> # <name>Add-on Name to Display</name> + # <!-- + # Check product's name (optional item). If set to false, <name> won't be checked + # against product's name found in the media (CD/DVD only). + # --> + # <check_name config:type="boolean">true</check_name> # <!-- Product URL (mandatory item) --> # <url>http://product.repository/url/</url> # <!-- Product path, default is "/" (optional item) --> @@ -1667,109 +1669,59 @@ # $[ "file" : "/local/path/to/an/add_on_products/file.xml", "type":"xml" ] # ] def AddPreselectedAddOnProducts(filelist) - filelist = deep_copy(filelist) - if filelist == nil || filelist == [] - Builtins.y2milestone( - "No add-on products defined on the media or by inst-sys" - ) + if filelist.nil? || filelist.empty? + log.info "No add-on products defined on the media or by inst-sys" return true end base_url = GetBaseProductURL() - Builtins.y2milestone("Base URL: %1", URL.HidePassword(base_url)) + log.info "Base URL: #{URL.HidePassword(base_url)}" # Processes all add_on_products files found - Builtins.foreach(filelist) do |add_on_products_file| - filename = Ops.get(add_on_products_file, "file", "") - type = Ops.get(add_on_products_file, "type", "") - add_products = [] - # new xml format - if type == "xml" - add_products = ParseXMLBasedAddOnProductsFile(filename, base_url) - # old fallback - elsif type == "plain" - add_products = ParsePlainAddOnProductsFile(filename, base_url) - else - Builtins.y2error("Unsupported type: %1", type) - next false - end - repo_id = -1 - Builtins.y2milestone("Adding products: %1", add_products) - Builtins.foreach(add_products) do |one_product| - url = Ops.get_string(one_product, "url", "") - pth = Ops.get_string(one_product, "path", "") - priority = Ops.get_integer(one_product, "priority", -1) - prodname = Ops.get_string(one_product, "name", "") + filelist.each do |file| + add_products = parse_add_on_products_file( + file.fetch("file", ""), file.fetch("type", ""), base_url + ) + next unless add_products + + log.info "Adding products: #{add_products}" + add_products.each do |one_product| + url = one_product.fetch("url", "") + pth = one_product.fetch("path", "") + priority = one_product.fetch("priority", -1).to_i + prodname = one_product.fetch("name", "") + check_name = one_product.fetch("check_name", true) # Check URL and setup network if required or prompt to insert CD/DVD parsed = URL.Parse(url) - scheme = Builtins.tolower(Ops.get_string(parsed, "scheme", "")) + scheme = parsed.fetch("scheme", "").downcase # check if network needs to be configured - if Builtins.contains( - ["http", "https", "ftp", "nfs", "cifs", "slp"], - scheme - ) + if NETWORK_SCHEMES.include?(scheme) inc_ret = Convert.to_symbol( WFM.CallFunction("inst_network_check", []) ) Builtins.y2milestone("inst_network_check ret: %1", inc_ret) end + # a CD/DVD repository - if Builtins.contains(["cd", "dvd"], scheme) - # if the CD/DVD product is known just try if it's there - # and ask if not - if prodname != "" - found = false - - while !found - repo_id = AddRepo(url, pth, priority) - next false if repo_id == nil - - prod2 = Pkg.SourceProductData(repo_id) - if Ops.get_string(prod2, "label", "") == prodname - found = true - else - Builtins.y2milestone( - "Removing repo %1: Add-on found: %2, expected: %3", - repo_id, - Ops.get_string(prod2, "label", ""), - prodname - ) - Pkg.SourceDelete(repo_id) - - # ask for a different medium - url = AskForCD(url, prodname) - next false if url == nil - end - end + repo_id = + if CD_SCHEMES.include?(scheme) + add_product_from_cd(url, pth, priority, prodname, check_name) else - result = AskForCD(url, prodname) - next false if result == nil - - repo_id = AddRepo(result, pth, priority) - next false if repo_id == nil + # a non CD/DVD repository + AddRepo(url, pth, priority) end - else - # a non CD/DVD repository - repo_id = AddRepo(url, pth, priority) - next false if repo_id == nil - end + next false unless repo_id + if !AcceptedLicenseAndInfoFile(repo_id) - Builtins.y2warning("License not accepted, delete the repository") + log.warn "License not accepted, delete the repository" Pkg.SourceDelete(repo_id) next false end Integrate(repo_id) # adding the product to the list of products (BNC #269625) prod = Pkg.SourceProductData(repo_id) - Builtins.y2milestone( - "Repository (%1) product data: %2", - repo_id, - prod - ) - InstallProductsFromRepository( - Ops.get_list(one_product, "install_products", []), - repo_id - ) + log.info "Repository (#{repo_id} product data: #{prod})" + InstallProductsFromRepository(one_product.fetch("install_products", []), repo_id) new_add_on_product = { "media" => repo_id, "product" => Ops.get_locale( @@ -1789,9 +1741,7 @@ "media_url" => url, "product_dir" => pth } - if Ops.greater_than(priority, -1) - Ops.set(new_add_on_product, "priority", priority) - end + new_add_on_product["priority"] = priority if priority > -1 @add_on_products = Builtins.add(@add_on_products, new_add_on_product) end end @@ -2256,6 +2206,63 @@ publish :function => :ImportGpgKeyCallback, :type => "boolean (map <string, any>, integer)" publish :function => :AcceptNonTrustedGpgKeyCallback, :type => "boolean (map <string, any>)" publish :function => :SetSignatureCallbacks, :type => "void (string)" + + private + + # Adds a product from a CD/DVD + # + # To add the product, the name should match +prodname+ argument. + # + # @param url [String] Repository URL (cd: or dvd: schemas are expected) + # @param pth [String] Repository path (in the media) + # @param priority [Integer] Repository priority + # @param prodname [String] Expected product's name + # @param check_name [Boolean] Check product's name + # @return [Integer,nil] Repository id; nil if product was not found and user cancelled. + # + # @see add_repo_from_cd + def add_product_from_cd(url, pth, priority, prodname, check_name) + current_url = url + loop do + # just try if it's there and ask if not + repo_id = AddRepo(current_url, pth, priority) + if repo_id + return repo_id if !check_name || prodname.empty? + found_product = Pkg.SourceProductData(repo_id) + return repo_id if found_product["label"] == prodname + log.info("Removing repo #{repo_id}: Add-on found #{found_product["label"]}, expected: #{prodname}") + Pkg.SourceDelete(repo_id) + end + + # ask for a different medium + current_url = AskForCD(current_url, prodname) + return nil if current_url.nil? + end + end + + # Parse a add-on products file + # + # @param filename [String] File path + # @param type [String] File type ("xml" or "plain") + # @param base_url [String] Product's base URL + # @return [Hash] Add-on specification (allowed keys + # are "name", "url", "path", "install_products", + # "check_name", "ask_user", "selected" and "priority"). + # + # @see ParseXMLBasedAddOnProductsFile + # @see ParsePlainAddOnProductsFile + # @see AddPreselectedAddOnProducts + def parse_add_on_products_file(filename, type, base_url) + case type.downcase + when "xml" + ParseXMLBasedAddOnProductsFile(filename, base_url) + when "plain" + ParsePlainAddOnProductsFile(filename, base_url) + else + log.error "Unsupported type: #{type}" + false + end + end end AddOnProduct = AddOnProductClass.new diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-packager-3.1.109/src/modules/Packages.rb new/yast2-packager-3.1.114/src/modules/Packages.rb --- old/yast2-packager-3.1.109/src/modules/Packages.rb 2016-08-09 20:55:14.000000000 +0200 +++ new/yast2-packager-3.1.114/src/modules/Packages.rb 2016-08-16 16:51:47.000000000 +0200 @@ -16,6 +16,10 @@ # All known types of resolvables RESOLVABLE_TYPES = [:product, :patch, :package, :pattern, :language] + + # Key to sort by resolvable selection + RESOLVABLE_SORT_ORDER = { :product => "source", :pattern => "order" } + # Minimum set of packages tags required to enable VNC server VNC_BASE_TAGS = ["xorg-x11", "xorg-x11-Xvnc", "xorg-x11-fonts", "xinetd"] # Additional packages tags needed to run second stage in graphical mode @@ -157,40 +161,15 @@ # @param [String] format string format string to print summaries in # @return a list of selected resolvables def ListSelected(what, format) - format = "%1" if format == "" || format == nil selected = Pkg.ResolvableProperties("", what, "") - # ignore hidden patterns - if what == :pattern - selected = Builtins.filter(selected) do |r| - Ops.get(r, "user_visible") == true - end + selected.select! {|r| r["status"] == :selected } - # order patterns according to "order" flag - selected = Builtins.sort(selected) do |x, y| - xo = Builtins.tointeger(Ops.get_string(x, "order", "")) - yo = Builtins.tointeger(Ops.get_string(y, "order", "")) - if xo == nil || yo == nil - # order is not an integer, compare as strings - next Ops.less_than( - Ops.get_string(x, "order", ""), - Ops.get_string(y, "order", "") - ) - else - next Ops.less_than(xo, yo) - end - end - end + selected.select! {|r| r["user_visible"] } if what == :pattern - selected = Builtins.filter(selected) do |r| - Ops.get(r, "status") == :selected - end + sort_resolvable!(selected, what) - ret = Builtins.maplist(selected) do |r| - disp = Ops.get_string(r, "summary", Ops.get_string(r, "name", "")) - Builtins.sformat(format, disp) - end - deep_copy(ret) + formatted_resolvables(selected, format) end # Count the total size of packages to be installed @@ -2599,6 +2578,33 @@ end end + # Prepares a list of formatted selected resolvables + # + # @param [Array<Hash>] list of selected resolvables to format + # @param [String] string format to use + def formatted_resolvables(selected, format) + format = "%1" if format == "" || format == nil + + Builtins.maplist(selected) do |r| + disp = Ops.get_string(r, "summary", Ops.get_string(r, "name", "")) + Builtins.sformat(format, disp) + end + end + + # Sort selected resolvables of specified type + # + # :pattern resolvables are sorted by "order" + # :product resolvables are sorted by "source" + # + # @param [Array<Hash>] list of selected resolvables to sort + # @param [Symbol] what symbol specifying the type of resolvables to select + # @see RESOLVABLE_SORT_ORDER + def sort_resolvable!(selected, what) + order = RESOLVABLE_SORT_ORDER[what] + + selected.sort_by! { |r| r[order].to_i } if order + end + # Computes all patterns that are expected to be selected for default installation def patterns_to_install patterns = ComputeSystemPatternList().dup diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-packager-3.1.109/src/modules/ProductLicense.rb new/yast2-packager-3.1.114/src/modules/ProductLicense.rb --- old/yast2-packager-3.1.109/src/modules/ProductLicense.rb 2016-08-09 20:55:14.000000000 +0200 +++ new/yast2-packager-3.1.114/src/modules/ProductLicense.rb 2016-08-16 16:51:47.000000000 +0200 @@ -52,6 +52,11 @@ ] # no more wildcard patterns here, UI can display only html and txt anyway + initialize_default_values + end + + # (Re)Initializes all internal caches + def initialize_default_values # All licenses have their own unique ID @license_ids = [] @@ -302,14 +307,56 @@ ) end + # Returns source ID of the base product - initial installation only! + # If no sources are found, returns 0. + # FIXME: Connected to bsc#993285, refactoring needed + # + # return [Integer] base_product_id or 0 + def base_product_id + raise "Base product can be only found in installation" unless Stage.initial + + # The first product in the list of known products + # 0 is the backward-compatible default value, first installation repo always + # gets this ID later + current_sources = Pkg.SourceGetCurrent(true) + current_sources.any? ? current_sources.first : 0 + end + # Returns whether accepting the license manually is requied. # # @see BNC #448598 + # @param [Any] unique ID # @return [Boolean] if required def AcceptanceNeeded(id) - Ops.get(@license_acceptance_needed, id, true) + # FIXME: lazy loading of the info about licenses, bigger refactoring needed + # @see bsc#993285 + # + # In the initial installation, for base product, acceptance_needed needs + # to be known before showing the license dialog (inst_complex_welcome). + # Loading the info is handled internally in other cases. + # + # id can be a string (currently is) when called from inst_complex_welcome + if !@license_acceptance_needed.key?(id) && + Stage.initial && + id.to_s == base_product_id.to_s + # Although we know the base product ID, the function below expects + # id to be nil for base product in inital installation + GetSourceLicenseDirectory(nil, "/") + cache_license_acceptance_needed(id, @license_dir) + end + + if @license_acceptance_needed.key?(id) + @license_acceptance_needed[id] + else + log.warn "SetAcceptanceNeeded(#{id}) should be called first, using default 'true'" + true + end end + # Sets whether explicit acceptance of a license is needed + # + # @param [Any] unique ID (often a source ID) + # @param [Boolean] new_value if needed def SetAcceptanceNeeded(id, new_value) if new_value == nil Builtins.y2error( @@ -320,15 +367,12 @@ return end - Ops.set(@license_acceptance_needed, id, new_value) + @license_acceptance_needed[id] = new_value if new_value == true - Builtins.y2milestone("License agreement (ID %1) WILL be required", id) + log.info "License agreement (ID #{id}) WILL be required" else - Builtins.y2milestone( - "License agreement (ID %1) will NOT be required", - id - ) + log.info "License agreement (ID #{id}) will NOT be required" end nil @@ -751,12 +795,14 @@ # Bugzilla #299732 # Base Product - LiveCD installation if Mode.live_installation + log.info "LiveCD Installation" SearchForLicense_LiveCDInstallation(src_id, fallback_dir) # Base-product - license not in installation # * Stage is not initial # * source ID is not defined elsif !Stage.initial && src_id == nil + log.info "Base product, not in initial stage" SearchForLicense_NormalRunBaseProduct(src_id, fallback_dir) # Base-product - first-stage installation @@ -764,14 +810,13 @@ # * Source ID is not set # bugzilla #298342 elsif Stage.initial && src_id == nil - SearchForLicense_FirstStageBaseProduct( - src_id == nil ? Ops.get(Pkg.SourceGetCurrent(true), 0, 0) : src_id, - fallback_dir - ) + log.info "Base product, initial stage" + SearchForLicense_FirstStageBaseProduct(base_product_id, fallback_dir) # Add-on-product license # * Source ID is set elsif src_id != nil && Ops.greater_than(src_id, -1) + log.info "Add-On product" SearchForLicense_AddOnProduct(src_id, fallback_dir) # Fallback @@ -793,20 +838,21 @@ nil end + # Finds out whether user needs to 'Agree to the license coming from a given source_id' + # + # @param [Any] unique ID + # @param [String] path to directory with unpacked licenses (mandatory) + def cache_license_acceptance_needed(id, license_dir) + raise "Parameter 'license_dir' must not be nil" if license_dir.nil? + + license_acceptance_needed = !FileUtils.Exists("#{license_dir}/no-acceptance-needed") + SetAcceptanceNeeded(id, license_acceptance_needed) + end def InitLicenseData(src_id, dir, licenses, available_langs, require_agreement, license_ident, id) + # Downloads and unpacks all licenses for a given source ID GetSourceLicenseDirectory(src_id, dir) - - # License does not need to be accepted. Well, I mean, manually selected "Yes, of course, I agree..." - if FileUtils.Exists( - Builtins.sformat("%1/no-acceptance-needed", @license_dir) - ) - if id == nil - Builtins.y2error("Parameter id not set") - else - SetAcceptanceNeeded(id, false) - end - end + cache_license_acceptance_needed(id, @license_dir) licenses.value = LicenseFiles(@license_dir, @license_patterns) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-packager-3.1.109/test/addon_product_test.rb new/yast2-packager-3.1.114/test/addon_product_test.rb --- old/yast2-packager-3.1.109/test/addon_product_test.rb 2016-08-09 20:55:14.000000000 +0200 +++ new/yast2-packager-3.1.114/test/addon_product_test.rb 2016-08-16 16:51:47.000000000 +0200 @@ -5,6 +5,8 @@ Yast.import "AddOnProduct" describe Yast::AddOnProduct do + subject { Yast::AddOnProduct } + describe "#renamed?" do it "returns true if product has been renamed" do expect(Yast::AddOnProduct.renamed?("SUSE_SLES", "SLES")).to eq(true) @@ -87,4 +89,197 @@ end end end + + describe "#AddPreselectedAddOnProducts" do + BASE_URL = "cd:/?devices=/dev/disk/by-id/ata-QEMU_DVD-ROM_QM00001".freeze + ADDON_REPO = { + "path" => "/foo", "priority" => 50, "url" => "cd:/?alias=Foo" + }.freeze + + let(:repo) { ADDON_REPO } + let(:filelist) do + [{ "file" => "/add_on_products.xml", "type" => "xml" }] + end + + before do + subject.SetBaseProductURL(BASE_URL) + allow(subject).to receive(:ParseXMLBasedAddOnProductsFile).and_return([repo]) + subject.add_on_products = [] + end + + context "when filelist is empty" do + let(:filelist) { [] } + + it "just returns true" do + expect(subject).to_not receive(:GetBaseProductURL) + subject.AddPreselectedAddOnProducts(filelist) + end + end + + context "when filelist is nil" do + let(:filelist) { nil } + + it "just returns true" do + expect(subject).to_not receive(:GetBaseProductURL) + subject.AddPreselectedAddOnProducts(filelist) + end + end + + context "when filelist contains XML files" do + it "parses the XML file" do + expect(subject).to receive(:ParseXMLBasedAddOnProductsFile).and_return([]) + subject.AddPreselectedAddOnProducts(filelist) + end + end + + context "when filelist contains plain-text files" do + let(:filelist) do + [{ "file" => "/add_on_products.xml", "type" => "plain" }] + end + + it "parses the plain file" do + expect(subject).to receive(:ParsePlainAddOnProductsFile).and_return([]) + subject.AddPreselectedAddOnProducts(filelist) + end + end + + context "when filelist contains unsupported file types" do + let(:filelist) do + [{ "file" => "/add_on_products.xml", "type" => "unsupported" }] + end + + it "logs the error" do + expect(subject.log).to receive(:error).with(/Unsupported/) + subject.AddPreselectedAddOnProducts(filelist) + end + end + + context "when the add-on is on a CD/DVD" do + let(:repo_id) { 1 } + let(:cd_url) { "cd:///?device=/dev/sr0" } + + before do + allow(subject).to receive(:AcceptedLicenseAndInfoFile).and_return(true) + allow(Yast::Pkg). to receive(:SourceProductData).with(repo_id) + allow(subject).to receive(:InstallProductsFromRepository) + allow(subject).to receive(:ReIntegrateFromScratch) + allow(subject).to receive(:Integrate) + end + + context "and no product name was given" do + let(:repo) { ADDON_REPO } + + it "adds the repository" do + expect(subject).to receive(:AddRepo).with(repo["url"], repo["path"], repo["priority"]) + .and_return(repo_id) + subject.AddPreselectedAddOnProducts(filelist) + expect(subject.add_on_products).to_not be_empty + end + + it "asks for the CD/DVD if the repo could not be added" do + allow(subject).to receive(:AddRepo).with(repo["url"], repo["path"], repo["priority"]) + .and_return(nil) + expect(subject).to receive(:AskForCD).and_return(cd_url) + expect(subject).to receive(:AddRepo).with(cd_url, repo["path"], repo["priority"]) + .and_return(repo_id) + subject.AddPreselectedAddOnProducts(filelist) + expect(subject.add_on_products).to_not be_empty + end + + it "does not add the repository if user cancels the dialog" do + allow(subject).to receive(:AddRepo).with(repo["url"], repo["path"], repo["priority"]) + .and_return(nil) + allow(subject).to receive(:AskForCD).and_return(nil) + + subject.AddPreselectedAddOnProducts(filelist) + expect(subject.add_on_products).to be_empty + end + end + + context "and a network scheme is used" do + let(:repo) { ADDON_REPO.merge("url" => "http://example.net/repo") } + + it "checks whether the network is working" do + allow(subject).to receive(:AddRepo).and_return(nil) + expect(Yast::WFM).to receive(:CallFunction).with("inst_network_check", []) + subject.AddPreselectedAddOnProducts(filelist) + end + end + + context "and a product name was given" do + let(:repo) { ADDON_REPO.merge("name" => "Foo") } + let(:matching_product) { { "label" => repo["name"] } } + let(:other_product) { { "label" => "other" } } + let(:other_repo_id) { 2 } + + context "and the product is found in the CD/DVD" do + before do + allow(Yast::Pkg).to receive(:SourceProductData).with(repo_id) + .and_return(matching_product) + end + + it "adds the product without asking" do + expect(subject).to_not receive(:AskForCD) + expect(subject).to receive(:AddRepo).with(repo["url"], anything, anything) + .and_return(repo_id) + subject.AddPreselectedAddOnProducts(filelist) + end + end + + context "and the product is not found in the CD/DVD" do + before do + allow(Yast::Pkg).to receive(:SourceProductData).with(repo_id) + .and_return(matching_product) + allow(Yast::Pkg).to receive(:SourceProductData).with(other_repo_id) + .and_return(other_product) + end + + it "does not add the repository if the user cancels the dialog" do + allow(subject).to receive(:AddRepo).with(repo["url"], anything, anything) + .and_return(other_repo_id) + allow(subject).to receive(:AskForCD).and_return(nil) + + expect(Yast::Pkg).to receive(:SourceDelete).with(other_repo_id) + expect(subject).to_not receive(:Integrate).with(other_repo_id) + subject.AddPreselectedAddOnProducts(filelist) + expect(subject.add_on_products).to be_empty + end + + it "adds the product if the user points to a valid CD/DVD" do + allow(subject).to receive(:AddRepo).with(repo["url"], repo["path"], repo["priority"]) + .and_return(other_repo_id) + allow(subject).to receive(:AskForCD).and_return(cd_url) + allow(subject).to receive(:AddRepo).with(cd_url, repo["path"], repo["priority"]) + .and_return(repo_id) + + expect(Yast::Pkg).to receive(:SourceDelete).with(other_repo_id) + expect(Yast::Pkg).to_not receive(:SourceDelete).with(repo_id) + expect(subject).to receive(:Integrate).with(repo_id) + subject.AddPreselectedAddOnProducts(filelist) + expect(subject.add_on_products).to_not be_empty + end + + context "and check_name option is disabled" do + let(:repo) { ADDON_REPO.merge("check_name" => true) } + it "adds the repository" do + allow(subject).to receive(:AddRepo).with(repo["url"], repo["path"], repo["priority"]) + .and_return(other_repo_id) + + subject.AddPreselectedAddOnProducts(filelist) + expect(subject.add_on_products).to_not be_empty + end + end + end + end + + it "removes the product is the license is not accepted" do + allow(subject).to receive(:AddRepo).with(repo["url"], repo["path"], repo["priority"]) + .and_return(repo_id) + expect(subject).to receive(:AcceptedLicenseAndInfoFile).and_return(false) + expect(Yast::Pkg).to receive(:SourceDelete).with(repo_id) + subject.AddPreselectedAddOnProducts(filelist) + expect(subject.add_on_products).to be_empty + end + end + end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-packager-3.1.109/test/packages_test.rb new/yast2-packager-3.1.114/test/packages_test.rb --- old/yast2-packager-3.1.109/test/packages_test.rb 2016-08-09 20:55:14.000000000 +0200 +++ new/yast2-packager-3.1.114/test/packages_test.rb 2016-08-16 16:51:47.000000000 +0200 @@ -897,4 +897,92 @@ Yast::Packages.Reset([:product]) end end + + describe "#ListSelected" do + let(:unordered_products) do + [ + product("name" => "p3", "status" => :selected, "source" => 15), + product("name" => "p4", "status" => :available, "source" => 40), + product("name" => "p1", "status" => :selected, "source" => 10) + ] + end + + let(:filtered_products) do + [ + product("name" => "p3", "status" => :selected, "source" => 15), + product("name" => "p1", "status" => :selected, "source" => 10) + ] + end + + let(:ordered_products) do + [ + product("name" => "p1", "status" => :selected, "source" => 10), + product("name" => "p3", "status" => :selected, "source" => 15) + ] + end + + let(:unordered_patterns) do + [ + pattern("name" => "p3", "status" => :selected, "order" => "3", "user_visible" => true), + pattern("name" => "p1", "status" => :selected, "order" => "1", "user_visible" => false), + pattern("name" => "p2", "status" => :available, "order" => "2", "user_visible" => true) + ] + end + + let(:filtered_patterns) do + [ + pattern("name" => "p3", "status" => :selected, "order" => "3", "user_visible" => true) + ] + end + + before do + allow(Yast::Pkg).to receive(:ResolvableProperties).with("", :product, "") + .and_return(unordered_products) + end + + it "obtains a list of resolvables of the given type" do + expect(Yast::Pkg).to receive(:ResolvableProperties).with("", :product, "") + + subject.ListSelected(:product, "") + end + + it "filters not selected resolvables from the list" do + expect(subject).to receive(:sort_resolvable!) + .with(filtered_products, :product) + + subject.ListSelected(:product, "") + end + + it "filters not user visible resolvables from the list for type pattern" do + expect(Yast::Pkg).to receive(:ResolvableProperties).with("", :pattern, "") + .and_return(unordered_patterns) + expect(subject).to receive(:sort_resolvable!) + .with(filtered_patterns, :pattern) + + subject.ListSelected(:pattern, "") + end + + it "sorts resultant list depending on resolvable type" do + expect(subject).to receive(:formatted_resolvables).with(ordered_products, "") + + subject.ListSelected(:product, "") + end + + it "returns an empty list if no resolvables selected" do + allow(Yast::Pkg).to receive(:ResolvableProperties).with("", :product, "") + .and_return([]) + + expect(subject.ListSelected(:product, "Product: %1")).to eql([]) + end + + it "returns a list with each resultant resolvable formatted as the format given" do + expect(subject.ListSelected(:product, "Product: %1")).to eql( + [ + "Product: p1", + "Product: p3" + ] + ) + end + end + end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-packager-3.1.109/test/product_license_test.rb new/yast2-packager-3.1.114/test/product_license_test.rb --- old/yast2-packager-3.1.109/test/product_license_test.rb 2016-08-09 20:55:14.000000000 +0200 +++ new/yast2-packager-3.1.114/test/product_license_test.rb 2016-08-16 16:51:47.000000000 +0200 @@ -147,4 +147,101 @@ end end + + describe "#AcceptanceNeeded" do + let(:base_product_id) { 0 } + let(:add_on_product_id) { 1 } + + before do + # Downloading and unpacking licenses is expensive, so we cache all values + # and thus we need to reinit all caches for testing with different values + Yast::ProductLicense.initialize_default_values + + allow(Yast::ProductLicense).to receive(:base_product_id).and_return(base_product_id) + end + + context "when called in the initial stage of installation" do + before do + # Initial installation + allow(Yast::Stage).to receive(:initial).and_return(true) + allow(Yast::Mode).to receive(:installation).and_return(true) + + # Tarball with licenses exists + allow(Yast::FileUtils).to receive(:Exists).with(/license.tar.gz/).and_return(true) + # Info file exists + allow(Yast::FileUtils).to receive(:Exists).with(/info.txt/).and_return(true) + end + + context "when called for base-product" do + before do + expect(Yast::ProductLicense).to receive(:GetSourceLicenseDirectory).and_call_original + expect(Yast::ProductLicense).to receive(:SetAcceptanceNeeded).and_call_original + expect(Yast::ProductLicense).to receive(:UnpackLicenseTgzFileToDirectory).and_return(true) + end + + it "returns that acceptance is needed if no-acceptance-needed file is not found" do + expect(Yast::FileUtils).to receive(:Exists).with(/no-acceptance-needed/).and_return(false) + expect(Yast::ProductLicense.AcceptanceNeeded(base_product_id)).to eq(true) + end + + it "returns that acceptance is not needed if the no-acceptance-needed file is found" do + expect(Yast::FileUtils).to receive(:Exists).with(/no-acceptance-needed/).and_return(true) + expect(Yast::ProductLicense.AcceptanceNeeded(base_product_id)).to eq(false) + end + end + + context "when called for add-on product" do + context "when value has not been stored yet" do + it "returns the safe default true" do + expect(Yast::ProductLicense.AcceptanceNeeded(add_on_product_id)).to eq(true) + end + end + + context "when value has been already stored" do + it "returns the stored value" do + Yast::ProductLicense.SetAcceptanceNeeded(add_on_product_id, false) + expect(Yast::ProductLicense.AcceptanceNeeded(add_on_product_id)).to eq(false) + end + end + end + end + + context "when not called in initial installation" do + before do + allow(Yast::Stage).to receive(:initial).and_return(false) + allow(Yast::Mode).to receive(:installation).and_return(false) + end + + context "when called for base-product" do + context "returns the safe default true" do + it "throws an error" do + expect(Yast::ProductLicense.AcceptanceNeeded(base_product_id)).to eq(true) + end + end + + context "when value has been already stored" do + it "returns the stored value" do + Yast::ProductLicense.SetAcceptanceNeeded(base_product_id, false) + expect(Yast::ProductLicense.AcceptanceNeeded(base_product_id)).to eq(false) + end + end + end + + context "when called for add-on product" do + context "when value has not been stored yet" do + it "returns the safe default true" do + expect(Yast::ProductLicense.AcceptanceNeeded(add_on_product_id)).to eq(true) + end + end + + context "when value has been already stored" do + it "returns the stored value" do + Yast::ProductLicense.SetAcceptanceNeeded(add_on_product_id, true) + expect(Yast::ProductLicense.AcceptanceNeeded(add_on_product_id)).to eq(true) + end + end + end + end + end + end
