solaris-patch 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,32 +9,38 @@ Copyright:: Copyright (c) Martin Carpenter 2011
9
9
  The solaris-patch gem helps with the manipulation of SunOS and Solaris
10
10
  patches.
11
11
 
12
- * Read (or write!) patchdiag.xref files.
13
- * Find latest version of a patch.
14
- * Find latest non-superseded version of a patch.
15
- * Download patchdiag.xref, patches, readmes from Oracle.
16
- * ...
12
+ * Read (or write!) patchdiag.xref files.
13
+ * Find latest version of a patch.
14
+ * Find latest non-superseded version of a patch.
15
+ * Download patchdiag.xref, patches, readmes from Oracle.
16
+ * ...
17
17
 
18
18
  == Examples
19
19
 
20
20
  === Download a patch
21
21
 
22
22
  require 'solaris/patch'
23
- Solaris::Patch.download_patch!('123456-78',
24
- :to_file => '/tmp/123456-78.zip')
23
+ Solaris::Patch.download_patch!( '123456-78',
24
+ :to_file => '/tmp/123456-78.zip' )
25
25
 
26
26
  Alternatively:
27
27
 
28
28
  patch = Solaris::Patch.new( '123456-78' )
29
29
  patch.download_patch!( :to_dir => '/tmp' )
30
30
 
31
+ === Download a readme
32
+
33
+ require 'solaris/patch'
34
+ Solaris::Patch.download_readme!( '123456-78',
35
+ :to_file => '/tmp/123456-78.txt' )
36
+
31
37
  === Get the latest version of a patch
32
38
 
33
39
  require 'solaris/patch'
34
40
  Solaris::Patchdiag.open( '/tmp/patchdiag.xref' ).latest( '123456-01' )
35
41
  => "123456|12|..."
36
42
 
37
- === Get the latest non-obsolete version of an possibly obsoleted patch
43
+ === Get the latest non-obsolete version of a possibly obsoleted patch
38
44
 
39
45
  require 'solaris/patch'
40
46
  Solaris::Patchdiag.open( '/tmp/patchdiag.xref' ).successor( '123456-01' )
@@ -48,11 +54,11 @@ Alternatively:
48
54
  patchdiag = Solaris::Patchdiag.new( '/tmp/patchdiag.xref' )
49
55
 
50
56
  # all sparc patches
51
- patchdiag.all.select { |p| p.archs.include? 'sparc' }.inspect
57
+ patchdiag.select { |p| p.archs.include? 'sparc' }.inspect
52
58
  => [ "123456-78", ... ]
53
59
 
54
60
  # latest line added to patchdiag.xref
55
- most_recent = patchdiag.all( :sort_by => :date, :order => ascending ).max
61
+ most_recent = patchdiag.sort_by( &:date ).last
56
62
  most_recent
57
63
  => "123456|78|..."
58
64
 
@@ -67,5 +73,5 @@ Alternatively:
67
73
  == Known issues
68
74
 
69
75
  Dates in patchdiag.xref are Mon/dd/yy format. This gem will break in
70
- 2050 since it assumes year 50 and above is in the 20th Century.
76
+ 2050 since it assumes year 50 and above is in the 20th century.
71
77
 
@@ -6,11 +6,6 @@ module Solaris
6
6
  # Superclass for all throwable exceptions.
7
7
  class Exception < ::Exception ; end
8
8
 
9
- # Exception is raised by #find_successor when the patch whose
10
- # successor is to be sought or the supposed successor to a patch
11
- # does not exist in patchdiag.xref.
12
- class NotFound < Exception ; end
13
-
14
9
  # Exception is raised when the terminal (non-obsolete) succesor
15
10
  # to a patch has been withdrawn (is bad).
16
11
  class BadSuccessor < Exception ; end
@@ -22,9 +17,18 @@ module Solaris
22
17
  # Raised if a patchdiag entry appears to have multiple successors.
