Class: Solaris::Patchdiag

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/solaris/patchdiag.rb

Overview

Class to represent the Oracle patchdiag “database” (file). See the following Oracle support publication for format: support.oracle.com/CSP/main/article?cmd=show&type=NOT&doctype=REFERENCE&id=1019527.1

Constant Summary collapse

DEFAULT_XREF_FILE =

Default patchdiag.xref file, as for Patch Check Advanced cache

'/var/tmp/patchdiag.xref'
DEFAULT_XREF_URL =

URL of latest patchdiag.xref from Oracle.

'https://getupdates.oracle.com/reports/patchdiag.xref'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(xref_file = DEFAULT_XREF_FILE) ⇒ Patchdiag

Create a new patchdiag database object by reading the given xref file (this may be a filename (string) or a fileish object (File, StringIO)). If no xref file is given then the default is read (/var/tmp/patchdiag.xref); this is the cache file used by Patch Check Advanced (pca).



36
37
38
39
40
41
42
43
44
45
46
# File 'lib/solaris/patchdiag.rb', line 36

def initialize(xref_file=DEFAULT_XREF_FILE)
  xref_file = File.new(xref_file) if xref_file.is_a?(String)
  @entries, @header, @footer = [], [], []
  xref_file.each_line do |line|
    if line =~ /^\d/
      @entries << PatchdiagEntry.new(line)
    else
      (@entries.empty? ? @header : @footer) << line.chomp
    end
  end
end

Instance Attribute Details

#dateObject

Return the date parsed from the patchdiag.xref comment lines.



74
75
76
77
78
# File 'lib/solaris/patchdiag.rb', line 74

def date
  ## PATCHDIAG TOOL CROSS-REFERENCE FILE AS OF Jan/23/14 ##
  @date ||= @header.find { |line| line =~ /\s(\w\w\w\/\d\d\/\d\d)\s/ } &&
    Date.parse($1)
end

The array of lines that comprise the footer, sans trailing newline.



29
30
31
# File 'lib/solaris/patchdiag.rb', line 29

def footer
  @footer
end

#headerObject

The array of lines that comprise the header, sans trailing newline.



26
27
28
# File 'lib/solaris/patchdiag.rb', line 26

def header
  @header
end

Class Method Details

.download!(opts = {}) ⇒ Object

Download the patchdiag database and return it as a string. Note the contents will be returned as a string but not saved to disk unless :to_file or :to_dir are given. For the options hash argument see Solaris::Util.download!



52
53
54
55
# File 'lib/solaris/patchdiag.rb', line 52

def Patchdiag.download!(opts={})
  url = opts.delete(:url) || DEFAULT_XREF_URL
  Util.download!(url, opts)
end

.open(xref_file = DEFAULT_XREF_FILE, &blk) ⇒ Object

Open the given optional patchdiag xref file and yield to the optional block.



59
60
61
62
63
64
65
66
# File 'lib/solaris/patchdiag.rb', line 59

def Patchdiag.open(xref_file=DEFAULT_XREF_FILE, &blk)
  patchdiag = Patchdiag.new(xref_file)
  if block_given?
    yield patchdiag
  else
    patchdiag
  end
end

Instance Method Details

#cloneObject

Create and return a deep copy of this object.



69
70
71
# File 'lib/solaris/patchdiag.rb', line 69

def clone
  Marshal.load(Marshal.dump(self))
end

#each(&blk) ⇒ Object

For Enumerator module: yields each Solaris::PatchdiagEntry in turn.



82
83
84
# File 'lib/solaris/patchdiag.rb', line 82

def each(&blk)
  @entries.each(&blk)
end

#find(patch) ⇒ Object

Returns an array of Solaris::PatchdiagEntry from the patchdiag.xref with the given patch number (a String like xxxxxx-yy or xxxxxx or a Solaris::Patch), sorted by minor number. If both a major and minor number are supplied (xxxxxx-yy) then returned entries (normally only one) will match exactly. If only a major number (xxxxxx) is supplied then all entries with that major number are returned. Returns an empty array if no such patches can be found. This method overrides Enumerable#find.



