class Chef::Provider::Package::Yum::RPMUtils

Public Class Methods

isalnum(x) click to toggle source

verify

# File lib/chef/provider/package/yum/rpm_utils.rb, line 75
def isalnum(x)
  isalpha(x) || isdigit(x)
end
isalpha(x) click to toggle source
# File lib/chef/provider/package/yum/rpm_utils.rb, line 79
def isalpha(x)
  v = x.ord
  (v >= 65 && v <= 90) || (v >= 97 && v <= 122)
end
isdigit(x) click to toggle source
# File lib/chef/provider/package/yum/rpm_utils.rb, line 84
def isdigit(x)
  v = x.ord
  v >= 48 && v <= 57
end
rpmvercmp(x, y) click to toggle source

based on the reference spec in lib/rpmvercmp.c in rpm 4.9.0

# File lib/chef/provider/package/yum/rpm_utils.rb, line 90
def rpmvercmp(x, y)
  # easy! :)
  return 0 if x == y

  if x.nil?
    x = ""
  end

  if y.nil?
    y = ""
  end

  # not so easy :(
  #
  # takes 2 strings like
  #
  # x = "1.20.b18.el5"
  # y = "1.20.b17.el5"
  #
  # breaks into purely alpha and numeric segments and compares them using
  # some rules
  #
  # * 10 > 1
  # * 1 > a
  # * z > a
  # * Z > A
  # * z > Z
  # * leading zeros are ignored
  # * separators (periods, commas) are ignored
  # * "1.20.b18.el5.extrastuff" > "1.20.b18.el5"

  x_pos = 0                # overall string element reference position
  x_pos_max = x.length - 1 # number of elements in string, starting from 0
  x_seg_pos = 0            # segment string element reference position
  x_comp = nil             # segment to compare

  y_pos = 0
  y_seg_pos = 0
  y_pos_max = y.length - 1
  y_comp = nil

  while x_pos <= x_pos_max && y_pos <= y_pos_max
    # first we skip over anything non alphanumeric
    while (x_pos <= x_pos_max) && (isalnum(x[x_pos]) == false)
      x_pos += 1 # +1 over pos_max if end of string
    end
    while (y_pos <= y_pos_max) && (isalnum(y[y_pos]) == false)
      y_pos += 1
    end

    # if we hit the end of either we are done matching segments
    if (x_pos == x_pos_max + 1) || (y_pos == y_pos_max + 1)
      break
    end

    # we are now at the start of a alpha or numeric segment
    x_seg_pos = x_pos
    y_seg_pos = y_pos

    # grab segment so we can compare them
    if isdigit(x[x_seg_pos].ord)
      x_seg_is_num = true

      # already know it's a digit
      x_seg_pos += 1

      # gather up our digits
      while (x_seg_pos <= x_pos_max) && isdigit(x[x_seg_pos])
        x_seg_pos += 1
      end
      # copy the segment but not the unmatched character that x_seg_pos will
      # refer to
      x_comp = x[x_pos, x_seg_pos - x_pos]

      while (y_seg_pos <= y_pos_max) && isdigit(y[y_seg_pos])
        y_seg_pos += 1
      end
      y_comp = y[y_pos, y_seg_pos - y_pos]
    else
      # we are comparing strings
      x_seg_is_num = false

      while (x_seg_pos <= x_pos_max) && isalpha(x[x_seg_pos])
        x_seg_pos += 1
      end
      x_comp = x[x_pos, x_seg_pos - x_pos]

      while (y_seg_pos <= y_pos_max) && isalpha(y[y_seg_pos])
        y_seg_pos += 1
      end
      y_comp = y[y_pos, y_seg_pos - y_pos]
    end

    # if y_seg_pos didn't advance in the above loop it means the segments are
    # different types
    if y_pos == y_seg_pos
      # numbers always win over letters
      return x_seg_is_num ? 1 : -1
    end

    # move the ball forward before we mess with the segments
    x_pos += x_comp.length # +1 over pos_max if end of string
    y_pos += y_comp.length

    # we are comparing numbers - simply convert them
    if x_seg_is_num
      x_comp = x_comp.to_i
      y_comp = y_comp.to_i
    end

    # compares ints or strings
    # don't return if equal - try the next segment
    if x_comp > y_comp
      return 1
    elsif x_comp < y_comp
      return -1
    end

    # if we've reached here than the segments are the same - try again
  end

  # we must have reached the end of one or both of the strings and they
  # matched up until this point

  # segments matched completely but the segment separators were different -
  # rpm reference code treats these as equal.
  if (x_pos == x_pos_max + 1) && (y_pos == y_pos_max + 1)
    return 0
  end

  # the most unprocessed characters left wins
  if (x_pos_max - x_pos) > (y_pos_max - y_pos)
    return 1
  else
    return -1
  end
end
version_parse(evr) click to toggle source

RPM::Version ::version_parse equivalent

# File lib/chef/provider/package/yum/rpm_utils.rb, line 38
def version_parse(evr)
  return if evr.nil?

  epoch = nil
  # assume this is a version
  version = evr
  release = nil

  lead = 0
  tail = evr.size

  if /^([\d]+):/.match(evr) # rubocop:disable Performance/RedundantMatch
    epoch = $1.to_i
    lead = $1.length + 1
  elsif evr[0].ord == ":".ord
    epoch = 0
    lead = 1
  end

  if /:?.*-(.*)$/.match(evr) # rubocop:disable Performance/RedundantMatch
    release = $1
    tail = evr.length - release.length - lead - 1

    if release.empty?
      release = nil
    end
  end

  version = evr[lead, tail]
  if version.empty?
    version = nil
  end

  [ epoch, version, release ]
end