Hello community, here is the log from the commit of package yast2 for openSUSE:Factory checked in at 2016-12-03 18:24:12 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/yast2 (Old) and /work/SRC/openSUSE:Factory/.yast2.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "yast2" Changes: -------- --- /work/SRC/openSUSE:Factory/yast2/yast2.changes 2016-11-25 12:05:12.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.yast2.new/yast2.changes 2016-12-03 18:24:13.000000000 +0100 @@ -1,0 +2,7 @@ +Wed Nov 30 09:18:23 UTC 2016 - [email protected] + +- Enhanced PackagesProposal API to handle required and optional + resolvables separately (bsc#885496) +- 3.2.7 + +------------------------------------------------------------------- Old: ---- yast2-3.2.6.tar.bz2 New: ---- yast2-3.2.7.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ yast2.spec ++++++ --- /var/tmp/diff_new_pack.rXOUwA/_old 2016-12-03 18:24:14.000000000 +0100 +++ /var/tmp/diff_new_pack.rXOUwA/_new 2016-12-03 18:24:14.000000000 +0100 @@ -17,7 +17,7 @@ Name: yast2 -Version: 3.2.6 +Version: 3.2.7 Release: 0 Summary: YaST2 - Main Package License: GPL-2.0 ++++++ yast2-3.2.6.tar.bz2 -> yast2-3.2.7.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-3.2.6/library/general/src/modules/PackagesProposal.rb new/yast2-3.2.7/library/general/src/modules/PackagesProposal.rb --- old/yast2-3.2.6/library/general/src/modules/PackagesProposal.rb 2016-11-23 17:54:27.000000000 +0100 +++ new/yast2-3.2.7/library/general/src/modules/PackagesProposal.rb 2016-11-30 17:32:04.000000000 +0100 @@ -3,6 +3,7 @@ # *************************************************************************** # # Copyright (c) 2002 - 2012 Novell, Inc. +# Copyright (c) 2016 SUSE LLC # All Rights Reserved. # # This program is free software; you can redistribute it and/or @@ -21,16 +22,17 @@ # you may find current contact information at www.novell.com # # *************************************************************************** -# File: PackagesProposal.ycp -# Package: Packages installation -# Summary: API for selecting or de-selecting packages for installation -# Authors: Lukas Ocilka <[email protected]> -# -# $Id$ + require "yast" module Yast + # API for selecting or de-selecting packages or patterns for installation. + # It stores two separate lists, one for required resolvables and the other one + # for optional resolvables. The optional resolvables can be deselected by user + # manually and the installation proposal will not complain that they are missing. class PackagesProposalClass < Module + include Yast::Logger + def main textdomain "base" @@ -44,20 +46,19 @@ # ] # ] @resolvables_to_install = {} + # the same as above but the resolvables are considered optional + @opt_resolvables_to_install = {} # List of currently supported types of resolvables @supported_resolvables = [:package, :pattern] end - # Resets all resolvables to install. Use carefully. + # Resets all resolvables to install (both required and optional). Use carefully. def ResetAll - if @resolvables_to_install != {} - Builtins.y2warning("Reseting all PackagesProposal items") - else - Builtins.y2milestone("Reseting all PackagesProposal items") - end + log.info("Resetting all PackagesProposal items") - @resolvables_to_install = {} + @resolvables_to_install.clear + @opt_resolvables_to_install.clear nil end @@ -68,42 +69,13 @@ # # @return [Array<Symbol>] of resolvables def GetSupportedResolvables - deep_copy(@supported_resolvables) + @supported_resolvables end def IsSupportedResolvableType(type) - if type.nil? - Builtins.y2error("Wrong type: %1", type) - return false - end + log.warn("Type cannot be nil") if type.nil? - Builtins.contains(@supported_resolvables, type) - end - - # Checks the currently created data structure and creates - # missing keys if needed. - # - # @param [String] unique_ID - # @param [Symbol] type - def CreateEmptyStructureIfMissing(unique_ID, type) - if !Builtins.haskey(@resolvables_to_install, unique_ID) - Builtins.y2debug( - "Creating '%1' key in resolvables_to_install", - unique_ID - ) - Ops.set(@resolvables_to_install, unique_ID, {}) - end - - if !Builtins.haskey(Ops.get(@resolvables_to_install, unique_ID, {}), type) - Builtins.y2debug( - "Creating '%1' key in resolvables_to_install[%2]", - type, - unique_ID - ) - Ops.set(@resolvables_to_install, [unique_ID, type], []) - end - - nil + @supported_resolvables.include?(type) end # Checks parameters for global functions @@ -113,16 +85,12 @@ # @return [Boolean] if parameters are correct def CheckParams(unique_ID, type) if unique_ID.nil? || unique_ID == "" - Builtins.y2error("Unique ID cannot be: %1", unique_ID) + log.error("Unique ID cannot be: #{unique_ID.inspect}") return false end if !IsSupportedResolvableType(type) - Builtins.y2error( - "Not a supported type: %1, supported are only: %2", - type, - @supported_resolvables - ) + log.error("Not a supported type: #{type}") return false end @@ -135,6 +103,8 @@ # @param [String] unique_ID # @param symbol resolvable type # @param list <string> of resolvables to add for installation + # @param [Boolean] optional True for optional list, false (the default) for + # the required list # @return [Boolean] whether successful # # @example @@ -144,35 +114,19 @@ # # @see #supported_resolvables # @see #RemoveResolvables() - def AddResolvables(unique_ID, type, resolvables) + def AddResolvables(unique_ID, type, resolvables, optional: false) resolvables = deep_copy(resolvables) return false if !CheckParams(unique_ID, type) - CreateEmptyStructureIfMissing(unique_ID, type) - if resolvables.nil? - Builtins.y2warning("Changing resolvables %1 to empty list", resolvables) + log.info("Using empty list instead of nil") resolvables = [] end - Builtins.y2milestone( - "Adding resolvables %1 type %2 for %3", - resolvables, - type, - unique_ID - ) - Ops.set( - @resolvables_to_install, - [unique_ID, type], - Convert.convert( - Builtins.union( - Ops.get(@resolvables_to_install, [unique_ID, type], []), - resolvables - ), - from: "list", - to: "list <string>" - ) - ) + log.info("Adding #{log_label(optional)} #{resolvables} of type #{type} for #{unique_ID}") + + current_resolvables = data_for(unique_ID, type, optional: optional) + current_resolvables.concat(resolvables) true end @@ -181,28 +135,25 @@ # but it replaces the list of resolvables instead of adding them to the pool. # It always replaces only the part that is identified by the unique_ID. # - # @param [String] unique_ID - # @param symbol resolvable type - # @param list <string> of resolvables to add for installation + # @param [String] unique_ID the unique identificator + # @param [Symbol] type resolvable type + # @param [Array<String>] resolvables list of resolvables to add for installation + # @param [Boolean] optional True for optional list, false (the default) for + # the required list # @return [Boolean] whether successful - def SetResolvables(unique_ID, type, resolvables) + def SetResolvables(unique_ID, type, resolvables, optional: false) resolvables = deep_copy(resolvables) return false if !CheckParams(unique_ID, type) - CreateEmptyStructureIfMissing(unique_ID, type) - if resolvables.nil? - Builtins.y2warning("Changing resolvables %1 to empty list", resolvables) + log.warn("Using empty list instead of nil") resolvables = [] end - Builtins.y2milestone( - "Adjusting resolvables %1 type %2 for %3", - resolvables, - type, - unique_ID - ) - Ops.set(@resolvables_to_install, [unique_ID, type], resolvables) + log.info("Setting #{log_label(optional)} #{resolvables} of type #{type} for #{unique_ID}") + + current_resolvables = data_for(unique_ID, type, optional: optional) + current_resolvables.replace(resolvables) true end @@ -210,9 +161,11 @@ # Removes list of packages from pool that is then used by software proposal # to propose a selection of resolvables to install. # - # @param [String] unique_ID - # @param symbol resolvable type - # @param list <string> of resolvables to remove from list selected for installation + # @param [String] unique_ID the unique identificator + # @param [Symbol] type resolvable type + # @param [Array<String>] resolvables list of resolvables to add for installation + # @param [Boolean] optional True for optional list, false (the default) for + # the required list # @return [Boolean] whether successful # # @example @@ -220,55 +173,47 @@ # # @see #supported_resolvables # @see #AddResolvables() - def RemoveResolvables(unique_ID, type, resolvables) + def RemoveResolvables(unique_ID, type, resolvables, optional: false) resolvables = deep_copy(resolvables) return false if !CheckParams(unique_ID, type) - CreateEmptyStructureIfMissing(unique_ID, type) - if resolvables.nil? - Builtins.y2warning("Changing resolvables %1 to empty list", resolvables) + log.warn("Using empty list instead of nil") resolvables = [] end - Builtins.y2milestone( - "Removing resolvables %1 type %2 for %3", - resolvables, - type, - unique_ID - ) - Ops.set( - @resolvables_to_install, - [unique_ID, type], - Builtins.filter(Ops.get(@resolvables_to_install, [unique_ID, type], [])) do |one_resolvable| - !Builtins.contains(resolvables, one_resolvable) - end - ) - Builtins.y2milestone( - "Resolvables left: %1", - Ops.get(@resolvables_to_install, [unique_ID, type], []) - ) + log.info("Removing #{log_label(optional)} #{resolvables} type #{type} for #{unique_ID}") + + current_resolvables = data_for(unique_ID, type, optional: optional) + current_resolvables.reject! { |r| resolvables.include?(r) } + + log.info("#{log_label(optional)} left: #{current_resolvables.inspect}") true end # Returns all resolvables selected for installation. # - # @param [String] unique_ID - # @param symbol resolvable type + # @param [String] unique_ID the unique identificator + # @param [Symbol] type resolvable type + # @param [Boolean] optional True for optional list, false (the default) for + # the required list + # @return [Array<String>] of resolvables # # @example # GetResolvables ("y2_kdump", `package) -> ["yast2-kdump", "kdump"] - def GetResolvables(unique_ID, type) + def GetResolvables(unique_ID, type, optional: false) return nil if !CheckParams(unique_ID, type) - Ops.get(@resolvables_to_install, [unique_ID, type], []) + data(optional).fetch(unique_ID, {}).fetch(type, []) end # Returns list of selected resolvables of a given type # - # @param symbol resolvable type + # @param [Symbol] type resolvable type + # @param [Boolean] optional True for optional list, false (the default) for + # the required list # @return [Array<String>] list of resolvables # # @example @@ -278,35 +223,29 @@ # GetAllResolvables (`unknown) -> nil # # @see #supported_resolvables - def GetAllResolvables(type) + def GetAllResolvables(type, optional: false) if !IsSupportedResolvableType(type) - Builtins.y2error( - "Not a supported type: %1, supported are only: %2", - type, - @supported_resolvables - ) + log.error("Not a supported type: #{type}, supported are only: #{@supported_resolvables}") return nil end ret = [] - Builtins.foreach(@resolvables_to_install) do |_unique_ID, resolvables| - if Builtins.haskey(resolvables, type) - ret = Builtins.sort( - Convert.convert( - Builtins.union(ret, Ops.get(resolvables, type, [])), - from: "list", - to: "list <string>" - ) - ) - end + data(optional).each do |_unique_ID, resolvables| + ret.concat(resolvables[type]) if resolvables.key?(type) end - deep_copy(ret) + # sort the result and remove the duplicates + ret.sort! + ret.uniq! + + ret end # Returns all selected resolvables for all supported types # + # @param [Boolean] optional True for optional list, false (the default) for + # the required list # @return [Hash{Symbol => Array<String>}] map of resolvables # # **Structure:** @@ -326,31 +265,28 @@ # `pattern : ["some", "patterns"], # `package : ["some", "packages"], # ] - def GetAllResolvablesForAllTypes + def GetAllResolvablesForAllTypes(optional: false) ret = {} - resolvables = [] - Builtins.foreach(GetSupportedResolvables()) do |one_type| - resolvables = GetAllResolvables(one_type) - if !resolvables.nil? && resolvables != [] - Ops.set(ret, one_type, resolvables) - end + GetSupportedResolvables().each do |one_type| + resolvables = GetAllResolvables(one_type, optional: optional) + ret[one_type] = resolvables if !resolvables.nil? && !resolvables.empty? end - deep_copy(ret) + ret end - # Return whether a unique ID is already in use. + # Returns true/false indicating whether the ID is already in use. # - # @param [String] unique_ID to check - # @return [Boolean] whether the ID is not in use yet + # @param [String] unique_ID the unique identificator to check + # @return [Boolean] true if the ID is not used, false otherwise def IsUniqueID(unique_ID) if unique_ID.nil? || unique_ID == "" - Builtins.y2error("Unique ID cannot be: %1", unique_ID) + log.error("Unique ID cannot be #{unique_ID.inspect}") return nil end - !Builtins.haskey(@resolvables_to_install, unique_ID) + !@resolvables_to_install.key?(unique_ID) && !@opt_resolvables_to_install.key?(unique_ID) end publish function: :ResetAll, type: "void ()" @@ -362,6 +298,45 @@ publish function: :GetAllResolvables, type: "list <string> (symbol)" publish function: :GetAllResolvablesForAllTypes, type: "map <symbol, list <string>> ()" publish function: :IsUniqueID, type: "boolean (string)" + + private + + # Return the required or the optional resolvable list. + # @param [Boolean] optional true for optional resolvables, false for + # the required resolvables + # @return [Hash] the stored resolvables + def data(optional) + optional ? @opt_resolvables_to_install : @resolvables_to_install + end + + # Build a label for logging resolvable kind + # @param [Boolean] optional true for optinal resolvables, false for required ones + # @return [String] description of the resolvables + def log_label(optional) + optional ? "optional resolvables" : "resolvables" + end + + # Returns the resolvable list for the requested ID, resolvable type and kind + # (required/optinal). If the list does not exit yet then a new empty list is created. + # + # @param [String] unique_ID + # @param [Symbol] type + # @param [Boolean] optional True for optional list, false (the default) for + # the required list + # @return [Array<String>] the stored resolvables list + def data_for(unique_ID, type, optional: false) + if !data(optional).key?(unique_ID) + log.debug("Creating #{unique_ID.inspect} ID") + data(optional)[unique_ID] = {} + end + + if !data(optional)[unique_ID].key?(type) + log.debug("Creating '#{type}' key for #{unique_ID.inspect} ID") + data(optional)[unique_ID][type] = [] + end + + data(optional)[unique_ID][type] + end end PackagesProposal = PackagesProposalClass.new diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-3.2.6/library/general/test/packages_proposal_test.rb new/yast2-3.2.7/library/general/test/packages_proposal_test.rb --- old/yast2-3.2.6/library/general/test/packages_proposal_test.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/yast2-3.2.7/library/general/test/packages_proposal_test.rb 2016-11-30 17:32:04.000000000 +0100 @@ -0,0 +1,195 @@ +#!/usr/bin/env rspec + +require_relative "test_helper" + +Yast.import "PackagesProposal" + +describe Yast::PackagesProposal do + subject { Yast::PackagesProposal } + + let(:proposal_id) { "yast-proposal-test" } + let(:packages) { ["grub2", "kexec-tools"] } + + let(:proposal_id2) { "yast-proposal-test2" } + let(:packages2) { ["kdump"] } + + before do + # store both required and optional resolvables + subject.AddResolvables(proposal_id, :package, packages) + subject.AddResolvables(proposal_id, :package, packages2, optional: true) + end + + after do + # make sure the internal state is reset after running the test + subject.ResetAll + end + + describe "ResetAll" do + it "resets the added resolvables" do + # not empty before, but empty after calling the reset + expect { subject.ResetAll }.to change { subject.GetAllResolvablesForAllTypes } + .from(package: packages).to({}) + end + end + + describe "GetSupportedResolvables" do + it "return the list of supported resolvables" do + # ignore the order of the items + expect(subject.GetSupportedResolvables).to match_array([:package, :pattern]) + end + end + + describe "AddResolvables" do + it "adds the required resolvables" do + add_list = ["new_package"] + subject.AddResolvables(proposal_id, :package, add_list) + expect(subject.GetResolvables(proposal_id, :package)).to match_array(packages + add_list) + end + + it "adds the optional resolvables" do + add_list = ["new_package"] + subject.AddResolvables(proposal_id, :package, add_list, optional: true) + expect(subject.GetResolvables(proposal_id, :package, optional: true)).to \ + match_array(packages2 + add_list) + end + + it "adding nil does not change the stored resolvables" do + expect { subject.AddResolvables(proposal_id, :package, nil) }.to_not \ + change { subject.GetResolvables(proposal_id, :package) } + end + end + + describe "GetResolvables" do + it "returns the required resolvables" do + ret = subject.GetResolvables(proposal_id, :package) + expect(ret).to match_array(packages) + end + + it "returns the optional resolvables" do + ret = subject.GetResolvables(proposal_id, :package, optional: true) + expect(ret).to match_array(packages2) + end + end + + describe "SetResolvables" do + it "removes the previous resolvables and sets new ones" do + expect { subject.SetResolvables(proposal_id, :package, packages2) }.to \ + change { subject.GetResolvables(proposal_id, :package) } + .from(packages).to(packages2) + end + + it "removes the previous optional resolvables and sets new ones" do + expect { subject.SetResolvables(proposal_id, :package, packages, optional: true) }.to \ + change { subject.GetResolvables(proposal_id, :package, optional: true) } + .from(packages2).to(packages) + end + + it "resets to empty list when nil is used" do + expect { subject.SetResolvables(proposal_id, :package, nil) }.to \ + change { subject.GetResolvables(proposal_id, :package) } + .from(packages).to([]) + end + end + + describe "RemoveResolvables" do + it "removes only the listed resolvables" do + expect { subject.RemoveResolvables(proposal_id, :package, ["kexec-tools"]) }.to \ + change { subject.GetResolvables(proposal_id, :package) } + .from(["grub2", "kexec-tools"]).to(["grub2"]) + end + + it "keeps the optional resolvables when removing the required ones" do + expect { subject.RemoveResolvables(proposal_id, :package, ["kexec-tools"]) }.to_not \ + change { subject.GetResolvables(proposal_id, :package, optional: true) } + end + + it "removes only the listed optional resolvables" do + expect { subject.RemoveResolvables(proposal_id, :package, ["kdump"], optional: true) }.to \ + change { subject.GetResolvables(proposal_id, :package, optional: true) } + .from(["kdump"]).to([]) + end + + it "keeps the optional resolvables when removing the required ones" do + expect { subject.RemoveResolvables(proposal_id, :package, packages2, optional: true) }.to_not \ + change { subject.GetResolvables(proposal_id, :package) } + end + + it "does not remove anything when nil is used" do + expect { subject.RemoveResolvables(proposal_id, :package, nil) }.to_not \ + change { subject.GetResolvables(proposal_id, :package) } + end + end + + describe "GetResolvables" do + it "returns the required resolvables" do + expect(subject.GetResolvables(proposal_id, :package)).to match_array(packages) + end + + it "returns the optional resolvables" do + expect(subject.GetResolvables(proposal_id, :package, optional: true)).to \ + match_array(packages2) + end + + it "returns nil for invalid ID" do + expect(subject.GetResolvables(nil, :package)).to be_nil + expect(subject.GetResolvables(nil, :package, optional: true)).to be_nil + end + + it "returns nil for invalid resolvable type" do + expect(subject.GetResolvables(proposal_id, :foobar)).to be_nil + expect(subject.GetResolvables(proposal_id, :foobar, optional: true)).to be_nil + end + + it "returns nil for nil resolvable type" do + expect(subject.GetResolvables(proposal_id, nil)).to be_nil + expect(subject.GetResolvables(proposal_id, nil, optional: true)).to be_nil + end + end + + describe "GetAllResolvables" do + it "returns nil if unsupported resolvable type is used" do + expect(subject.GetAllResolvables(:foobar)).to be_nil + end + + it "returns nil if unsupported resolvable type is used for optional resolvables" do + expect(subject.GetAllResolvables(:foobar, optional: true)).to be_nil + end + + it "returns the required resolvables" do + expect(subject.GetAllResolvables(:package)).to eq(packages) + end + + it "returns the optional resolvables" do + expect(subject.GetAllResolvables(:package, optional: true)).to eq(packages2) + end + end + + describe "GetAllResolvablesForAllTypes" do + it "returns the required resolvables" do + expect(subject.GetAllResolvablesForAllTypes).to eq(package: packages) + end + + it "returns the optional resolvables" do + expect(subject.GetAllResolvablesForAllTypes(optional: true)).to \ + eq(package: packages2) + end + end + + describe "IsUniqueID" do + it "returns nil for nil" do + expect(subject.IsUniqueID(nil)).to be_nil + end + + it "returns nil for empty string" do + expect(subject.IsUniqueID("")).to be_nil + end + + it "returns true if the ID is not already used" do + expect(subject.IsUniqueID("no-existing-proposal-id")).to eq(true) + end + + it "returns false if the ID is already used" do + expect(subject.IsUniqueID(proposal_id)).to eq(false) + end + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-3.2.6/package/yast2.changes new/yast2-3.2.7/package/yast2.changes --- old/yast2-3.2.6/package/yast2.changes 2016-11-23 17:54:28.000000000 +0100 +++ new/yast2-3.2.7/package/yast2.changes 2016-11-30 17:32:05.000000000 +0100 @@ -1,4 +1,11 @@ ------------------------------------------------------------------- +Wed Nov 30 09:18:23 UTC 2016 - [email protected] + +- Enhanced PackagesProposal API to handle required and optional + resolvables separately (bsc#885496) +- 3.2.7 + +------------------------------------------------------------------- Wed Nov 23 15:23:24 UTC 2016 - [email protected] - Fix replacement of workflow modules (bsc#1011869) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-3.2.6/package/yast2.spec new/yast2-3.2.7/package/yast2.spec --- old/yast2-3.2.6/package/yast2.spec 2016-11-23 17:54:28.000000000 +0100 +++ new/yast2-3.2.7/package/yast2.spec 2016-11-30 17:32:05.000000000 +0100 @@ -17,7 +17,7 @@ Name: yast2 -Version: 3.2.6 +Version: 3.2.7 Release: 0 Summary: YaST2 - Main Package License: GPL-2.0