94
95
96
97
98
99
# File 'lib/solaris/patchdiag.rb', line 94

def find(patch)
  patch = Patch.new(patch.to_s)
  property = patch.minor ? :to_s : :major
  comparator = patch.send(property)
  @entries.select { |pde| pde.patch.send(property) == comparator }
end

#lastObject

Strangely Enumerable module does not define Enumerable#last (although it does define Enumerable#first) so we define last here.



103
104
105
# File 'lib/solaris/patchdiag.rb', line 103

def last
  @entries.last
end

#latest(patch) ⇒ Object

Return the Solaris::PatchdiagEntry of the latest version of the given patch (a String like xxxxxx-yy or xxxxxx or a Solaris::Patch). Throws Solaris::Patch::NotFound if the patch cannot be found in patchdiag.xref.



111
112
113
114
115
116
# File 'lib/solaris/patchdiag.rb', line 111

def latest(patch)
  major = Patch.new(patch.to_s).major
  find(major).max ||
    raise(Solaris::Patch::NotFound,
          "Cannot find patch #{patch} in patchdiag.xref")
end

#sort(&blk) ⇒ Object

Returns a (deep) copy of self with the entries sorted, takes an optional block. This method overrides Enumerable#sort. See also Solaris::Patchdiag#sort!.



121
122
123
# File 'lib/solaris/patchdiag.rb', line 121

def sort(&blk)
  clone.sort!(&blk)
end

#sort!(&blk) ⇒ Object

Returns self with the entries sorted in place, takes an optional block. See also Solaris::Patchdiag#sort.



127
128
129
130
131
# File 'lib/solaris/patchdiag.rb', line 127

def sort!(&blk)
  # use @entries since #entries returns a copy
  @entries.sort!(&blk)
  self
end

#successor(patch) ⇒ Object

Return the Solaris::PatchdiagEntry of the latest non-obsolete successor of this patch. This is a convenience method for #successors.last.



172
173
174
# File 'lib/solaris/patchdiag.rb', line 172

def successor(patch)
  latest(successors(patch).last)
end

#successors(patch, ancestors = []) ⇒ Object

Return an array of Solaris::Patch of the successors to the given patch terminating in the latest non-obsolete successor (where that exists).

Throws Solaris::Patch::NotFound if the patch or any of its named successors cannot be found in patchdiag.xref, or if no later version of the patch exists.

Throws Solaris::Patch::SuccessorLoop if the successor of a patch refers to a patch that has already been referenced (an ancestor).

The ancestors parameter is a recursion accumulator and should not normally be assigned to by callers.



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/solaris/patchdiag.rb', line 146

def successors(patch, ancestors=[])
  patch = Patch.new(patch.to_s)
  raise Solaris::Patch::SuccessorLoop,
    "Loop detected for patch #{patch} with ancestors #{ancestors.inspect}" if ancestors.include?(patch)
  ancestors << patch
  if ! patch.minor # patch has no minor number
    successors(latest(patch).patch, ancestors)
  elsif ! entry = find(patch).last # explicit patch not found
    latest_patch = latest(patch).patch
    raise Solaris::Patch::NotFound,
      "Patch #{patch} not found and has no later version" if latest_patch.minor <= patch.minor
    successors(latest_patch, ancestors)
  else
    if entry.obsolete?
      succ = entry.successor
      successors(succ, ancestors)
    elsif entry.bad?
      raise BadSuccessor, "Terminal successor #{patch} is bad/withdrawn"
    else
      ancestors
    end
  end
end

#to_sObject Also known as: to_str

Returns a string representation of the patchdiag.xref. All comments and blank lines are elided.



178
179
180
# File 'lib/solaris/patchdiag.rb', line 178

def to_s
  (@header + @entries + @footer).join("\n") << "\n"
end