Class: Composer::Semver::VersionParser

Inherits:
Object
  • Object
show all
Defined in:
lib/composer/semver/version_parser.rb

Overview

Version Parser

PHP Authors: Jordi Boggiano <[email protected]>

Ruby Authors: Ioannis Kappas <[email protected]>

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.modifier_regexObject



23
24
25
# File 'lib/composer/semver/version_parser.rb', line 23

def self.modifier_regex
  @modifier_regex ||= '[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)((?:[.-]?\d+)*+)?)?([.-]?dev)?'.freeze
end

.normalize_stability(stability) ⇒ Object

Normalize the specified stability

Parameters:

  • stability

    string The stability to normalize.

Returns:

  • string

Raises:

  • (ArgumentError)


83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/composer/semver/version_parser.rb', line 83

def self.normalize_stability(stability)

  # verify supplied arguments
  raise ArgumentError,
        'stability must be specified' unless stability

  raise TypeError,
        'stability must be of type String' unless stability.is_a?(String)

  stability = stability.downcase
  stability === 'rc' ? 'RC' : stability
end

.parse_stability(version) ⇒ Object

Returns the stability of a version

Parameters:

  • version

    string The version to parse for stability

Returns:

  • string The version’s stability

Raises:

  • (ArgumentError)


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
70
71
72
73
74
75
76
# File 'lib/composer/semver/version_parser.rb', line 36

def self.parse_stability(version)

  raise ArgumentError,
        'version must be specified' if version.nil?

  raise TypeError,
        'version must be of type String' unless version.is_a?(String)

  version.gsub!(/#.+$/i, '')

  # match dev stability
  if version.start_with?('dev-') or version.end_with?('-dev')
    return 'dev'
  end

  /#{self.modifier_regex}$/i.match(version.downcase) do |matches|

    if !matches[3].nil? && !matches[3].empty?
      return 'dev'
    end

    if !matches[1].nil? && !matches[1].empty?

      if matches[1] === 'beta' || matches[1] === 'b'
        return 'beta'
      end

      if matches[1] === 'alpha' || matches[1] === 'a'
        return 'alpha'
      end

      if matches[1] === 'rc'
        return 'RC'
      end

    end

  end

  'stable'
end

.stabilitiesObject



27
28
29
# File 'lib/composer/semver/version_parser.rb', line 27

def self.stabilities
  @stabilities ||= %w{stable RC beta alpha dev}.freeze
end

Instance Method Details

#normalize(version, full_version = nil) ⇒ Object

Normalizes a version string to be able to perform comparisons on it

Params:

Parameters:

  • version

    string The version string to normalize

  • full_version (defaults to: nil)

    string Optional. The complete version string to give more context

Returns:

  • string The normalized version string.

Raises:

  • (ArgumentError)


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
# File 'lib/composer/semver/version_parser.rb', line 106

def normalize(version, full_version = nil)

  # verify supplied arguments
  raise ArgumentError,
        'version must be specified' if version.nil?

  raise TypeError,
        'version must be of type String' unless version.is_a?(String)

  # trim the version
  version.strip!

  # set the full_version unless specified
  full_version = version if full_version.nil?

  # set default index
  index = 0

  # strip off aliasing
  /^([^,\s]+) +as +([^,\s]+)$/.match(version) do |matches|
    version = matches[1]
  end

  # strip off build metadata
  /^([^,\s+]+)\+[^\s]+$/.match(version) do |matches|
    version = matches[1]
  end

  # match master-like branches
  if /^(?:dev-)?(?:master|trunk|default)$/i.match(version)
    return '9999999-dev'
  end

  # match dev- prefix versioning
  if version.downcase.start_with?('dev-')
    return "dev-#{version[4..version.size]}"
  end

  # match classical versioning
  if (matches = /^v?(\d{1,5})(\.\d+)?(\.\d+)?(\.\d+)?#{self.class.modifier_regex}$/i.match(version))
    version = ''
    matches.to_a[1..4].each do |c|
      version += c ? c : '.0'
    end
    index = 5
  # match data(time) based versioning
  elsif (matches = /^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3})?)#{self.class.modifier_regex}$/i.match(version))
    version = matches[1].gsub(/\D/, '.')
    index = 2
  end

  # add version modifiers if a version was matched
  if index > 0

    if !matches[index].nil? && !matches[index].empty?

      if matches[index] === 'stable'
        return version
      end

      stability = expand_stability(matches[index])
      version << "-#{stability}"
      if !matches[index + 1].nil? && !matches[index + 1].empty?
        version << matches[index + 1].gsub(/^[.-]+/, '')
      end

    end

    if !matches[index + 2].nil? && !matches[index + 2].empty?
      version << '-dev'
    end

    return version
  end

  # match dev branches
  /(.*?)[.-]?dev$/i.match(version) do |match|
    begin
      return normalize_branch(match[1])
    rescue
      #skip
    end
  end

  extra_message = ''
  if / +as +#{Regexp.escape(version)}$/.match(full_version)
    extra_message = " in \"#{full_version}\", the alias must be an exact version"
  elsif /^#{Regexp.escape(version)} +as +/.match(full_version)
    extra_message = " in \"#{full_version}\", the alias source must be an exact version, if it is a branch name you should prefix it with dev-"
  end

  raise ArgumentError,
        "Invalid version string \"#{version}\"#{extra_message}"
