Class: Chef::Provider::Package::Yum::RPMUtils

Inherits:
Object
  • Object
show all
Defined in:
lib/chef/provider/package/yum/rpm_utils.rb

Class Method Summary collapse

Class Method Details

.isalnum(x) ⇒ Object

verify


66
67
68
# File 'lib/chef/provider/package/yum/rpm_utils.rb', line 66

def isalnum(x)
  isalpha(x) || isdigit(x)
end

.isalpha(x) ⇒ Object


70
71
72
73
# File 'lib/chef/provider/package/yum/rpm_utils.rb', line 70

def isalpha(x)
  v = x.ord
  (v >= 65 && v <= 90) || (v >= 97 && v <= 122)
end

.isdigit(x) ⇒ Object


75
76
77
78
# File 'lib/chef/provider/package/yum/rpm_utils.rb', line 75

def isdigit(x)
  v = x.ord
  v >= 48 && v <= 57
end

.rpmvercmp(x, y) ⇒ Object

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


81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/chef/provider/package/yum/rpm_utils.rb', line 81

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) ⇒ Object

RPM::Version version_parse equivalent


29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/chef/provider/package/yum/rpm_utils.rb', line 29

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