solaris-patch 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE ADDED
@@ -0,0 +1,26 @@
1
+ Copyright 2011 Martin Carpenter. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without modification, are
4
+ permitted provided that the following conditions are met:
5
+
6
+ 1. Redistributions of source code must retain the above copyright notice, this list of
7
+ conditions and the following disclaimer.
8
+
9
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list
10
+ of conditions and the following disclaimer in the documentation and/or other materials
11
+ provided with the distribution.
12
+
13
+ THIS SOFTWARE IS PROVIDED BY Martin Carpenter ``AS IS'' AND ANY EXPRESS OR IMPLIED
14
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
15
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Martin Carpenter OR
16
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
19
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
21
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
+
23
+ The views and conclusions contained in the software and documentation are those of the
24
+ authors and should not be interpreted as representing official policies, either expressed
25
+ or implied, of Martin Carpenter.
26
+
data/README.rdoc ADDED
@@ -0,0 +1,71 @@
1
+
2
+ = solaris-patch
3
+
4
+ Author:: Martin Carpenter
5
+ Email:: mcarpenter@free.fr
6
+ Copyright:: Copyright (c) Martin Carpenter 2011
7
+
8
+ == About
9
+ The solaris-patch gem helps with the manipulation of SunOS and Solaris
10
+ patches.
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
+ * ...
17
+
18
+ == Examples
19
+
20
+ === Download a patch
21
+
22
+ require 'solaris/patch'
23
+ Solaris::Patch.download_patch!('123456-78',
24
+ :to_file => '/tmp/123456-78.zip')
25
+
26
+ Alternatively:
27
+
28
+ patch = Solaris::Patch.new( '123456-78' )
29
+ patch.download_patch!( :to_dir => '/tmp' )
30
+
31
+ === Get the latest version of a patch
32
+
33
+ require 'solaris/patch'
34
+ Solaris::Patchdiag.open( '/tmp/patchdiag.xref' ).latest( '123456-01' )
35
+ => "123456|12|..."
36
+
37
+ === Get the latest non-obsolete version of an possibly obsoleted patch
38
+
39
+ require 'solaris/patch'
40
+ Solaris::Patchdiag.open( '/tmp/patchdiag.xref' ).successor( '123456-01' )
41
+ => "234567|12|..."
42
+
43
+ === Interrogate patchdiag.xref
44
+
45
+ require 'solaris/patch'
46
+
47
+ # slurp in patchdiag.xref
48
+ patchdiag = Solaris::Patchdiag.new( '/tmp/patchdiag.xref' )
49
+
50
+ # all sparc patches
51
+ patchdiag.all.select { |p| p.archs.include? 'sparc' }.inspect
52
+ => [ "123456-78", ... ]
53
+
54
+ # latest line added to patchdiag.xref
55
+ most_recent = patchdiag.all( :sort_by => :date, :order => ascending ).max
56
+ most_recent
57
+ => "123456|78|..."
58
+
59
+ # most recent patch number
60
+ most_recent.patch
61
+ => "123456-78"
62
+
63
+ # most recent patch's README if it was recommended
64
+ most_recent.download_readme! if most_recent.recommended?
65
+ => "Patch-ID# 123456-78..."
66
+
67
+ == Known issues
68
+
69
+ 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.
71
+
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ require 'rake'
2
+ require 'rake/clean'
3
+ require 'rake/gempackagetask'
4
+ require 'rake/rdoctask'
5
+ require 'rake/testtask'
6
+
7
+ desc 'Default task (package)'
8
+ task :default => [:package]
9
+
10
+ Rake::TestTask.new( 'test' )
11
+
12
+ SPECFILE = 'solaris-patch.gemspec'
13
+ if File.exist?( SPECFILE )
14
+ spec = eval( File.read( SPECFILE ) )
15
+ Rake::GemPackageTask.new( spec ).define
16
+ end
17
+
18
+ Rake::RDocTask.new do |rdoc|
19
+ rdoc.rdoc_dir = 'rdoc'
20
+ rdoc.title = 'solaris-patch'
21
+ rdoc.options << '--charset' << 'utf-8'
22
+ rdoc.options << '--all'
23
+ rdoc.rdoc_files.include( 'README.rdoc' )
24
+ rdoc.rdoc_files.include( FileList[ 'lib/**/*' ] )
25
+ rdoc.rdoc_files.include( FileList[ 'test/**/*' ] )
26
+ end
27
+
@@ -0,0 +1,31 @@
1
+
2
+ module Solaris
3
+
4
+ class Patch
5
+
6
+ # Superclass for all throwable exceptions.
7
+ class Exception < ::Exception ; end
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
+ # Exception is raised when the terminal (non-obsolete) succesor
15
+ # to a patch has been withdrawn (is bad).
16
+ class BadSuccessor < Exception ; end
17
+
18
+ # Raised if the "obsoleted by" value for this patchdiag entry is not
19
+ # comprehensible.
20
+ class InvalidSuccessor < Exception ; end
21
+
22
+ # Raised if a patchdiag entry appears to have multiple successors.
23
+ class MultipleSuccessors < Exception ; end
24
+
25
+ # Raised if one tries to determine the successor of a non-obsolete patch.
26
+ class NotObsolete < Exception ; end
27
+
28
+ end
29
+
30
+ end # Solaris
31
+
data/lib/solaris/foo ADDED
@@ -0,0 +1,13 @@
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)
@@ -0,0 +1,116 @@
1
+
2
+ module Solaris
3
+
4
+ # Class to represent a patch number.
5
+ class Patch
6
+
7
+ include Comparable
8
+
9
+ require 'solaris/util'
10
+ require 'solaris/exception'
11
+ require 'solaris/patchdiag'
12
+ require 'solaris/patchdiag_entry'
13
+
14
+ # Hash of URL patterns for downloads of type :patch or :readme.
15
+ # The string format parameter (%s) is the full patch number.
16
+ URL = {
17
+ :patch => 'https://getupdates.oracle.com/all_unsigned/%s.zip',
18
+ :readme => 'https://getupdates.oracle.com/readme/README.%s'
19
+ }
20
+
21
+ # The major number of the patch (integer), the part before the dash.
22
+ attr_accessor :major
23
+
24
+ # The minor number of the patch (integer), the part after the dash.
25
+ # Since this is an integer, values less than 10 will not be left
26
+ # padded with zero (see Patch::pad_minor). May be nil if not specified
27
+ # in the constructor.
28
+ attr_accessor :minor
29
+
30
+ # Create a patch. May take zero, one or two parameters.
31
+ #
32
+ # In the one parameter form, this is a string of the patch number
33
+ # eg '123456-78'. (If you specify integer 123456-78 then the
34
+ # resulting object will have major number 123378 and no minor
35
+ # number; this is probably not what you want).
36
+ #
37
+ # In the two parameter form, the first parameter is the major
38
+ # patch number (123456) and the second is the minor number (78).
39
+ # Although it is possible to provide strings or integers here strings
40
+ # should be prefered since a leading zero on an integer in Ruby
41
+ # indicates an octal representation (in the tradition of C). This can
42
+ # cause problems with a revision number of 09, since this is not a
43
+ # valid octal representation.
44
+ #
45
+ # TLDR: Patch.new('123456-78')
46
+ def initialize(major=nil, minor=nil)
47
+ if major
48
+ patch_no = major.to_s + ( minor ? "-#{minor}" : '' )
49
+ if patch_no =~ /^(\d+)(-(\d+))?$/
50
+ @major = $1.to_i
51
+ @minor = $3.to_i if $3
52
+ else
53
+ raise ArgumentError, "Invalid patch number string #{patch_no.inspect}"
54
+ end
55
+ end
56
+ end
57
+
58
+ # Download this patch. For the options hash see private method Patch#download!
59
+ def download_patch!(opts={})
60
+ download!( :patch, opts )
61
+ end
62
+
63
+ # Download this README. For the options hash see private method Patch#download!
64
+ def download_readme!(opts={})
65
+ download!( :readme, opts )
66
+ end
67
+
68
+ # Return a string representation of this patch. If the minor
69
+ # number has not been set then just return the major number.
70
+ def to_s
71
+ minor ? "#{@major}-#{Patch.pad_minor( @minor )}" : "#{@major}"
72
+ end
73
+
74
+ # Compare patch versions. (Performs a string compare on the full patch numbers).
75
+ def <=>(other)
76
+ self.to_s <=> other.to_s
77
+ end
78
+
79
+ # Download the given patch (this may be a Patch object or a string
80
+ # like '123456-78'). For the options hash see Patch#download!.
81
+ def Patch.download_patch!(patch, opts={})
82
+ patch_to_dl = Patch.new( patch.to_s )
83
+ patch_to_dl.download_patch!( opts )
84
+ end
85
+
86
+ # Download the given readme (this may be a Patch object or a string
87
+ # like '123456-78'). For the options hash see Patch#download!.
88
+ def Patch.download_readme!(patch, opts={})
89
+ patch_to_dl = Patch.new( patch.to_s )
90
+ patch_to_dl.download_readme!( opts )
91
+ end
92
+
93
+ # Left pad a minor version number with zeros as required.
94
+ def Patch.pad_minor(minor)
95
+ "#{minor.to_s.rjust( 2, '0' )}"
96
+ end
97
+
98
+ private
99
+
100
+ # Download this patch or readme from Oracle.
101
+ # For the options hash argument see Solaris::Util.download!
102
+ def download!(type, opts={})
103
+ raise ArgumentError, "Patch #{self.inspect} requires a major number to download" unless @major
104
+ raise ArgumentError, "Patch #{self.inspect} requires a minor number to download" unless @minor
105
+ raise ArgumentError, "Unknown type #{type.inspect}" unless URL[ type ]
106
+ url = URL[ type ] % self.to_s
107
+ opts = {
108
+ :agent => 'Wget/1.10.2', # default user agent, required by Oracle
109
+ }.merge( opts )
110
+ Solaris::Util.download!( url, opts )
111
+ end
112
+
113
+ end # Patch
114
+
115
+ end # Solaris
116
+
@@ -0,0 +1,135 @@
1
+
2
+ module Solaris
3
+
4
+ # Class to represent the Oracle patchdiag "database" (file).
5
+ # See the following Oracle support publication for format:
6
+ # https://support.oracle.com/CSP/main/article?cmd=show&type=NOT&doctype=REFERENCE&id=1019527.1
7
+ class Patchdiag
8
+
9
+ require 'date'
10
+
11
+ require 'solaris/exception'
12
+ require 'solaris/patchdiag_entry'
13
+ require 'solaris/util'
14
+
15
+ # Default patchdiag.xref file, as for Patch Check Advanced cache
16
+ DEFAULT_XREF_FILE = '/var/tmp/patchdiag.xref'
17
+
18
+ # URL of latest patchdiag.xref from Oracle.
19
+ DEFAULT_XREF_URL = 'https://getupdates.oracle.com/reports/patchdiag.xref'
20
+
21
+ # An array containing all entries (of class PatchdiagEntry) read
22
+ # from the patchdiag.xref file.
23
+ attr_accessor :entries
24
+
25
+ # Create a new patchdiag database object by reading the given
26
+ # xref file (this may be a filename (string) or a fileish object
27
+ # (File, StringIO)). If no xref file is given then the default
28
+ # is read (/var/tmp/patchdiag.xref); this is the cache file used
29
+ # by Patch Check Advanced (pca).
30
+ def initialize(xref_file=DEFAULT_XREF_FILE)
31
+ xref_file = File.new( xref_file ) if xref_file.is_a?(String)
32
+ @entries = xref_file.
33
+ readlines.
34
+ reject { |line| line =~ /^#|^\s*$/ }. # discard comments, blanks
35
+ map { |line| PatchdiagEntry.new( line ) }
36
+ end
37
+
38
+ # Download the patchdiag database and return it as a string.
39
+ # Note the contents will be returned as a string but not saved
40
+ # to disk unless :to_file or :to_dir are given.
41
+ # For the options hash argument see Solaris::Util.download!
42
+ def Patchdiag.download!(opts={})
43
+ url = opts.delete( :url ) || DEFAULT_XREF_URL
44
+ Util.download!( url, opts )
45
+ end
46
+
47
+ # Open the given optional patchdiag xref file and yield to the optional
48
+ # block.
49
+ def Patchdiag.open(xref_file=DEFAULT_XREF_FILE, &blk)
50
+ patchdiag = Patchdiag.new( xref_file )
51
+ if block_given?
52
+ yield patchdiag
53
+ else
54
+ patchdiag
55
+ end
56
+ end
57
+
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.
61
+ def find(patch)
62
+ patch = Patch.new( patch.to_s )
63
+ property = patch.minor ? :to_s : :major
64
+ comparator = patch.send( property )
65
+ all.select { |pde| pde.patch.send( property ) == comparator }
66
+ end
67
+
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.
71
+ def latest(patch)
72
+ major = Patch.new( patch.to_s ).major
73
+ find( major ).max ||
74
+ raise( Solaris::Patch::NotFound, "Cannot find patch #{patch} in patchdiag.xref" )
75
+ end
76
+
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
95
+ end
96
+
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
119
+
120
+ # Compute the lambda for sorting.
121
+ if order == :ascending
122
+ boat_op = lambda { |x,y| x.send( sort_by ) <=> y.send( sort_by ) }
123
+ else
124
+ boat_op = lambda { |x,y| y.send( sort_by ) <=> x.send( sort_by ) }
125
+ end
126
+
127
+ # Sort and return.
128
+ @entries.sort { |x,y| boat_op.call( x, y ) }
129
+
130
+ end
131
+
132
+ end # Patchdiag
133
+
134
+ end # Solaris
135
+
@@ -0,0 +1,182 @@
1
+
2
+ module Solaris
3
+
4
+ # Class to represent a line from Sun's patchdiag.xref patch "database".
5
+ # See the following Oracle support publication for format:
6
+ # https://support.oracle.com/CSP/main/article?cmd=show&type=NOT&doctype=REFERENCE&id=1019527.1
7
+ class PatchdiagEntry
8
+
9
+ include Comparable
10
+
11
+ require 'date'
12
+
13
+ require 'solaris/exception'
14
+ require 'solaris/patch'
15
+
16
+ # An array of architectures for this patch. Values are strings like
17
+ # "sparc", "i386".
18
+ attr_accessor :archs
19
+
20
+ # The bad field from the patchdiag xref database. Should be either 'B'
21
+ # or the empty string. See also PatchdiagEntry#bad?
22
+ attr_accessor :bad
23
+
24
+ # The date of this patch (a Date object).
25
+ attr_accessor :date
26
+
27
+ # The operating system for this patch, a string like "2.4, "10",
28
+ # "10_x86" or "Unbundled".
29
+ attr_accessor :os
30
+
31
+ # The patch object (class Patch) that this entry represents. See
32
+ # also convenience methods PatchdiagEntry#major and PatchdiagEntry#minor.
33
+ attr_accessor :patch
34
+
35
+ # An array of packages that pertain to this patch. Values are strings
36
+ # like "SUNWcsr".
37
+ attr_accessor :pkgs
38
+
39
+ # The recommended field from the patchdiag xref database. Should be either 'R'
40
+ # or the empty string. See also PatchdiagEntry#recommended?
41
+ attr_accessor :recommended
42
+
43
+ # The security field from the patchdiag xref database. Should be either 'S'
44
+ # or the empty string. See also PatchdiagEntry#security?
45
+ attr_accessor :security
46
+
47
+ # This synopsis of this patch from the patchdiag xref database. This is a free
48
+ # text field (string).
49
+ attr_accessor :synopsis
50
+
51
+ def initialize(patchdiag_line)
52
+ fields = patchdiag_line.split('|')[0..10]
53
+ major, minor, date, @recommended, @security, @obsolete, @bad, @os, archs, pkgs, @synopsis = *fields
54
+ @archs = archs.split( ';' )
55
+ if date == ''
56
+ year, month, day = 1970, 1, 1
57
+ else
58
+ month_s, day_s, year_s = *date.split( '/' )
59
+ year = ( year_s.to_i > 50 ? "19#{year_s}" : "20#{year_s}" ).to_i
60
+ month = Date::ABBR_MONTHNAMES.index( month_s )
61
+ day = day_s.to_i
62
+ end
63
+ @date = Date.new( year, month, day )
64
+ @patch = Patch.new( major, minor )
65
+ @pkgs = pkgs.split( ';' )
66
+ end
67
+
68
+ # Boolean, returns true if this patch is marked as "bad" in the patchdiag
69
+ # xref database.
70
+ def bad? ; @bad == 'B' end
71
+
72
+ # Download this patch. For options hash see Patch#download!.
73
+ def download_patch!(opts={}) ;
74
+ @patch.download_patch!( opts )
75
+ end
76
+
77
+ # Download the README for this patch. For options hash see Patch#download!.
78
+ def download_readme!(opts={})
79
+ @patch.download_readme!( opts )
80
+ end
81
+
82
+ # Returns this entries major patch number as an integer.
83
+ def major ; @patch.major end
84
+
85
+ # Returns this entries minor patch number as an integer.
86
+ def minor ; @patch.minor end
87
+
88
+ # Boolean, returns true if this patch is marked as "obsolete" in the patchdiag
89
+ # xref database.
90
+ def obsolete? ; @obsolete == 'O' end
91
+
92
+ # Boolean, returns true if this patch is marked as "recommended" in the patchdiag
93
+ # xref database.
94
+ def recommended? ; @recommended == 'R' end
95
+
96
+ # Boolean, returns true if this patch is marked as "security" in the patchdiag
97
+ # xref database.
98
+ def security? ; @security == 'S' end
99
+
100
+ # Return the Solaris::Patch by which this entry is obsoleted.
101
+ # Throws Solaris::Patch::NotObsolete if this entry is not obsolete.
102
+ # Throws Solaris::Patch::MultipleSuccessors if this entry has more than
103
+ # one successor.
104
+ # Throws Solaris::Patch::InvalidSuccessor if the "obsoleted by" entry cannot
105
+ # be understood.
106
+ def successor
107
+ # I <3 consistency:
108
+ # Obsoleted by : XXXXXX-XX
109
+ # Obsoleted by: XXXXXX-XX
110
+ # OBSOLETED by: XXXXXX
111
+ # Obsoleted by: XXXXXX-XX OBSOLETED by WITHDRAWN
112
+ # OBSOLETED by WITHDRAWN
113
+ # OBSOLETED by XXXXXX
114
+ # OBSOLETED by XXXXXX and XXXXXX # we ignore this pattern, see below
115
+ # Obsoleted by XXXXXX-XX:
116
+ # OBSOLETED by XXXXXX-XX:
117
+ # WITHDRAWN Obsoleted by: XXXXXX-XX
118
+ # WITHDRAWN PATCH Obsolete by:
119
+ # WITHDRAWN PATCH Obsoleted by:
120
+ # WITHDRAWN PATCH Obsoleted by XXXXXX-XX:
121
+
122
+ # Fail if this entry is not actually obsolete
123
+ raise Solaris::Patch::NotObsolete,
124
+ "Entry #{patch.inspect} not obsolete" unless obsolete?
125
+
126
+ # Fail on these two entries from 1999 since they are the only ones ever
127
+ # that are succeeded by two patches each
128
+ raise Solaris::Patch::MultipleSuccessors,
129
+ "More than one successor for entry #{patch.inspect}" if [ 105716, 105717 ].include?( self.major )
130
+
131
+ # See if we can find a successor
132
+ if synopsis =~ /obsolete(d?) by\s*(:?)\s*(\d+(-\d+)?)/i
133
+ Patch.new( $3 )
134
+ else
135
+ raise Solaris::Patch::InvalidSuccessor,
136
+ "Failed to parse successor to obsolete patchdiag entry for patch #{patch.inspect}"
137
+ end
138
+ end
139
+
140
+ # Output this patchdiag xref entry as a string, in format of Oracle's
141
+ # database.
142
+ def to_s
143
+ [ patch.major,
144
+ Patch.pad_minor( patch.minor ),
145
+ date_s,
146
+ @recommended,
147
+ @security,
148
+ @obsolete,
149
+ @bad,
150
+ @os,
151
+ join_semis( @archs ),
152
+ join_semis( @pkgs ),
153
+ @synopsis
154
+ ].join('|')
155
+ end
156
+
157
+ # Compare (by delegated comparison of patch versions, see Solaris::Patch#<=>).
158
+ def <=>(other)
159
+ self.patch <=> other.patch
160
+ end
161
+
162
+ private
163
+
164
+ # Convert the Date object to a date string as found in patchdiag.xref.
165
+ def date_s
166
+ [ Date::ABBR_MONTHNAMES[ @date.mon ], # month eg Jan
167
+ @date.mday.to_s.rjust(2, '0'), # day of month
168
+ @date.year % 100 # 2 digit year
169
+ ].join('/')
170
+ end
171
+
172
+ # Join an array of items with semicolons and append a trailing
173
+ # semicolon if the array is non-empty, otherwise return the
174
+ # empty string. Used to format @archs and @pkgs for #to_s.
175
+ def join_semis(a)
176
+ a.empty? ? '' : a.join(';') + ';'
177
+ end
178
+
179
+ end # PatchdiagEntry
180
+
181
+ end # Solaris
182
+
@@ -0,0 +1,68 @@
1
+
2
+ module Solaris
3
+
4
+ # Utility module.
5
+ module Util
6
+
7
+ require 'rubygems'
8
+ gem 'mechanize', '>= 1.0.0'
9
+ require 'mechanize'
10
+
11
+ # Download the given URL, return the document body. Options:
12
+ # :agent -- set HTTP user agent
13
+ # :password -- Oracle support password
14
+ # :to_file -- a file path to which the patch/readme should be saved
15
+ # :to_dir -- a directory path to which the patch/readme should be saved
16
+ # :user -- Oracle support username
17
+ # (:to_dir and :to_file are mutually exclusive)
18
+ def Util.download!(url, opts={})
19
+ agent = Mechanize.new
20
+ dirname, filename = nil, nil
21
+ opts.each do |key, value|
22
+ case key
23
+ when :agent
24
+ agent.user_agent = value
25
+ when :to_dir
26
+ dirname = value
27
+ when :to_file
28
+ filename = value
29
+ when :password, :user
30
+ # noop
31
+ else
32
+ raise ArgumentError, "Unknown option key #{key.inspect}"
33
+ end
34
+ end
35
+ # If we got a filename then open now before attempting download
36
+ raise ArgumentError, 'Cannot specify both :to_dir and :to_file' if filename && dirname
37
+ filename = File.join( dirname, File.basename( url ) ) if dirname
38
+ begin
39
+ file = File.open( filename, 'w' ) if filename
40
+ # Set agent authentication parameters
41
+ if opts[:user] && opts[:password]
42
+ agent.basic_auth( opts[:user], opts[:password] )
43
+ elsif opts[:user]
44
+ raise ArgumentError, 'Cannot authenticate without a password'
45
+ elsif opts[:password]
46
+ raise ArgumentError, 'Cannot authenticate without a username'
47
+ end
48
+ # Download file and save as required
49
+ page = agent.get( url )
50
+ if file
51
+ file.write( page.body )
52
+ file.close
53
+ end
54
+ rescue => exception
55
+ # Try to remove incomplete file on error
56
+ if file
57
+ begin file.close ; rescue ; end
58
+ begin File.unlink( file ) ; rescue ; end
59
+ end
60
+ raise exception # rethrow original exception
61
+ end
62
+ page.body # return file as string (even if written)
63
+ end
64
+
65
+ end # Util
66
+
67
+ end # Solaris
68
+
data/lib/solaris.rb ADDED
@@ -0,0 +1,10 @@
1
+
2
+ # Namespace for child classes.
3
+ module Solaris
4
+
5
+ require 'solaris/patch'
6
+ require 'solaris/patchdiag'
7
+ require 'solaris/patchdiag_entry'
8
+
9
+ end # Solaris
10
+
@@ -0,0 +1,100 @@
1
+
2
+ require 'test/unit'
3
+ require 'solaris/patch'
4
+
5
+ # Unit tests for class Patch.
6
+ class TestPatch < Test::Unit::TestCase #:nodoc:
7
+
8
+ def test_new_string_major_only
9
+ patch = Solaris::Patch.new( '123456' )
10
+ assert_equal( 123456, patch.major )
11
+ assert_nil( patch.minor )
12
+ end
13
+
14
+ def test_new_int_major_only
15
+ patch = Solaris::Patch.new( 123456 )
16
+ assert_equal( 123456, patch.major )
17
+ assert_nil( patch.minor )
18
+ end
19
+
20
+ def test_new_string_minor_only
21
+ assert_raise( ArgumentError ) do
22
+ Solaris::Patch.new( '-78' )
23
+ end
24
+ end
25
+
26
+ def test_new_string_major_and_minor
27
+ patch = Solaris::Patch.new( '123456-78' )
28
+ assert_equal( 123456, patch.major )
29
+ assert_equal( 78, patch.minor )
30
+ end
31
+
32
+ def test_new_int_major_and_minor
33
+ patch = Solaris::Patch.new( 123456, 78 )
34
+ assert_equal( 123456, patch.major )
35
+ assert_equal( 78, patch.minor )
36
+ end
37
+
38
+ def test_new_no_args
39
+ patch = Solaris::Patch.new()
40
+ assert_nil( patch.major )
41
+ assert_nil( patch.minor )
42
+ end
43
+
44
+ def test_new_valid_opts
45
+ patch = Solaris::Patch.new( '123456-78' )
46
+ assert_equal( 123456, patch.major )
47
+ assert_equal( 78, patch.minor )
48
+ end
49
+
50
+ def test_to_s
51
+ patch = Solaris::Patch.new( '123456-78' )
52
+ assert_equal( '123456-78', patch.to_s )
53
+ end
54
+
55
+ def test_to_s_padding
56
+ patch = Solaris::Patch.new( '123456-7' )
57
+ assert_equal( '123456-07', patch.to_s )
58
+ end
59
+
60
+ def test_to_s_major_only
61
+ patch = Solaris::Patch.new( 123456 )
62
+ assert_equal( '123456', patch.to_s )
63
+ end
64
+
65
+ def test_comparison
66
+ assert( Solaris::Patch.new( '123456-78' ) == Solaris::Patch.new( '123456-78' ) )
67
+ assert( Solaris::Patch.new( '123456-1' ) == Solaris::Patch.new( '123456-01' ) )
68
+ assert( Solaris::Patch.new( '123456' ) == Solaris::Patch.new( '123456' ) )
69
+ assert( Solaris::Patch.new( '123456-78' ) < Solaris::Patch.new( '123456-79' ) )
70
+ assert( Solaris::Patch.new( '123456-78' ) < Solaris::Patch.new( '123457-78' ) )
71
+ assert( Solaris::Patch.new( '123456-1' ) < Solaris::Patch.new( '123456-10' ) )
72
+ end
73
+
74
+ def test_download_requires_major
75
+ patch = Solaris::Patch.new
76
+ patch.minor = 1
77
+ assert_raise( ArgumentError ) { patch.download_patch! }
78
+ assert_raise( ArgumentError ) { patch.download_readme! }
79
+ end
80
+
81
+ def test_download_requires_minor
82
+ patch = Solaris::Patch.new
83
+ patch.major = 123456
84
+ assert_raise( ArgumentError ) { patch.download_patch! }
85
+ assert_raise( ArgumentError ) { patch.download_readme! }
86
+ end
87
+
88
+ def test_download!
89
+ skip 'Mock required'
90
+ end
91
+
92
+ def test_pad_minor
93
+ assert_equal( '00', Solaris::Patch.pad_minor( 0 ) )
94
+ assert_equal( '01', Solaris::Patch.pad_minor( 1 ) )
95
+ assert_equal( '12', Solaris::Patch.pad_minor( 12 ) )
96
+ assert_equal( '123', Solaris::Patch.pad_minor( 123 ) )
97
+ end
98
+
99
+ end
100
+
@@ -0,0 +1,198 @@
1
+
2
+ require 'test/unit'
3
+ require 'stringio'
4
+ require 'solaris/patchdiag'
5
+
6
+ # Unit tests for class Patchdiag.
7
+ class TestPatchdiag < Test::Unit::TestCase #:nodoc:
8
+
9
+ def setup
10
+ @empty_file = '/dev/null'
11
+ @patchdiag_fileish = StringIO.new(<<-EOF
12
+ ## PATCHDIAG TOOL CROSS-REFERENCE FILE AS OF Feb/10/11 ##
13
+ ##
14
+ ## The content of this file has changed as of Jun/04/10. Due to the merging of
15
+ ## the Sun Alert and Recommended patch clusters, some patches tagged with the
16
+ ## "R" flag may now be obsoleted patches (and as a result additionally have the
17
+ ## "O" flag set).
18
+ ## Details of this change are explained in the following blog posting:
19
+ ## http://blogs.sun.com/patch/entry/merging_the_solaris_recommended_and
20
+ ## The following Technical Info Document explains the various fields in the
21
+ ## patchdiag.xref file:
22
+ ## https://support.oracle.com/CSP/main/article?cmd=show&type=NOT&doctype=REFERENCE&id=1019527.1
23
+ 100287|05|Oct/31/91| | | | |Unbundled|||PC-NFS 3.5c: Jumbo patch (updated PRT.COM to v3.5c)
24
+ 100323|05|Feb/11/92| | | | |Unbundled|||PC-NFS Advanced Telnet: bug fixes, National Character Set support
25
+ 100386|01|Sep/20/91| | | | |Unbundled|||PC-NFS Programmer's Toolkit/2.0: Runtime modules
26
+ 100393|01|Sep/02/94| | |O| |Unbundled|||OBSOLETED by 100394
27
+ 100438|01|Dec/02/91| | | | |Unbundled|||PCNFS/v3.5c: PC-NFS loses mounted printer names when PCNFSLPD load
28
+ 100455|01|Dec/17/91| | | | |Unbundled|||LifeLine/2.0: Does not parse the FROM: and/or Reply-TO: fields cor
29
+ 100648|01|Jun/11/92| | | | |Unbundled|||PC-NFS/4.0a: Jumbo Patch
30
+ 100701|03|Feb/17/93| | | | |Unbundled|sparc;|SUNWowbcp:1.8.1;SUNWowbcp:2.10;|OpenWindows 3.0.1;3.1: programs compiled under Solaris 1.x /usr/5b
31
+ 100791|04|Apr/12/93| | |O| |Unbundled||SPROsw:2.1.0.1;|OBSOLETED by 100974
32
+ 100791|05|Apr/12/93| | |O| |Unbundled||SPROsw:2.1.0.1;|OBSOLETED by 100974
33
+ 100807|03|May/02/94| | |O| B|Unbundled|||OBSOLETED by WITHDRAWN
34
+ 100807|04|Jul/07/94| | | | |Unbundled|sparc;|SPROswmgr:2.1.2.1;|Sparcworks 2.0.1: statically linking X11 library doesn't run on As
35
+ 100811|01|Mar/17/93| | |O| |Unbundled||SPROcpl:2.1.0.3;SPROlang:2.1.0.3;|OBSOLETED by 100967
36
+ 100812|02|Jan/27/93| | | | |Unbundled|sparc;|SUNWowrqd:1.16.2;|OpenWindows 3.0.1: Binder as root with "-system" or "-network" doe
37
+ 100824|03|Jun/29/93| | | | |Unbundled|sparc;|SUNWowrqd:2.10;|OpenWindows 3.1: fixes various bugs in xnews server
38
+ 100830|01|Mar/12/93| | |O| |Unbundled||SPROlang:2.1.0.1;|OBSOLETED by 100861
39
+ 100837|01|Jan/20/93| | | | |Unbundled|sparc;|SUNWowrqd:2.10.0.1;|OpenWindows 3.1: core dump in ras3,ras4,ras5 and install_check on
40
+ 100843|01|Feb/05/93| | | | |Unbundled|||PC-NFS/4.0a: various, system or print server hangs under heavy loa
41
+ 100849|01|Jan/20/93| | |O| |Unbundled||SPROpas:2.1.0.1;|OBSOLETED by 100964
42
+ 100852|02|Jul/01/93| | |O| |2.1||SUNWcsu:11.4.2,PATCH=28;|OBSOLETED by WITHDRAWN
43
+ 146124|01|Dec/08/10| | | | |10|sparc;|SUNWthunderbirdl10n-de-DE:3.0.3,REV=101.0.3;SUNWthunderbirdl10n-es-ES:3.0.3,REV=101.0.3;SUNWthunderbirdl10n-extra:3.0.3,REV=101.0.3;SUNWthunderbirdl10n-fr-FR:3.0.3,REV=101.0.3;SUNWthunderbirdl10n-it-IT:3.0.3,REV=101.0.3;SUNWthunderbirdl10n-ja-JP:3.0.3,REV=101.0.3;SUNWthunderbirdl10n-ko-KR:3.0.3,REV=101.0.3;SUNWthunderbirdl10n-pl-PL:3.0.3,REV=101.0.3;SUNWthunderbirdl10n-pt-BR:3.0.3,REV=101.0.3;SUNWthunderbirdl10n-ru-RU:3.0.3,REV=101.0.3;SUNWthunderbirdl10n-sv-SE:3.0.3,REV=101.0.3;SUNWthunderbirdl10n-zh-CN:3.0.3,REV=101.0.3;SUNWthunderbirdl10n-zh-TW:3.0.3,REV=101.0.3;|SunOS 5.10: Thunderbird l10n packages update Patch
44
+ 146132|01|Jan/05/11| | | | |10|sparc;137137-09;141444-09;|SUNWcsu:11.10.0,REV=2005.01.21.15.53;|SunOS 5.10: newfs fails on newly-formatted floppy disk
45
+ 146133|01|Jan/05/11| | | | |10_x86|i386;137138-09;141445-09;|SUNWcsu:11.10.0,REV=2005.01.21.16.34;|SunOS 5.10_x86: newfs fails on newly-formatted floppy disk
46
+ 146236|01|Dec/10/10| | | | |10|sparc;137137-09;|SUNWckr:11.10.0,REV=2005.01.21.15.53;|SunOS 5.10: dcfs patch
47
+ 146237|01|Dec/10/10| | | | |10_x86|i386;141445-09;|SUNWckr:11.10.0,REV=2005.01.21.16.34;|SunOS 5.10_x86: dcfs patch
48
+ 146241|02|Dec/16/10| | | | |Unbundled|sparc;|SUNWscsaa:3.3.0,REV=2010.07.26.12.56;|Oracle Solaris Cluster 3.3: SWIFTAllianceAccess patch
49
+ 146277|01|Dec/10/10| | | | |10|sparc;118833-36;120011-14;127127-11;139555-08;142909-17;|SUNWcslr:11.10.0,REV=2005.01.21.15.53;|SunOS 5.10: libnsl patch
50
+ 146278|01|Dec/10/10| | | | |10_x86|i386;118855-36;120012-14;127128-11;139556-08;142910-17;|SUNWcslr:11.10.0,REV=2005.01.21.16.34;|SunOS 5.10_x86: libnsl patch
51
+ 146279|01|Dec/22/10|R|S| | |10|sparc;|SUNWbnuu:11.10.0,REV=2005.01.21.15.53;|SunOS 5.10: uucp patch
52
+ 146280|01|Dec/22/10|R|S| | |10_x86|i386;|SUNWbnuu:11.10.0,REV=2005.01.21.16.34;|SunOS 5.10_x86: uucp patch
53
+ 146281|01|Dec/15/10| | | | |10|sparc;|SUNWckr:11.10.0,REV=2005.01.21.15.53;SUNWhea:11.10.0,REV=2005.01.21.15.53;|SunOS 5.10: ldterm patch
54
+ 146282|01|Dec/15/10| | | | |10_x86|i386;|SUNWckr:11.10.0,REV=2005.01.21.16.34;SUNWhea:11.10.0,REV=2005.01.21.16.34;|SunOS 5.10_x86: ldterm patch
55
+ 146283|01|Dec/10/10| | | | |10|sparc;118833-36;137137-09;142909-17;|SUNWckr:11.10.0,REV=2005.01.21.15.53;|SunOS 5.10: lofi patch
56
+ 146284|01|Dec/10/10| | | | |10_x86|i386;118855-36;137138-09;142910-17;|SUNWckr:11.10.0,REV=2005.01.21.16.34;|SunOS 5.10_x86: lofi patch
57
+ 146287|01|Jan/24/11| | | | |10|sparc.sun4u;sparc.sun4us;sparc.sun4v;118833-36;120011-14;|SUNWkvm:11.10.0,REV=2005.01.20.17.25;SUNWkvm:11.10.0,REV=2005.01.21.15.53;SUNWkvm:11.10.0,REV=2005.08.04.12.25;|SunOS 5.10: trapstat Patch
58
+ 146332|02|Feb/03/11| | | | |10|sparc;142909-17;|SUNWaccu:11.10.0,REV=2005.01.21.15.53;|SunOS 5.10: sadc patch
59
+ 146333|02|Feb/03/11| | | | |10_x86|i386;142910-17;|SUNWaccu:11.10.0,REV=2005.01.21.16.34;|SunOS 5.10_x86: sadc patch
60
+ 146334|01|Jan/19/11| | | | |10|sparc;120011-14;121133-02;127127-11;139555-08;142909-17;|SUNWzoneu:11.10.0,REV=2005.01.21.15.53;|SunOS 5.10: zlogin patch
61
+ 146335|01|Jan/19/11| | | | |10_x86|i386;120012-14;121334-04;127128-11;139556-08;142910-17;|SUNWzoneu:11.10.0,REV=2005.01.21.16.34;|SunOS 5.10_x86: zlogin patch
62
+ 146336|01|Jan/13/11| | | | |10|sparc;118833-36;120011-14;127127-11;137137-09;142909-17;|SUNWarc:11.10.0,REV=2005.01.21.15.53;SUNWcsl:11.10.0,REV=2005.01.21.15.53;|SunOS 5.10: libsldap.so.1 patch
63
+ 146337|01|Jan/13/11| | | | |10_x86|i386;120012-14;127128-11;137138-09;142910-17;|SUNWarc:11.10.0,REV=2005.01.21.16.34;SUNWcsl:11.10.0,REV=2005.01.21.16.34;|SunOS 5.10_x86: libsldap.so.1 patch
64
+ 146363|01|Jan/04/11|R|S| | |10|sparc;119757-19;|SUNWsfman:11.10.0,REV=2005.01.08.05.16;SUNWsmbaS:11.10.0,REV=2005.01.08.05.16;SUNWsmbar:11.10.0,REV=2005.01.08.05.16;SUNWsmbau:11.10.0,REV=2005.01.08.05.16;|SunOS 5.10: Samba patch
65
+ 146364|01|Jan/04/11|R|S| | |10_x86|i386;119758-19;|SUNWsfman:11.10.0,REV=2005.01.08.01.09;SUNWsmbaS:11.10.0,REV=2005.01.08.01.09;SUNWsmbar:11.10.0,REV=2005.01.08.01.09;SUNWsmbau:11.10.0,REV=2005.01.08.01.09;|SunOS 5.10_x86: Samba patch
66
+ 146435|01|Feb/01/11| | | | |Unbundled|||Hardware FC Disk Drive Patch : Download program and FC Disk Drive
67
+ 146440|01|Jan/13/11| | | | |10|sparc;118833-36;120011-14;137137-09;139555-08;141444-09;142909-17;|SUNWckr:11.10.0,REV=2005.01.21.15.53;|SunOS 5.10: dld patch
68
+ 146441|01|Jan/13/11| | | | |10_x86|i386;118855-36;120012-14;139556-08;141445-09;142910-17;|SUNWckr:11.10.0,REV=2005.01.21.16.34;|SunOS 5.10_x86: dld patch
69
+ 146442|01|Jan/24/11| | | | |10|sparc;126897-02;127127-11;127755-01;137137-09;139555-08;141444-09;142909-17;|SUNWfmd:11.10.0,REV=2005.01.21.15.53;|SunOS 5.10: libldom.so.1 patch
70
+ 146443|01|Feb/09/11| | | | |10|sparc;142909-17;|SUNWfmd:11.10.0,REV=2005.01.21.15.53;|SunOS 5.10: gmem.eft and generic-mem.so patch
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
+ 800054|01|Mar/16/01| | |O| |Unbundled|||Obsoleted by: 111346-01 Hardware/PROM: Sun Fire 3800/4800/4810/680
73
+ 100974|02|Mar/14/95| | | | |Unbundled|sparc;|SPROsw:2.1.0;|SparcWorks 2.0.1: dbx jumbo patch
74
+ EOF
75
+ )
76
+ @patchdiag = Solaris::Patchdiag.open( @patchdiag_fileish )
77
+ end
78
+
79
+ def teardown
80
+ @empty_file = nil
81
+ @patchdiag = nil
82
+ @patchdiag_fileish = nil
83
+ end
84
+
85
+ def test_new_by_fileish
86
+ assert_equal( 51, @patchdiag.entries.size )
87
+ end
88
+
89
+ def test_new_by_filename
90
+ temp = Tempfile.new( 'test_patchdiag' )
91
+ path = temp.path
92
+ temp.write( @patchdiag_fileish )
93
+ temp.close
94
+ patchdiag = Solaris::Patchdiag.new( path )
95
+ File.unlink( path )
96
+ assert_equal( 51, @patchdiag.entries.size )
97
+ end
98
+
99
+ def test_new_empty_file
100
+ if File.exists?( @empty_file )
101
+ patchdiag = Solaris::Patchdiag.new( @empty_file )
102
+ assert_equal( 0, patchdiag.entries.size )
103
+ end
104
+ end
105
+
106
+ def test_all
107
+ assert_equal( 51, @patchdiag.all.size )
108
+ end
109
+
110
+ def test_all_sort_by_date_order_ascending
111
+ all = @patchdiag.all( :sort_by => :date, :order => :ascending )
112
+ first = all.first.patch # oldest
113
+ last = all.last.patch # newest
114
+ assert_equal( Solaris::Patch.new( '100386-01' ), first )
115
+ assert_equal( Solaris::Patch.new( '146443-01' ), last )
116
+ end
117
+
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 )
124
+ end
125
+
126
+ def test_open_block
127
+ ret = Solaris::Patchdiag.open( @patchdiag_fileish ) do |patchdiag|
128
+ assert_equal( Solaris::Patchdiag, patchdiag.class )
129
+ :return_code
130
+ end
131
+ assert_equal( :return_code, ret )
132
+ end
133
+
134
+ def test_open_return
135
+ assert_equal( Solaris::Patchdiag, @patchdiag.class )
136
+ end
137
+
138
+ def test_find
139
+ assert_equal( [], @patchdiag.find( 123456 ) )
140
+ assert_equal( [], @patchdiag.find( '123456' ) )
141
+ assert_equal( [], @patchdiag.find( '123456-78' ) )
142
+ assert_equal( [], @patchdiag.find( Solaris::Patch.new( 123456 ) ) )
143
+ assert_equal( [], @patchdiag.find( Solaris::Patch.new( '123456' ) ) )
144
+ assert_equal( [], @patchdiag.find( Solaris::Patch.new( '123456-78' ) ) )
145
+ assert_equal( [], @patchdiag.find( '100791-01' ) )
146
+ assert_equal( [], @patchdiag.find( Solaris::Patch.new( '100791-01' ) ) )
147
+ assert_equal( '100791-04', @patchdiag.find( 100791 ).first.patch.to_s )
148
+ assert_equal( '100791-04', @patchdiag.find( '100791' ).first.patch.to_s )
149
+ assert_equal( '100791-04', @patchdiag.find( '100791-04' ).first.patch.to_s )
150
+ assert_equal( '100791-04', @patchdiag.find( Solaris::Patch.new( 100791) ).first.patch.to_s )
151
+ assert_equal( '100791-04', @patchdiag.find( Solaris::Patch.new( '100791') ).first.patch.to_s )
152
+ assert_equal( '100791-04', @patchdiag.find( Solaris::Patch.new( '100791-04') ).first.patch.to_s )
153
+ end
154
+
155
+ def test_latest
156
+ assert_raise( Solaris::Patch::NotFound ) do
157
+ @patchdiag.latest( 123456 )
158
+ end
159
+ assert_equal( '100791-05', @patchdiag.latest( 100791 ).patch.to_s )
160
+ assert_equal( '100791-05', @patchdiag.latest( '100791' ).patch.to_s )
161
+ assert_equal( '100791-05', @patchdiag.latest( '100791-01' ).patch.to_s )
162
+ assert_equal( '100791-05', @patchdiag.latest( '100791-05' ).patch.to_s )
163
+ assert_equal( '100791-05', @patchdiag.latest( Solaris::Patch.new( 100791 ) ).patch.to_s )
164
+ assert_equal( '100791-05', @patchdiag.latest( Solaris::Patch.new( '100791' ) ).patch.to_s )
165
+ assert_equal( '100791-05', @patchdiag.latest( Solaris::Patch.new( '100791-01' ) ).patch.to_s )
166
+ assert_equal( '100791-05', @patchdiag.latest( Solaris::Patch.new( '100791-05' ) ).patch.to_s )
167
+ end
168
+
169
+ def test_successor
170
+ assert_raise( Solaris::Patch::NotFound ) do
171
+ @patchdiag.latest( 123456 )
172
+ end
173
+ assert_equal( '100287-05', @patchdiag.successor( 100287 ).patch.to_s )
174
+ assert_equal( '100287-05', @patchdiag.successor( '100287' ).patch.to_s )
175
+ assert_equal( '100287-05', @patchdiag.successor( '100287-05' ).patch.to_s )
176
+ assert_equal( '100287-05', @patchdiag.successor( Solaris::Patch.new( '100287-05' ) ).patch.to_s )
177
+ assert_equal( '100974-02', @patchdiag.successor( 100791 ).patch.to_s )
178
+ assert_raise( Solaris::Patch::NotFound ) do
179
+ @patchdiag.successor( 100393 ) # successor 100394 not in patchdiag.xref
180
+ end
181
+ assert_equal( '100807-04', @patchdiag.successor( '100807-01' ).patch.to_s )
182
+ assert_raise( Solaris::Patch::InvalidSuccessor ) do
183
+ @patchdiag.successor( '100807-03' ) # successor 100807-03 WITHDRAWN
184
+ end
185
+ end
186
+
187
+ def test_download!
188
+ skip 'Mock required'
189
+ end
190
+
191
+ private
192
+
193
+ def successor(patch)
194
+ @patchdiag.successor( patch ).patch.to_s
195
+ end
196
+
197
+ end
198
+
@@ -0,0 +1,115 @@
1
+
2
+ require 'test/unit'
3
+ require 'solaris/patchdiag_entry'
4
+
5
+ # Unit tests for class PatchdiagEntry.
6
+ class TestPatchdiagEntry < Test::Unit::TestCase #:nodoc:
7
+
8
+ def test_146636_01
9
+ line = '146336|01|Jan/13/11| | | | |10|sparc;118833-36;120011-14;127127-11;137137-09;142909-17;|SUNWarc:11.10.0,REV=2005.01.21.15.53;SUNWcsl:11.10.0,REV=2005.01.21.15.53;|SunOS 5.10: libsldap.so.1 patch'
10
+ pde = Solaris::PatchdiagEntry.new( line )
11
+ assert_equal( 146336, pde.major )
12
+ assert_equal( 1, pde.minor )
13
+ assert_equal( false, pde.recommended? )
14
+ assert_equal( false, pde.obsolete? )
15
+ assert_equal( false, pde.security? )
16
+ assert_equal( Date.new(2011, 1, 13), pde.date )
17
+ assert_equal( '10', pde.os )
18
+ assert_equal( '146336-01', pde.patch.to_s )
19
+ assert_equal( ['SUNWarc:11.10.0,REV=2005.01.21.15.53',
20
+ 'SUNWcsl:11.10.0,REV=2005.01.21.15.53'], pde.pkgs )
21
+ assert_equal( [ 'sparc', '118833-36', '120011-14', '127127-11', '137137-09', '142909-17' ], pde.archs )
22
+ assert_equal( 'SunOS 5.10: libsldap.so.1 patch', pde.synopsis )
23
+ assert_equal( line, pde.to_s )
24
+ end
25
+
26
+ def test_100393_01
27
+ line = '100393|01|Sep/02/94| | |O| |Unbundled|||OBSOLETED by 100394'
28
+ pde = Solaris::PatchdiagEntry.new( line )
29
+ assert_equal( 100393, pde.major )
30
+ assert_equal( 1, pde.minor )
31
+ assert_equal( false, pde.recommended? )
32
+ assert_equal( true, pde.obsolete? )
33
+ assert_equal( false, pde.security? )
34
+ assert_equal( Date.new(1994, 9, 2), pde.date )
35
+ assert_equal( 'Unbundled', pde.os )
36
+ assert_equal( '100393-01', pde.patch.to_s )
37
+ assert_equal( [], pde.pkgs )
38
+ assert_equal( [], pde.archs )
39
+ assert_equal( 'OBSOLETED by 100394', pde.synopsis )
40
+ assert_equal( line, pde.to_s )
41
+ end
42
+
43
+ def test_146364_01
44
+ line = '146364|01|Jan/04/11|R|S| | |10_x86|i386;119758-19;|SUNWsfman:11.10.0,REV=2005.01.08.01.09;SUNWsmbaS:11.10.0,REV=2005.01.08.01.09;SUNWsmbar:11.10.0,REV=2005.01.08.01.09;SUNWsmbau:11.10.0,REV=2005.01.08.01.09;|SunOS 5.10_x86: Samba patch'
45
+ pde = Solaris::PatchdiagEntry.new( line )
46
+ assert_equal( 146364, pde.major )
47
+ assert_equal( 1, pde.minor )
48
+ assert_equal( true, pde.recommended? )
49
+ assert_equal( false, pde.obsolete? )
50
+ assert_equal( true, pde.security? )
51
+ assert_equal( Date.new(2011, 1, 4), pde.date )
52
+ assert_equal( '10_x86', pde.os )
53
+ assert_equal( '146364-01', pde.patch.to_s )
54
+ assert_equal( ['SUNWsfman:11.10.0,REV=2005.01.08.01.09',
55
+ 'SUNWsmbaS:11.10.0,REV=2005.01.08.01.09',
56
+ 'SUNWsmbar:11.10.0,REV=2005.01.08.01.09',
57
+ 'SUNWsmbau:11.10.0,REV=2005.01.08.01.09'],
58
+ pde.pkgs )
59
+ assert_equal( ['i386', '119758-19'], pde.archs )
60
+ assert_equal( 'SunOS 5.10_x86: Samba patch', pde.synopsis )
61
+ assert_equal( line, pde.to_s )
62
+ end
63
+
64
+ def test_compare_equal
65
+ line = '100393|01|Sep/02/94| | |O| |Unbundled|||OBSOLETED by 100394'
66
+ assert_equal(Solaris::PatchdiagEntry.new( line ),
67
+ Solaris::PatchdiagEntry.new( line ))
68
+ end
69
+
70
+ def test_compare_less_than
71
+ line1 = '100393|01|Sep/02/94| | |O| |Unbundled|||OBSOLETED by 100394'
72
+ line2 = '146364|01|Jan/04/11|R|S| | |10_x86|i386;119758-19;|SUNWsfman:11.10.0,REV=2005.01.08.01.09;SUNWsmbaS:11.10.0,REV=2005.01.08.01.09;SUNWsmbar:11.10.0,REV=2005.01.08.01.09;SUNWsmbau:11.10.0,REV=2005.01.08.01.09;|SunOS 5.10_x86: Samba patch'
73
+ assert( Solaris::PatchdiagEntry.new( line1 ) < Solaris::PatchdiagEntry.new( line2 ) )
74
+ end
75
+
76
+ def test_successor
77
+ assert_raise( Solaris::Patch::NotObsolete ) do
78
+ successor( '100287|05|Oct/31/91| | | | |Unbundled|||PC-NFS 3.5c: Jumbo patch (updated PRT.COM to v3.5c)' )
79
+ end
80
+ assert_equal( '110258-01', successor( '109687|01|Aug/11/00| | |O| |Unbundled|sparc;|VRTSvxvm:3.0.4,REV=04.18.2000.10.00;|Obsoleted by : 110258-01 VxVM 3.0.4: vxio and vxdmp driver patch' ) )
81
+ assert_equal( '101318-94', successor( '101859|01|Feb/06/01| | |O| |2.3|sparc;|SUNWcsr:11.5.0,REV=2.0.19,PATCH=118;|Obsoleted by: 101318-94 SunOS 5.3: socket lib in 2.3/2.2 have prob' ) )
82
+ assert_equal( '106542', successor( '107440|01|Mar/26/99| | |O| |7_x86||SUNWcar:11.7.0,REV=1998.09.01.04.53;|OBSOLETED by: 106542 SunOS 5.7_x86: /platform/i86pc/kernel/mmu/mm' ) )
83
+ assert_equal( '109212-02', successor( '108191|01|Sep/07/99| | |O| B|Unbundled|||Obsoleted by: 109212-02 OBSOLETED by WITHDRAWN' ) )
84
+ assert_raise( Solaris::Patch::InvalidSuccessor ) do
85
+ successor( '100807|03|May/02/94| | |O| B|Unbundled|||OBSOLETED by WITHDRAWN' )
86
+ end
87
+ assert_equal( '100394', successor( '100393|01|Sep/02/94| | |O| |Unbundled|||OBSOLETED by 100394' ) )
88
+ assert_raise( Solaris::Patch::MultipleSuccessors ) do
89
+ successor( '105716|07|Jun/30/99| |S|O| |Unbundled||SUNWdtbas:1.0.2,REV=10.96.04.12;|OBSOLETED by 108363 and 108289' )
90
+ end
91
+ assert_raise( Solaris::Patch::MultipleSuccessors ) do
92
+ successor( '105717|06|Jun/30/99| |S|O| |Unbundled||SUNWdtbas:1.0.2,REV=10.96.04.12;|OBSOLETED by 108290 and 108364' )
93
+ end
94
+ assert_equal( '110256-01', successor( '109685|02|Feb/09/01| | |O| |Unbundled|sparc;|VRTSvxvm:3.0.4,REV=04.18.2000.10.00;|Obsoleted by 110256-01: VxVM 3.0.4: vxio and vxdmp driver patch' ) )
95
+ assert_equal( '110257-01', successor( '109686|02|Feb/09/01| | |O| |Unbundled|sparc;|VRTSvxvm:3.0.4,REV=04.18.2000.10.00;|OBSOLETED by 110257-01: VxVM 3.0.4: vxio and vxdmp driver patch' ) )
96
+ assert_equal( '106513-07', successor( '106513|06|Oct/03/00| | |O| B|Unbundled|sparc;|SUNWosafw:6.01,REV=01.11;SUNWosau:6.01,REV=01.11;108555-02;|WITHDRAWN Obsoleted by: 106513-07 RM 6.1.1: generic Raid Manager 6' ) )
97
+ assert_raise( Solaris::Patch::InvalidSuccessor ) do
98
+ # NB fudged the obsolete flag here
99
+ successor( '111442|01|May/04/01| | |O| B|2.5.1|sparc;sparc.sun4c;sparc.sun4d;sparc.sun4m;sparc.sun4u;sparc.sun4u1;103640-35;|SUNWcar:11.5.1,REV=96.05.02.21.09;SUNWcar:11.5.1,REV=97.02.21.21.14;SUNWcsr:11.5.1,REV=96.05.02.21.09;103640-36;|WITHDRAWN PATCH Obsolete by: <INTEGRATION> SunOS 5.5.1: Supplement' )
100
+ end
101
+ assert_equal( '103901-08', successor( '103901|07|Aug/05/97| |S|O| B|2.5.1|||WITHDRAWN PATCH Obsoleted by: 103901-08 OpenWindows 3.5.1: Xview P' ) )
102
+ assert_raise( Solaris::Patch::InvalidSuccessor ) do
103
+ # NB fudged the obsolete flag here
104
+ successor( '111433|02|Jun/04/01| | |O| B|8|sparc;sparc.sun4d;sparc.sun4m;sparc.sun4u;sparc.sun4us;108528-08;|FJSVhea:1.0,REV=1999.12.23.19.10;SUNWcar:11.8.0,REV=2000.01.08.18.12;SUNWcar:11.8.0,REV=2000.01.13.13.40;SUNWcarx:11.8.0,REV=2000.01.08.18.12;SUNWcarx:11.8.0,REV=2000.01.13.13.40;SUNWcsr:11.8.0,REV=2000.01.08.18.12;SUNWhea:11.8.0,REV=2000.01.08.18.12;108528-09;|WITHDRAWN PATCH Obsoleted by: <Integration> SunOS 5.8: Supplementa' )
105
+ end
106
+ end
107
+
108
+ private
109
+
110
+ def successor(line)
111
+ Solaris::PatchdiagEntry.new( line ).successor.to_s
112
+ end
113
+
114
+ end
115
+
@@ -0,0 +1,29 @@
1
+
2
+ require 'test/unit'
3
+ require 'solaris'
4
+
5
+ # Unit tests for top level require.
6
+ class TestSolaris < Test::Unit::TestCase #:nodoc:
7
+
8
+ def test_solaris
9
+ assert_nothing_raised { Solaris }
10
+ end
11
+
12
+ def test_solaris_patch
13
+ assert_nothing_raised { Solaris::Patch }
14
+ end
15
+
16
+ def test_solaris_patchdiag
17
+ assert_nothing_raised { Solaris::Patchdiag }
18
+ end
19
+
20
+ def test_solaris_patchdiag_entry
21
+ assert_nothing_raised { Solaris::PatchdiagEntry }
22
+ end
23
+
24
+ def test_test
25
+ assert_raise( NameError ) { Solaris::DoesNotExist }
26
+ end
27
+
28
+ end
29
+
data/test/test_util.rb ADDED
@@ -0,0 +1,31 @@
1
+
2
+ require 'test/unit'
3
+ require 'solaris/util'
4
+
5
+ # Unit tests for utility module.
6
+ class TestUtil < Test::Unit::TestCase #:nodoc:
7
+
8
+ def test_to_dir_to_file_mutually_exclusive
9
+ assert_raise( ArgumentError ) do
10
+ Solaris::Util.download!('http://example.com',
11
+ :to_dir => 'dir',
12
+ :to_file => 'file')
13
+ end
14
+ end
15
+
16
+ def test_user_without_password
17
+ assert_raise( ArgumentError ) do
18
+ Solaris::Util.download!('http://example.com',
19
+ :user => 'user')
20
+ end
21
+ end
22
+
23
+ def test_password_without_user
24
+ assert_raise( ArgumentError ) do
25
+ Solaris::Util.download!('http://example.com',
26
+ :password => 'password')
27
+ end
28
+ end
29
+
30
+ end
31
+
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: solaris-patch
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 0
9
+ version: 1.0.0
10
+ platform: ruby
11
+ authors:
12
+ - Martin Carpenter
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-05-03 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: mechanize
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 1
30
+ - 0
31
+ - 0
32
+ version: 1.0.0
33
+ type: :runtime
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
36
+ email: mcarpenter@free.fr
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - LICENSE
43
+ - Rakefile
44
+ - README.rdoc
45
+ files:
46
+ - lib/solaris/exception.rb
47
+ - lib/solaris/patch.rb
48
+ - lib/solaris/foo
49
+ - lib/solaris/patchdiag_entry.rb
50
+ - lib/solaris/util.rb
51
+ - lib/solaris/patchdiag.rb
52
+ - lib/solaris.rb
53
+ - test/test_patchdiag_entry.rb
54
+ - test/test_patch.rb
55
+ - test/test_util.rb
56
+ - test/test_solaris.rb
57
+ - test/test_patchdiag.rb
58
+ - LICENSE
59
+ - Rakefile
60
+ - README.rdoc
61
+ has_rdoc: true
62
+ homepage: http://mcarpenter.org/projects/solaris-patch
63
+ licenses:
64
+ - BSD
65
+ post_install_message:
66
+ rdoc_options: []
67
+
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ segments:
76
+ - 0
77
+ version: "0"
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ segments:
84
+ - 0
85
+ version: "0"
86
+ requirements: []
87
+
88
+ rubyforge_project:
89
+ rubygems_version: 1.3.7
90
+ signing_key:
91
+ specification_version: 3
92
+ summary: Facilitate the manipulation of Solaris patches
93
+ test_files:
94
+ - test/test_patchdiag_entry.rb
95
+ - test/test_patch.rb
96
+ - test/test_util.rb
97
+ - test/test_solaris.rb
98
+ - test/test_patchdiag.rb