end

#normalize_branch(name) ⇒ Object

Normalizes a branch name to be able to perform comparisons on it

Parameters:

  • name

    string The branch name to normalize

Returns:

  • string The normalized branch name

Raises:

  • (ArgumentError)


218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/composer/semver/version_parser.rb', line 218

def normalize_branch(name)

  # verify supplied arguments
  raise ArgumentError,
        'name must be specified' unless name

  raise TypeError,
        'name must be of type String' unless name.is_a?(String)

  raise ArgumentError,
        'name string must not be empty' if name.empty?

  name.strip!
  if %w{master trunk default}.include?(name)
    normalize(name)
  elsif (matches = /^v?(\d+)(\.(?:\d+|[xX*]))?(\.(?:\d+|[xX*]))?(\.(?:\d+|[xX*]))?$/i.match(name))
    version = ''
    matches.captures.each { |match| version << (match != nil ? match.tr('*', 'x').tr('X', 'x') : '.x') }
    "#{version.gsub('x', '9999999')}-dev"
  else
    "dev-#{name}"
  end
end

#parse_constraints(constraints) ⇒ Object

Parses a constraint string into MultiConstraint and/or Constraint objects.

Parameters:

  • constraints

    string The constraints to parse.

Returns:

  • ::Composer::Semver::Constraint::Base

Raises:

  • (ArgumentError)


247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# File 'lib/composer/semver/version_parser.rb', line 247

def parse_constraints(constraints)

  # verify supplied arguments
  raise ArgumentError,
        'version must be specified' unless constraints

  raise TypeError,
        'version must be of type String' unless constraints.is_a?(String)

  raise ArgumentError,
        'version string must not be empty' if constraints.empty?

  pretty_constraint = constraints

  # match stabilities constraints
  /^([^,\s]*?)@(#{self.class.stabilities.join('|')})$/i.match(constraints) do |match|
    constraints = match[1].nil? || match[1].empty? ? '*' : match[1]
  end

  # match dev constraints
  /^(dev-[^,\s@]+?|[^,\s@]+?\.x-dev)#.+$/i.match(constraints) do |match|
    constraints = match[1]
  end

  or_groups = []
  or_constraints = constraints.strip.split(/\s*\|\|?\s*/)
  or_constraints.each do |or_constraint|

    and_constraints = or_constraint.split(/(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)/)

    if and_constraints.length > 1
      constraint_objects = []
      and_constraints.each do |and_constraint|
        parse_constraint(and_constraint).each {|parsed_constraint| constraint_objects << parsed_constraint }
      end
    else
      constraint_objects = parse_constraint(and_constraints[0])
    end

    if constraint_objects.length.equal?(1)
      constraint = constraint_objects[0]
    else
      constraint = ::Composer::Semver::Constraint::MultiConstraint.new(constraint_objects)
    end

    or_groups << constraint
  end

  if or_groups.length.equal?(1)
    constraint = or_groups[0]
  else
    constraint = ::Composer::Semver::Constraint::MultiConstraint.new(or_groups, false)
  end

  constraint.pretty_string = pretty_constraint

  constraint
end

#parse_numeric_alias_prefix(branch) ⇒ Object

Extract numeric prefix from alias, if it is in numeric format, suitable for version comparison.

Parameters:

  • branch

    string The branch name to parse (e.g. 2.1.x-dev)

Returns:

  • string|false The numeric prefix if present (e.g. 2.1.) or false



206
207
208
209
210
211
# File 'lib/composer/semver/version_parser.rb', line 206

def parse_numeric_alias_prefix(branch)
  /^(?<version>(\d+\.)*\d+)(?:\.x)?-dev$/i.match(branch) do |matches|
    return "#{matches['version']}."
  end
  false
end