23
18
  class MultipleSuccessors < Exception ; end
24
19
 
20
+ # Exception is raised by Patchdiag#successor when the patch whose
21
+ # successor is to be sought or the supposed successor to a patch
22
+ # does not exist in patchdiag.xref.
23
+ class NotFound < Exception ; end
24
+
25
25
  # Raised if one tries to determine the successor of a non-obsolete patch.
26
26
  class NotObsolete < Exception ; end
27
27
 
28
+ # Raised when seeking the successor to a patch in patchdiag.xref results
29
+ # in a loop.
30
+ class SuccessorLoop < Exception ; end
31
+
28
32
  end
29
33
 
30
34
  end # Solaris
@@ -12,24 +12,22 @@ module Solaris
12
12
  require 'solaris/patchdiag_entry'
13
13
  require 'solaris/util'
14
14
 
15
+ include Enumerable
16
+
15
17
  # Default patchdiag.xref file, as for Patch Check Advanced cache
16
18
  DEFAULT_XREF_FILE = '/var/tmp/patchdiag.xref'
17
19
 
18
20
  # URL of latest patchdiag.xref from Oracle.
19
21
  DEFAULT_XREF_URL = 'https://getupdates.oracle.com/reports/patchdiag.xref'
20
22
 
21
- # An array containing all entries (of class PatchdiagEntry) read
22
- # from the patchdiag.xref file.
23
- attr_accessor :entries
24
-
25
23
  # Create a new patchdiag database object by reading the given
26
24
  # xref file (this may be a filename (string) or a fileish object
27
25
  # (File, StringIO)). If no xref file is given then the default
28
26
  # is read (/var/tmp/patchdiag.xref); this is the cache file used
29
27
  # by Patch Check Advanced (pca).
30
28
  def initialize(xref_file=DEFAULT_XREF_FILE)
31
- xref_file = File.new( xref_file ) if xref_file.is_a?(String)
32
- @entries = xref_file.
29
+ xref_file = File.new( xref_file ) if xref_file.is_a?( String )
30
+ @_entries = xref_file.
33
31
  readlines.
