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

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

Class Method Summary collapse

Class Method Details

.isalnum(x) ⇒ Object

verify


72
73
74
# File 'lib/chef/provider/package/yum.rb', line 72

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

.isalpha(x) ⇒ Object


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

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

.isdigit(x) ⇒ Object


81
82
83
84
# File 'lib/chef/provider/package/yum.rb', line 81

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

.rpmvercmp(x, y) ⇒ Object

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


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
218
219
220
221
222
223
# File 'lib/chef/provider/package/yum.rb', line 87

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 and y_pos <= y_pos_max)
    # first we skip over anything non alphanumeric
    while (x_pos <= x_pos_max) and (isalnum(x[x_pos]) == false)
      x_pos += 1 # +1 over pos_max if end of string
    end
    while (y_pos <= y_pos_max) and (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) or (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) and 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) and 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) and 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) and 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) and (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


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
64
65
66
67
68
69
# File 'lib/chef/provider/package/yum.rb', line 35

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 evr =~ %r{^([\d]+):}
    epoch = $1.to_i
    lead = $1.length + 1
  elsif evr[0].ord == ":".ord
    epoch = 0
    lead = 1
  end

  if evr =~ %r{:?.*-(.*)$}
    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