Hello community,

here is the log from the commit of package zypper-lifecycle-plugin for 
openSUSE:Factory checked in at 2020-09-29 19:05:00
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/zypper-lifecycle-plugin (Old)
 and      /work/SRC/openSUSE:Factory/.zypper-lifecycle-plugin.new.4249 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "zypper-lifecycle-plugin"

Tue Sep 29 19:05:00 2020 rev:6 rq:838482 version:0.6.1601367426.843fe7a

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/zypper-lifecycle-plugin/zypper-lifecycle-plugin.changes
  2020-08-10 14:57:53.815997284 +0200
+++ 
/work/SRC/openSUSE:Factory/.zypper-lifecycle-plugin.new.4249/zypper-lifecycle-plugin.changes
        2020-09-29 19:05:19.814025177 +0200
@@ -1,0 +2,7 @@
+Tue Sep 29 08:18:45 UTC 2020 - Vladimir Nadvornik <nadvor...@suse.com>
+
+- Version 0.6.1601367426.843fe7a
+- Allow wildcard matching (jsc#SLE-14168)
+- Implement successor handling (jsc#SLE-16251)
+
+-------------------------------------------------------------------

Old:
----
  zypper-lifecycle-0.6.1596796104.87bdab7.tar.xz

New:
----
  zypper-lifecycle-0.6.1601367426.843fe7a.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ zypper-lifecycle-plugin.spec ++++++
--- /var/tmp/diff_new_pack.AAaaOr/_old  2020-09-29 19:05:20.486025855 +0200
+++ /var/tmp/diff_new_pack.AAaaOr/_new  2020-09-29 19:05:20.490025860 +0200
@@ -23,7 +23,7 @@
 
 Name:           zypper-lifecycle-plugin
 Url:            https://github.com/SUSE/zypper-lifecycle
-Version:        0.6.1596796104.87bdab7
+Version:        0.6.1601367426.843fe7a
 Release:        0
 Requires:       zypper >= 1.13.10
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build

++++++ zypper-lifecycle-0.6.1596796104.87bdab7.tar.xz -> 
zypper-lifecycle-0.6.1601367426.843fe7a.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/zypper-lifecycle-0.6.1596796104.87bdab7/test-data/SLES.lifecycle 
new/zypper-lifecycle-0.6.1601367426.843fe7a/test-data/SLES.lifecycle
--- old/zypper-lifecycle-0.6.1596796104.87bdab7/test-data/SLES.lifecycle        
2020-08-07 12:28:24.000000000 +0200
+++ new/zypper-lifecycle-0.6.1601367426.843fe7a/test-data/SLES.lifecycle        
2020-09-29 10:17:06.000000000 +0200
@@ -1,7 +1,36 @@
 # test data for SLES product
-# this should be installed in /var/lib/lifecycle/data/SLES.lifecycle
-# format: name,version,date
+# this should be installed in /usr/share/lifecycle/data/SLES.lifecycle
+# format: name,version,date,successor
+# successor is optional
+# date can be empty if successor is specified
+
 # version can contain wildcard character *
 
 aaa_base,       13.2*,           2016-05-05
-kernel-default, 3.12.51-60.25.1, 2016-05-01
+
+
+# Name can contain wildcard character *
+
+kernel-*, 3.12.51-60.25.1, 2016-05-01
+
+# or it can be specified as regexp enclosed in / /
+# See Ruby documentation for regexp syntax.
+# Typically the regexp should match whole name,
+# so ^ and $ should be used
+
+/^kernel-.*$/, 3.12.51-60.25.1, 2016-05-01
+
+# Successor specifies a package that replaces the given package
+# when available - jsc#SLE-16356
+#
+# Successor use the same syntax as name, additionally
+# it can reference matching groups from name with "<1>", "<2>" etc.
+# the groups are generated from wildcards, in regexp they must be
+# marked with ( )
+
+# the following 4 lines are equivalent
+
+hdf5_*-gnu*-hpc,         *, , hdf5_*-gnu<2>-hpc
+hdf5_*-gnu*-hpc,         *, , /^hdf5_(.*)-gnu<2>-hpc$/
+/^hdf5_.*-gnu(.*)-hpc$/, *, , hdf5_*-gnu<1>-hpc
+/^hdf5_.*-gnu(.*)-hpc$/, *, , /^hdf5_(.*)-gnu<1>-hpc$/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/zypper-lifecycle-0.6.1596796104.87bdab7/zypper-lifecycle 
new/zypper-lifecycle-0.6.1601367426.843fe7a/zypper-lifecycle
--- old/zypper-lifecycle-0.6.1596796104.87bdab7/zypper-lifecycle        
2020-08-07 12:28:24.000000000 +0200
+++ new/zypper-lifecycle-0.6.1601367426.843fe7a/zypper-lifecycle        
2020-09-29 10:17:06.000000000 +0200
@@ -116,9 +116,9 @@
         @installed_products[p[:name]] =  p if p[:installed] == "true"
       end
 
-      package_list = Zypper::xml_call("--no-refresh -x se -s -t package", 
'search-result/solvable-list')
+      @all_packages = Zypper::xml_call("--no-refresh -x se -s -t package", 
'search-result/solvable-list')
       @installed_package = {}
-      package_list.each do |p|
+      @all_packages.each do |p|
         if p[:kind] == 'package' && p[:status] == 'installed'
           @installed_package[p[:name]] ||= []
           @installed_package[p[:name]] << p
@@ -144,7 +144,7 @@
         end
       end
 
-      package_list.each do |p|
+      @all_packages.each do |p|
         p[:product] = product_by_repo[p[:repository]]
       end
 
@@ -156,6 +156,8 @@
     end
 
     def load_lifecycle_data()
+      @lifecycle_data = []
+      @successors = {}
       @installed_products.values.each do |product|
         [
           "/var/lib/lifecycle/data/#{product[:name]}.lifecycle",
@@ -165,20 +167,8 @@
           print "trying to load #{file}... " if @verbose
           begin
             CSV.foreach(file, :skip_blanks => true, :skip_lines => /^\s*#/ ) 
do |line|
-              name, version, date = line.map(&:strip)
-              date = Time.parse(date).strftime("%s")
-              version_re = Regexp.new( '^' + 
Regexp.quote(version).gsub(/\\\*/, '.*') + '$')
-              #print "match #{name} #{version_re}\n"
-              (@installed_package[name] || []).each do |p|
-                #print "#{p}\n"
-                if version_re.match(p[:edition])
-                  p[:package_eol] = date
-                end
-                if version_re.match(p[:update_edition])
-                  p[:update_package_eol] = date
-                end
-                p[:version_specified] = version
-              end
+              line.each{ |f| f = "" unless f; f.strip! }
+              @lifecycle_data.append(line)
             end
             print "ok\n" if @verbose
           rescue Errno::ENOENT => e
@@ -189,6 +179,93 @@
           end
         end
       end
+      parse_lifecycle_data(1)
+      # currenly we do not print successor EOL, so second pass is not needed
+      # parse_lifecycle_data(2)
+    end
+
+
+    def parse_lifecycle_data(pass)
+      if pass==1
+        target_hash = @installed_package
+      else
+        target_hash = @successors
+      end
+      @lifecycle_data.each do |line|
+        begin
+          name, version, date, successor = line
+
+          if !date || date.empty?
+            date = nil
+          else
+            date = Time.parse(date).strftime("%s")
+          end
+          version_re = Regexp.new( '^' + Regexp.quote(version).gsub(/\\\*/, 
'.*') + '$')
+          #print "match #{name} #{version_re}\n"
+          name_re = nil
+          if name.start_with?("/") && name.end_with?("/")
+            name_re = Regexp.new(name[1..-2])
+            matching_names = target_hash.keys.select { |p| name_re.match(p) }
+            matching_installed = matching_names.map { |p| target_hash[p] 
}.flatten(1)
+          elsif name.include? "*"
+            name_re = Regexp.new( '^' + Regexp.quote(name).gsub(/\\\*/, 
'(.*)') + '$')
+            matching_names = target_hash.keys.select { |p| name_re.match(p) }
+            matching_installed = matching_names.map { |p| target_hash[p] 
}.flatten(1)
+          else
+            matching_installed = target_hash[name]
+          end
+          (matching_installed || []).each do |p|
+            if version_re.match(p[:edition])
+              p[:package_eol] = date
+            end
+            if version_re.match(p[:update_edition])
+              p[:update_package_eol] = date
+            end
+            p[:version_specified] = version
+
+            if pass == 1 && successor
+              handle_successor(p, successor, name_re)
+            end
+          end
+        rescue Exception => e
+          print "\nError parsing #{line}: #{e.message}\n"
+            @retval = 2
+        end
+      end
+    end
+
+    def handle_successor(package, successor, name_re)
+      matches = [package[:name]]
+      if name_re
+          m = name_re.match(package[:name])
+          matches += m.captures if m
+      end
+      if successor.start_with?("/") && successor.end_with?("/")
+          successor_re = successor[1..-2]
+      else
+          successor_re = '^' + Regexp.quote(successor).gsub(/\\\*/, '.*') + '$'
+      end
+      for i in 0..9
+          successor_re.gsub!(/<#{i}>/, Regexp.quote(matches[i] || ''))
+      end
+      successor_re = Regexp.new(successor_re)
+      matching_successors = @all_packages.select { |s| 
successor_re.match(s[:name]) && package[:name] != s[:name] && package[:arch] == 
s[:arch] }
+
+      # select the successor with highest version
+      successor_version = package[:edition]
+      successor_pkg = nil
+      matching_successors.each do |s|
+        if Gem::Version.new(s[:edition]) > Gem::Version.new(successor_version)
+          successor_pkg = s
+          successor_version = s[:edition]
+        end
+      end
+
+      if successor_pkg
+        package[:successor] = successor_pkg
+        @successors[successor_pkg[:name]] ||= []
+        @successors[successor_pkg[:name]] << successor_pkg
+      end
     end
 
     def solve_package_eol()
@@ -211,6 +288,10 @@
           up_eol = p[:product][:endoflife_time_t] if !up_eol && p[:product] && 
p[:product][:endoflife_time_t] # default to product eol
           p[:update_eol] = up_eol.to_i if up_eol
         end
+
+        if p[:successor]
+          p[:eol] = NowTS
+        end
       end
     end
 
@@ -301,7 +382,10 @@
       vendor = p[:product][:vendor] if p[:product]
       eol = eol_string(p[:eol], vendor)
       up = ''
-      if p[:update_edition]
+      if p[:successor]
+        up = ", installed #{p[:edition]}, successor available 
#{p[:successor][:name]}-#{p[:successor][:edition]}"
+        up_eol = ''
+      elsif p[:update_edition]
         up = ", installed #{p[:edition]}, update available 
#{p[:update_edition]}"
         up_eol = ''
         up_eol = eol_string(p[:update_eol], vendor) if p[:update_eol] && 
p[:update_eol] < NaTS
@@ -366,7 +450,7 @@
         print ".\n"
       end
 
-      packages = @installed_package.values.flatten.select {|p| 
(p[:package_eol] || p[:update_edition]) }
+      packages = @installed_package.values.flatten.select {|p| 
(p[:package_eol] || p[:update_edition] || p[:successor]) }
       print_packages = packages.select {|p| !p[:already_reported] }
       if print_packages.length > 0
         print "\nPackage end of support if different from product:\n"
@@ -415,7 +499,7 @@
         print "\nNo products whose support ends before #{date_str}.\n"
       end
       packages = @installed_package.values.flatten.select {|p| p[:eol] && 
p[:eol] <= date_ts }
-      dif_packages = packages.select {|p| (p[:package_eol] || 
p[:update_edition]) }
+      dif_packages = packages.select {|p| (p[:package_eol] || 
p[:update_edition] || p[:successor]) }
       print_packages = dif_packages.select {|p| !p[:already_reported] }
       if packages.length > 0
         if print_packages.length > 0


Reply via email to