34
32
  reject { |line| line =~ /^#|^\s*$/ }. # discard comments, blanks
35
33
  map { |line| PatchdiagEntry.new( line ) }
@@ -44,8 +42,8 @@ module Solaris
44
42
  Util.download!( url, opts )
45
43
  end
46
44
 
47
- # Open the given optional patchdiag xref file and yield to the optional
48
- # block.
45
+ # Open the given optional patchdiag xref file and yield to the
46
+ # optional block.
49
47
  def Patchdiag.open(xref_file=DEFAULT_XREF_FILE, &blk)
50
48
  patchdiag = Patchdiag.new( xref_file )
51
49
  if block_given?
@@ -55,79 +53,113 @@ module Solaris
55
53
  end
56
54
  end
57
55
 
58
- # Returns an array of Solaris::PatchdiagEntry from the patchdiag with the given
59
- # patch number (a String like xxxxxx-yy or xxxxxx or a Solaris::Patch). Returns an
60
- # empty array if no such patches can be found.
56
+ # Create and return a deep copy of this object.
57
+ def clone
58
+ Marshal.load( Marshal.dump( self ) )
59
+ end
60
+
61
+ # For Enumerator module: yields each Solaris::PatchdiagEntry in
62
+ # turn.
63
+ def each(&blk)
64
+ @_entries.each( &blk )
65
+ end
66
+
67
+ # Returns an array of Solaris::PatchdiagEntry from the
68
+ # patchdiag.xref with the given patch number (a String like
69
+ # xxxxxx-yy or xxxxxx or a Solaris::Patch), sorted by minor number.
70
+ # If both a major and minor number are supplied (xxxxxx-yy) then
71
+ # returned entries (normally only one) will match exactly. If only
72
+ # a major number (xxxxxx) is supplied then all entries with that
73
+ # major number are returned. Returns an empty array if no such
74
+ # patches can be found. This method overrides Enumerable#find.
61
75
  def find(patch)
62
76
  patch = Patch.new( patch.to_s )
63
77
  property = patch.minor ? :to_s : :major
64
78
  comparator = patch.send( property )
65
- all.select { |pde| pde.patch.send( property ) == comparator }
79
+ entries.select { |pde| pde.patch.send( property ) == comparator }
66
80
  end
67
81
 
68
- # Return the Solaris::PatchdiagEntry of the latest version of the given patch
69
- # (a String like xxxxxx-yy or xxxxxx or a Solaris::Patch).
70
- # Throws Solaris::Patch::NotFound if the patch cannot be found in patchdiag.xref.
82
+ # Strangely Enumerable module does not define Enumerable#last (although
83
+ # it does define Enumerable#first) so we define last here.
84
+ def last
85
+ entries.last
86
+ end
87
+
88
+ # Return the Solaris::PatchdiagEntry of the latest version of the
89
+ # given patch (a String like xxxxxx-yy or xxxxxx or a
90
+ # Solaris::Patch). Throws Solaris::Patch::NotFound if the patch
91
+ # cannot be found in patchdiag.xref.
71
92
  def latest(patch)
72
93
  major = Patch.new( patch.to_s ).major
73
94
  find( major ).max ||
74
- raise( Solaris::Patch::NotFound, "Cannot find patch #{patch} in patchdiag.xref" )
95
+ raise( Solaris::Patch::NotFound,
96
+ "Cannot find patch #{patch} in patchdiag.xref" )
75
97
  end
76
98
 
77
- # Return the Solaris::PatchdiagEntry of the latest non-obsolete successor
78
- # of this patch. Throws Solaris::Patch::NotFound if the patch or any of its
79
- # named successors cannot be found in patchdiag.xref.
80
- def successor(patch)
81
- patch = Patch.new( patch.to_s )
82
- if ! patch.minor || ! entry = find( patch ).first
83
- entry = latest( patch )
84
- end
85
- raise Solaris::Patch::NotFound,
86
- "Cannot find patch #{patch} in patchdiag.xref" unless entry
87
- if entry.obsolete?
88
- succ = entry.successor # may raise
89
- successor( succ )
90
- elsif entry.bad?
91
- raise BadSuccessor, "Terminal successor #{patch} is bad/withdrawn"
92
- else
93
- entry
94
- end
99
+ # Returns a (deep) copy of +self+ with the entries sorted, takes an
100
+ # optional block. This method overrides Enumerable#sort. See also
101
+ # Solaris::Patchdiag#sort!.
102
+ def sort(&blk)
103
+ clone.sort!( &blk )
95
104
  end
96
105
 
97
- # Return all patchdiag entries (PatchdiagEntry) defined in the patchdiag.xref.
98
- # This method scans the entire patchdiag database so may be a little slow:
99
- # callers are encouraged to cache or memoize their results.
100
- def all(opts={})
101
-
102
- # Defaults
103
- order = :ascending
104
- sort_by = :patch
105
-
106
- # Parse options
107
- opts.each do |key, value|
108
- case key
109
- when :sort_by
110
- raise ArgumentError, "Invalid sort_by #{value.inspect}" unless [ :patch, :date ].include?( value )
111
- sort_by = value
112
- when :order
113
- raise ArgumentError, "Invalid order #{value.inspect}" unless [ :ascending, :descending ].include?( value )
114
- order = value
115
- else
116
- raise ArgumentError, "Unknown option key #{key.inspect}"
117
- end
118
- end
106
+ # Returns +self+ with the entries sorted in place, takes an optional
107
+ # block. See also Solaris::Patchdiag#sort.
108
+ def sort!(&blk)
109
+ # use @_entries since #entries returns a copy
110
+ @_entries.sort!( &blk )
111
+ self
112
+ end
119
113
 
120
- # Compute the lambda for sorting.
121
- if order == :ascending
122
- boat_op = lambda { |x,y| x.send( sort_by ) <=> y.send( sort_by ) }
114
+ # Return an array of Solaris::Patch of the successors to the given
115
+ # patch terminating in the latest non-obsolete successor (where that
116
+ # exists).
117
+ #
118
+ # Throws Solaris::Patch::NotFound if the patch or any of its named
119
+ # successors cannot be found in patchdiag.xref, or if no later version
120
+ # of the patch exists.
121
+ #
122
+ # Throws Solaris::Patch::SuccessorLoop if the successor of a patch refers
123
+ # to a patch that has already been referenced (an ancestor).
124
+ #
125
+ # The ancestors parameter is a recursion accumulator and should not
126
+ # normally be assigned to by callers.
127
+ def successors(patch, ancestors=[])
128
+ patch = Patch.new( patch.to_s )
129
+ raise Solaris::Patch::SuccessorLoop,
130
+ "Loop detected for patch #{patch} with ancestors #{ancestors.inspect}" if ancestors.include?( patch )
131
+ ancestors << patch
132
+ if ! patch.minor # patch has no minor number
133
+ successors( latest( patch ).patch, ancestors )
134
+ elsif ! entry = find( patch ).last # explicit patch not found
135
+ latest_patch = latest( patch ).patch
136
+ raise Solaris::Patch::NotFound,
137
+ "Patch #{patch} not found and has no later version" if latest_patch.minor <= patch.minor
138
+ successors( latest_patch, ancestors )
123
139
  else
124
- boat_op = lambda { |x,y| y.send( sort_by ) <=> x.send( sort_by ) }
140
+ if entry.obsolete?
141
+ succ = entry.successor
142
+ successors( succ, ancestors )
143
+ elsif entry.bad?
144
+ raise BadSuccessor, "Terminal successor #{patch} is bad/withdrawn"
145
+ else
146
+ ancestors
147
+ end
125
148
  end
149
+ end
126
150
 
127
- # Sort and return.
128
- @entries.sort { |x,y| boat_op.call( x, y ) }
151
+ # Return the Solaris::PatchdiagEntry of the latest non-obsolete successor
152
+ # of this patch. This is a convenience method for #successors.last.
153
+ def successor(patch)
154
+ latest( successors( patch ).last )
155
+ end
129
156
 
157
+ # Returns a string representation of the patchdiag.xref. All comments
158
+ # and blank lines are elided.
159
+ def to_s
160
+ entries.join("\n")
130
161
  end
162
+ alias to_str to_s
131
163
 
132
164
  end # Patchdiag
133
165
 
@@ -18,7 +18,9 @@ module Solaris
18
18
  attr_accessor :archs
19
19
 
20
20
  # The bad field from the patchdiag xref database. Should be either 'B'
21
- # or the empty string. See also PatchdiagEntry#bad?
21
+ # or the empty string. See also PatchdiagEntry#bad? (and
22
+ # PatchdiagEntry#y2k? since these flags share the same column in
23
+ # patchdiag.xref).
22
24
  attr_accessor :bad
23
25
 
24
26
  # The date of this patch (a Date object).
@@ -48,9 +50,15 @@ module Solaris
48
50
  # text field (string).
49
51
  attr_accessor :synopsis
50
52
 
53
+ # The year 2000 field from the patchdiag xref database. Should be either 'Y'
54
+ # or the empty string. See also PatchdiagEntry#y2k? (and
55
+ # PatchdiagEntry#bad? since these flags share the same column in
56
+ # patchdiag.xref).
57
+ attr_accessor :y2k
58
+
51
59
  def initialize(patchdiag_line)
52
- fields = patchdiag_line.split('|')[0..10]
53
- major, minor, date, @recommended, @security, @obsolete, @bad, @os, archs, pkgs, @synopsis = *fields
60
+ fields = patchdiag_line.split( '|', 11 )
61
+ major, minor, date, @recommended, @security, @obsolete, bad, @os, archs, pkgs, @synopsis = *fields
54
62
  @archs = archs.split( ';' )
55
63
  if date == ''
56
64
  year, month, day = 1970, 1, 1
@@ -60,9 +68,12 @@ module Solaris
60
68
  month = Date::ABBR_MONTHNAMES.index( month_s )
61
69
  day = day_s.to_i
62
70
  end
71
+ @bad = bad =~ /B/ ? 'B' : ' '
72
+ @y2k = bad =~ /Y/ ? 'Y' : ' '
63
73
  @date = Date.new( year, month, day )
64
74
  @patch = Patch.new( major, minor )
65
75
  @pkgs = pkgs.split( ';' )
76
+ @synopsis.chomp!
66
77
  end
67
78
 
68
79
  # Boolean, returns true if this patch is marked as "bad" in the patchdiag
@@ -123,10 +134,10 @@ module Solaris
123
134
  raise Solaris::Patch::NotObsolete,
124
135
  "Entry #{patch.inspect} not obsolete" unless obsolete?
125
136
 
126
- # Fail on these two entries from 1999 since they are the only ones ever
127
- # that are succeeded by two patches each
137
+ # Fail if this entry is obsoleted by two patches (currently 2011/05/04
138
+ # only 105716 and 105717)
128
139
  raise Solaris::Patch::MultipleSuccessors,
129
- "More than one successor for entry #{patch.inspect}" if [ 105716, 105717 ].include?( self.major )
140
+ "More than one successor for entry #{patch.inspect}" if synopsis =~ /obsolete(d?) by\s*(:?)\s*(\d+(-\d+)?)\s+and\s+(\d+(-\d+)?)/i
130
141
 
131
142
  # See if we can find a successor
132
143
  if synopsis =~ /obsolete(d?) by\s*(:?)\s*(\d+(-\d+)?)/i
@@ -146,13 +157,18 @@ module Solaris
146
157
  @recommended,
147
158
  @security,
148
159
  @obsolete,
149
- @bad,
160
+ @bad + @y2k,
150
161
  @os,
151
162
  join_semis( @archs ),
152
163
  join_semis( @pkgs ),
153
164
  @synopsis
154
165
  ].join('|')
