class Solaris::Patchdiag

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

Constants

DEFAULT_XREF_FILE

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

DEFAULT_XREF_URL

URL of latest patchdiag.xref from Oracle.

Attributes

date[W]

The date of this patchdiag.xref, parsed from the header.

header[RW]

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

Public Class Methods

download!(opts={}) click to toggle source

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!

# File lib/solaris/patchdiag.rb, line 52
def Patchdiag.download!(opts={})
  url = opts.delete(:url) || DEFAULT_XREF_URL
  Util.download!(url, opts)
end
new(xref_file=DEFAULT_XREF_FILE) click to toggle source

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).

# 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
open(xref_file=DEFAULT_XREF_FILE) { |patchdiag| ... } click to toggle source

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

# 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

Public Instance Methods

clone() click to toggle source

Create and return a deep copy of this object.

# File lib/solaris/patchdiag.rb, line 69
def clone
  Marshal.load(Marshal.dump(self))
end
date() click to toggle source

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

# 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
each(&blk) click to toggle source

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

# File lib/solaris/patchdiag.rb, line 82
def each(&blk)
  @entries.each(&blk)
end
find(patch) click to toggle source

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.

# 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
last() click to toggle source

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

# File lib/solaris/patchdiag.rb, line 103
def last
  @entries.last
end
latest(patch) click to toggle source

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.

# 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) click to toggle source

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

# File lib/solaris/patchdiag.rb, line 121
def sort(&blk)
  clone.sort!(&blk)
end
sort!(&blk) click to toggle source

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

# File lib/solaris/patchdiag.rb, line 127
def sort!(&blk)
  # use @entries since #entries returns a copy
  @entries.sort!(&blk)
  self
end
successor(patch) click to toggle source

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

# File lib/solaris/patchdiag.rb, line 172
def successor(patch)
  latest(successors(patch).last)
end
successors(patch, ancestors=[]) click to toggle source

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.

# 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_s() click to toggle source

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

# File lib/solaris/patchdiag.rb, line 178
def to_s
  (@header + @entries + @footer).join("\n") << "\n"
end
Also aliased as: to_str
to_str()
Alias for: to_s