155
166
  end
167
+ alias to_str to_s
168
+
169
+ # Boolean, returns true if this patch is marked as a year 2000 patch in the
170
+ # patchdiag xref database.
171
+ def y2k? ; @y2k == 'Y' end
156
172
 
157
173
  # Compare (by delegated comparison of patch versions, see Solaris::Patch#<=>).
158
174
  def <=>(other)
@@ -170,7 +186,7 @@ module Solaris
170
186
  end
171
187
 
172
188
  # Join an array of items with semicolons and append a trailing
173
- # semicolon if the array is non-empty, otherwise return the
189
+ # semicolon if the array is non-empty, otherwise return the
174
190
  # empty string. Used to format @archs and @pkgs for #to_s.
175
191
  def join_semis(a)
176
192
  a.empty? ? '' : a.join(';') + ';'
@@ -8,7 +8,7 @@ class TestPatchdiag < Test::Unit::TestCase #:nodoc:
8
8
 
9
9
  def setup
10
10
  @empty_file = '/dev/null'
11
- @patchdiag_fileish = StringIO.new(<<-EOF
11
+ @patchdiag_string = <<-EOF
12
12
  ## PATCHDIAG TOOL CROSS-REFERENCE FILE AS OF Feb/10/11 ##
13
13
  ##
14
14
  ## The content of this file has changed as of Jun/04/10. Due to the merging of
@@ -71,8 +71,14 @@ class TestPatchdiag < Test::Unit::TestCase #:nodoc:
71
71
  146444|01|Jan/27/11| | | | |10_x86|i386;120012-14;142910-17;|SUNWnge:11.10.0,REV=2005.06.22.03.40;|SunOS 5.10_x86: nge patch
72
72
  800054|01|Mar/16/01| | |O| |Unbundled|||Obsoleted by: 111346-01 Hardware/PROM: Sun Fire 3800/4800/4810/680
73
73
  100974|02|Mar/14/95| | | | |Unbundled|sparc;|SPROsw:2.1.0;|SparcWorks 2.0.1: dbx jumbo patch
74
+ 654321|01|Jan/01/00| | |O| |Unbundled|||Obsoleted by: 654321-02
75
+ 654321|02|Jan/01/00| | |O| |Unbundled|||Obsoleted by: 654321-03
76
+ 654321|03|Jan/01/00| | |O| |Unbundled|||Obsoleted by: 654321-01
77
+ 654322|01|Jan/01/00| | |O| |Unbundled|||Obsoleted by: 654321-05
78
+ 115302|01|Jul/08/03| | |O| B|Unbundled|||WITHDRAWN PATCH Obsoleted by: 115302-02 Hardware/PROM: CP2060/CP20
74
79
  EOF
75
- )
80
+ @patchdiag_fileish = StringIO.new( @patchdiag_string )
81
+ @patchdiag_size = 56
76
82
  @patchdiag = Solaris::Patchdiag.open( @patchdiag_fileish )
77
83
  end
78
84
 
@@ -80,10 +86,12 @@ EOF
80
86
  @empty_file = nil
81
87
  @patchdiag = nil
82
88
  @patchdiag_fileish = nil
89
+ @patchdiag_string = nil
90
+ @patchdiag_size = nil
83
91
  end
84
92
 
85
93
  def test_new_by_fileish
86
- assert_equal( 51, @patchdiag.entries.size )
94
+ assert_equal( @patchdiag_size, @patchdiag.entries.size )
87
95
  end
88
96
 
89
97
  def test_new_by_filename
@@ -93,7 +101,7 @@ EOF
93
101
  temp.close
94
102
  patchdiag = Solaris::Patchdiag.new( path )
95
103
  File.unlink( path )
96
- assert_equal( 51, @patchdiag.entries.size )
104
+ assert_equal( @patchdiag_size, @patchdiag.entries.size )
97
105
  end
98
106
 
99
107
  def test_new_empty_file
@@ -103,24 +111,40 @@ EOF
103
111
  end
104
112
  end
105
113
 
106
- def test_all
107
- assert_equal( 51, @patchdiag.all.size )
114
+ def test_no_tailing_newline
115
+ s = StringIO.new('115302|01|Jul/08/03| | |O| B|Unbundled|||blah blah')
116
+ assert_equal( 1, Solaris::Patchdiag.new( s ).entries.size )
108
117
  end
109
118
 
110
- def test_all_sort_by_date_order_ascending
111
- all = @patchdiag.all( :sort_by => :date, :order => :ascending )
119
+ def test_clone
120
+ @cloned = @patchdiag.clone
121
+ assert_equal( @patchdiag.class, @cloned.class )
122
+ assert_equal( @patchdiag.entries.size, @cloned.entries.size )
123
+ assert_equal( @patchdiag.entries.first, @cloned.entries.first )
124
+ assert_not_equal( @patchdiag.object_id, @cloned.object_id )
125
+ @patchdiag.entries.zip( @cloned.entries ).each do |x,y|
126
+ assert_not_equal( x.object_id, y.object_id )
127
+ end
128
+ end
129
+
130
+ def test_entries
131
+ assert_equal( @patchdiag_size, @patchdiag.entries.size )
132
+ end
133
+
134
+ def test_sort_by_date_order_ascending
135
+ all = @patchdiag.sort_by( &:date )
112
136
  first = all.first.patch # oldest
113
137
  last = all.last.patch # newest
114
138
  assert_equal( Solaris::Patch.new( '100386-01' ), first )
115
139
  assert_equal( Solaris::Patch.new( '146443-01' ), last )
116
140
  end
117
141
 
118
- def test_all_sort_by_patch_order_descending
119
- all = @patchdiag.all( :sort_by => :patch, :order => :descending )
120
- first = all.first.patch # largest
121
- last = all.last.patch # smallest
122
- assert_equal( Solaris::Patch.new( '800054-01' ), first )
123
- assert_equal( Solaris::Patch.new( '100287-05' ), last )
142
+ def test_sort_by_patch_order_ascending
143
+ all = @patchdiag.sort
144
+ first = all.first.patch # smallest
145
+ last = all.last.patch # largest
146
+ assert_equal( Solaris::Patch.new( '800054-01' ), last )
147
+ assert_equal( Solaris::Patch.new( '100287-05' ), first )
124
148
  end
125
149
 
126
150
  def test_open_block
@@ -135,6 +159,34 @@ EOF
135
159
  assert_equal( Solaris::Patchdiag, @patchdiag.class )
136
160
  end
137
161
 
162
+ def test_bad
163
+ entry = @patchdiag.latest( '115302' )
164
+ assert_equal( true, entry.bad? )
165
+ entry = @patchdiag.latest( '654321-01' )
166
+ assert_equal( false, entry.bad? )
167
+ end
168
+
169
+ def test_recommended
170
+ entry = @patchdiag.latest( '146279-01' )
171
+ assert_equal( true, entry.recommended? )
172
+ entry = @patchdiag.latest( '654321-01' )
173
+ assert_equal( false, entry.recommended? )
174
+ end
175
+
176
+ def test_security
177
+ entry = @patchdiag.latest( '146279-01' )
178
+ assert_equal( true, entry.security? )
179
+ entry = @patchdiag.latest( '654321-01' )
180
+ assert_equal( false, entry.security? )
181
+ end
182
+
183
+ def test_obsolete
184
+ entry = @patchdiag.latest( '115302-01' )
185
+ assert_equal( true, entry.obsolete? )
186
+ entry = @patchdiag.latest( '100287-05' )
187
+ assert_equal( false, entry.obsolete? )
188
+ end
189
+
138
190
  def test_find
139
191
  assert_equal( [], @patchdiag.find( 123456 ) )
140
192
  assert_equal( [], @patchdiag.find( '123456' ) )
@@ -152,6 +204,10 @@ EOF
152
204
  assert_equal( '100791-04', @patchdiag.find( Solaris::Patch.new( '100791-04') ).first.patch.to_s )
153
205
  end
154
206
 
207
+ def test_last
208
+ assert_equal( '115302-01', @patchdiag.last.patch.to_s )
209
+ end
210
+
155
211
  def test_latest
156
212
  assert_raise( Solaris::Patch::NotFound ) do
157
213
  @patchdiag.latest( 123456 )
@@ -166,6 +222,24 @@ EOF
166
222
  assert_equal( '100791-05', @patchdiag.latest( Solaris::Patch.new( '100791-05' ) ).patch.to_s )
167
223
  end
168
224
 
225
+ def test_sort
226
+ assert_equal( '115302-01', @patchdiag.entries.last.patch.to_s )
227
+ sorted = @patchdiag.sort
228
+ assert_equal( Solaris::Patchdiag, sorted.class )
229
+ assert_equal( '800054-01', sorted.entries.last.patch.to_s )
230
+ assert_equal( '115302-01', @patchdiag.entries.last.patch.to_s )
231
+ end
232
+
233
+ def test_sort!
234
+ assert_equal( '115302-01', @patchdiag.entries.last.patch.to_s )
235
+ size = @patchdiag.entries.size
236
+ ret = @patchdiag.sort!
237
+ assert_equal( @patchdiag, ret )
238
+ assert_equal( size, @patchdiag.entries.size )
239
+ assert_equal( Solaris::Patchdiag, @patchdiag.class )
240
+ assert_equal( '800054-01', @patchdiag.entries.last.patch.to_s )
241
+ end
242
+
169
243
  def test_successor
170
244
  assert_raise( Solaris::Patch::NotFound ) do
171
245
  @patchdiag.latest( 123456 )
@@ -175,13 +249,33 @@ EOF
175
249
  assert_equal( '100287-05', @patchdiag.successor( '100287-05' ).patch.to_s )
176
250
  assert_equal( '100287-05', @patchdiag.successor( Solaris::Patch.new( '100287-05' ) ).patch.to_s )
177
251
  assert_equal( '100974-02', @patchdiag.successor( 100791 ).patch.to_s )
252
+ assert_raise( Solaris::Patch::NotFound ) do
253
+ @patchdiag.successor( 123456 )
254
+ end
178
255
  assert_raise( Solaris::Patch::NotFound ) do
179
256
  @patchdiag.successor( 100393 ) # successor 100394 not in patchdiag.xref
180
257
  end
258
+ assert_raise( Solaris::Patch::NotFound ) do
259
+ @patchdiag.successor( '654322-05' )
260
+ end
181
261
  assert_equal( '100807-04', @patchdiag.successor( '100807-01' ).patch.to_s )
182
262
  assert_raise( Solaris::Patch::InvalidSuccessor ) do
183
263
  @patchdiag.successor( '100807-03' ) # successor 100807-03 WITHDRAWN
184
264
  end
265
+ assert_raise( Solaris::Patch::SuccessorLoop ) do
266
+ @patchdiag.successor( 654321 )
267
+ end
268
+ assert_raise( Solaris::Patch::SuccessorLoop ) do
269
+ @patchdiag.successor( '654321-01' )
270
+ end
271
+ assert_raise( Solaris::Patch::NotFound ) do
272
+ @patchdiag.successor( 115302 )
273
+ end
274
+ end
275
+
276
+ def test_successors
277
+ assert_equal( %w{ 100791 100791-05 100974 100974-02 },
278
+ @patchdiag.successors( 100791 ).map(&:to_s) )
185
279
  end
186
280
 
187
281
  def test_download!
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 1
7
7
  - 0
8
- - 0
9
- version: 1.0.0
8
+ - 1
9
+ version: 1.0.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - Martin Carpenter
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-05-03 00:00:00 +02:00
17
+ date: 2011-05-30 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -32,7 +32,7 @@ dependencies:
32
32
  version: 1.0.0
33
33
  type: :runtime
34
34
  version_requirements: *id001
35
- description: Provides methods to deal with Solaris patchdiag.xref and patches, including parsing patchdiag.xref, downloads from Oracle (patch and readme), patch version comparison, and eg seeking the latest non-obsolete version of a patch
35
+ description: Provides methods to deal with Solaris patchdiag.xref and patches, including parsing patchdiag.xref, downloads from Oracle (patch and readme), patch version comparison, and generic patchdiag.xref manipulations such as seeking the latest non-obsolete version of a patch
36
36
  email: mcarpenter@free.fr
37
37
  executables: []
38
38
 
@@ -45,7 +45,6 @@ extra_rdoc_files:
45
45
  files:
46
46
  - lib/solaris/exception.rb
47
47
  - lib/solaris/patch.rb
48
- - lib/solaris/foo
49
48
  - lib/solaris/patchdiag_entry.rb
50
49
  - lib/solaris/util.rb
51
50
  - lib/solaris/patchdiag.rb
@@ -1,13 +0,0 @@
1
- #!/usr/bin/ruby
2
-
3
- require 'pp'
4
-
5
- def find(what=:all, opts={})
6
- pp what
7
- pp opts
8
- puts
9
- end
10
-
11
- find
12
- find(:something, :foo=>:bar)
13
- find(:foo=>:bar)