2012-08-18 13:34:31 -05:00
|
|
|
class VersionElement
|
|
|
|
include Comparable
|
|
|
|
|
|
|
|
def initialize elem
|
|
|
|
elem = elem.to_s.downcase
|
|
|
|
@elem = case elem
|
2013-04-16 14:56:22 -05:00
|
|
|
when /\d+/ then elem.to_i
|
2012-08-18 13:34:31 -05:00
|
|
|
when 'a', 'alpha' then 'alpha'
|
|
|
|
when 'b', 'beta' then 'beta'
|
|
|
|
else elem
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-04-15 15:00:57 -05:00
|
|
|
ZERO = VersionElement.new(0)
|
|
|
|
|
2012-08-18 13:34:31 -05:00
|
|
|
def <=>(other)
|
|
|
|
return unless other.is_a? VersionElement
|
|
|
|
return -1 if string? and other.numeric?
|
|
|
|
return 1 if numeric? and other.string?
|
|
|
|
return elem <=> other.elem
|
|
|
|
end
|
|
|
|
|
|
|
|
def to_s
|
|
|
|
@elem.to_s
|
|
|
|
end
|
|
|
|
|
2013-01-15 18:20:52 -06:00
|
|
|
protected
|
|
|
|
|
|
|
|
attr_reader :elem
|
|
|
|
|
2012-08-18 13:34:31 -05:00
|
|
|
def string?
|
2013-01-15 18:20:52 -06:00
|
|
|
elem.is_a? String
|
2012-08-18 13:34:31 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def numeric?
|
2013-01-15 18:20:52 -06:00
|
|
|
elem.is_a? Numeric
|
2012-08-18 13:34:31 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-07-09 22:51:10 -05:00
|
|
|
class Version
|
|
|
|
include Comparable
|
|
|
|
|
2012-07-10 16:10:16 -05:00
|
|
|
def initialize val, detected=false
|
2012-07-09 23:24:27 -05:00
|
|
|
@version = val.to_s
|
2012-07-10 16:10:16 -05:00
|
|
|
@detected_from_url = detected
|
|
|
|
end
|
|
|
|
|
|
|
|
def detected_from_url?
|
|
|
|
@detected_from_url
|
2012-07-09 22:51:10 -05:00
|
|
|
end
|
|
|
|
|
2012-07-09 23:00:40 -05:00
|
|
|
def head?
|
|
|
|
@version == 'HEAD'
|
|
|
|
end
|
|
|
|
|
2012-08-18 13:34:31 -05:00
|
|
|
def devel?
|
|
|
|
alpha? or beta? or rc?
|
|
|
|
end
|
|
|
|
|
|
|
|
def alpha?
|
|
|
|
to_a.any? { |e| e.to_s == 'alpha' }
|
|
|
|
end
|
|
|
|
|
|
|
|
def beta?
|
|
|
|
to_a.any? { |e| e.to_s == 'beta' }
|
|
|
|
end
|
|
|
|
|
|
|
|
def rc?
|
|
|
|
to_a.any? { |e| e.to_s == 'rc' }
|
2012-07-09 22:51:10 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def <=>(other)
|
2012-08-18 13:34:31 -05:00
|
|
|
# Return nil if objects aren't comparable
|
|
|
|
return unless other.is_a? Version
|
|
|
|
# Versions are equal if both are HEAD
|
|
|
|
return 0 if head? and other.head?
|
|
|
|
# HEAD is greater than any numerical version
|
|
|
|
return 1 if head? and not other.head?
|
|
|
|
return -1 if not head? and other.head?
|
2012-07-09 23:00:40 -05:00
|
|
|
|
2012-08-18 13:34:31 -05:00
|
|
|
stuple, otuple = to_a, other.to_a
|
2013-04-15 15:00:57 -05:00
|
|
|
slen, olen = stuple.length, otuple.length
|
2012-07-09 23:00:40 -05:00
|
|
|
|
2013-04-15 15:00:57 -05:00
|
|
|
max = [slen, olen].max
|
2012-07-09 23:00:40 -05:00
|
|
|
|
2013-04-15 15:00:57 -05:00
|
|
|
stuple.fill(VersionElement::ZERO, slen, max - slen)
|
|
|
|
otuple.fill(VersionElement::ZERO, olen, max - olen)
|
2012-07-09 23:00:40 -05:00
|
|
|
|
2012-08-18 13:34:31 -05:00
|
|
|
stuple <=> otuple
|
2012-07-09 22:51:10 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def to_s
|
|
|
|
@version
|
|
|
|
end
|
|
|
|
alias_method :to_str, :to_s
|
|
|
|
|
2013-01-07 11:59:33 -06:00
|
|
|
protected
|
|
|
|
|
|
|
|
def to_a
|
|
|
|
@array ||= @version.scan(/\d+|[a-zA-Z]+/).map { |e| VersionElement.new(e) }
|
|
|
|
end
|
|
|
|
|
2013-02-06 22:25:02 -06:00
|
|
|
def self.parse spec
|
|
|
|
version = _parse(spec)
|
|
|
|
Version.new(version, true) unless version.nil?
|
|
|
|
end
|
2012-07-09 23:24:27 -05:00
|
|
|
|
|
|
|
def self._parse spec
|
|
|
|
spec = Pathname.new(spec) unless spec.is_a? Pathname
|
|
|
|
|
2013-04-16 14:32:28 -05:00
|
|
|
spec_s = spec.to_s
|
|
|
|
|
2012-07-09 23:24:27 -05:00
|
|
|
stem = if spec.directory?
|
|
|
|
spec.basename.to_s
|
2013-04-16 14:32:28 -05:00
|
|
|
elsif %r[((?:sourceforge.net|sf.net)/.*)/download$].match(spec_s)
|
2012-07-09 23:24:27 -05:00
|
|
|
Pathname.new(spec.dirname).stem
|
|
|
|
else
|
|
|
|
spec.stem
|
|
|
|
end
|
|
|
|
|
|
|
|
# GitHub tarballs, e.g. v1.2.3
|
2013-04-16 14:32:28 -05:00
|
|
|
m = %r[github.com/.+/(?:zip|tar)ball/v?((\d+\.)+\d+)$].match(spec_s)
|
2012-07-09 23:24:27 -05:00
|
|
|
return m.captures.first unless m.nil?
|
|
|
|
|
|
|
|
# e.g. https://github.com/sam-github/libnet/tarball/libnet-1.1.4
|
2013-04-16 14:32:28 -05:00
|
|
|
m = %r[github.com/.+/(?:zip|tar)ball/.*-((\d+\.)+\d+)$].match(spec_s)
|
2012-07-09 23:24:27 -05:00
|
|
|
return m.captures.first unless m.nil?
|
|
|
|
|
|
|
|
# e.g. https://github.com/isaacs/npm/tarball/v0.2.5-1
|
2013-04-16 14:32:28 -05:00
|
|
|
m = %r[github.com/.+/(?:zip|tar)ball/v?((\d+\.)+\d+-(\d+))$].match(spec_s)
|
2012-07-09 23:24:27 -05:00
|
|
|
return m.captures.first unless m.nil?
|
|
|
|
|
|
|
|
# e.g. https://github.com/petdance/ack/tarball/1.93_02
|
2013-04-16 14:32:28 -05:00
|
|
|
m = %r[github.com/.+/(?:zip|tar)ball/v?((\d+\.)+\d+_(\d+))$].match(spec_s)
|
2012-07-09 23:24:27 -05:00
|
|
|
return m.captures.first unless m.nil?
|
|
|
|
|
2012-08-25 10:20:48 -07:00
|
|
|
# e.g. https://github.com/erlang/otp/tarball/OTP_R15B01 (erlang style)
|
2013-04-16 14:32:28 -05:00
|
|
|
m = /[-_](R\d+[AB]\d*(-\d+)?)/.match(spec_s)
|
2012-08-25 10:20:48 -07:00
|
|
|
return m.captures.first unless m.nil?
|
|
|
|
|
2012-07-09 23:24:27 -05:00
|
|
|
# e.g. boost_1_39_0
|
|
|
|
m = /((\d+_)+\d+)$/.match(stem)
|
|
|
|
return m.captures.first.gsub('_', '.') unless m.nil?
|
|
|
|
|
|
|
|
# e.g. foobar-4.5.1-1
|
|
|
|
# e.g. ruby-1.9.1-p243
|
2012-12-31 11:18:38 +01:00
|
|
|
m = /-((\d+\.)*\d\.\d+-(p|rc|RC)?\d+)(?:[-._](?:bin|dist|stable|src|sources))?$/.match(stem)
|
2012-07-09 23:24:27 -05:00
|
|
|
return m.captures.first unless m.nil?
|
|
|
|
|
|
|
|
# e.g. lame-398-1
|
|
|
|
m = /-((\d)+-\d)/.match(stem)
|
|
|
|
return m.captures.first unless m.nil?
|
|
|
|
|
|
|
|
# e.g. foobar-4.5.1
|
|
|
|
m = /-((\d+\.)*\d+)$/.match(stem)
|
|
|
|
return m.captures.first unless m.nil?
|
|
|
|
|
|
|
|
# e.g. foobar-4.5.1b
|
|
|
|
m = /-((\d+\.)*\d+([abc]|rc|RC)\d*)$/.match(stem)
|
|
|
|
return m.captures.first unless m.nil?
|
|
|
|
|
|
|
|
# e.g. foobar-4.5.0-beta1, or foobar-4.50-beta
|
|
|
|
m = /-((\d+\.)*\d+-beta(\d+)?)$/.match(stem)
|
|
|
|
return m.captures.first unless m.nil?
|
|
|
|
|
|
|
|
# e.g. foobar4.5.1
|
|
|
|
m = /((\d+\.)*\d+)$/.match(stem)
|
|
|
|
return m.captures.first unless m.nil?
|
|
|
|
|
|
|
|
# e.g. foobar-4.5.0-bin
|
|
|
|
m = /-((\d+\.)+\d+[abc]?)[-._](bin|dist|stable|src|sources?)$/.match(stem)
|
|
|
|
return m.captures.first unless m.nil?
|
|
|
|
|
|
|
|
# e.g. dash_0.5.5.1.orig.tar.gz (Debian style)
|
|
|
|
m = /_((\d+\.)+\d+[abc]?)[.]orig$/.match(stem)
|
|
|
|
return m.captures.first unless m.nil?
|
|
|
|
|
2012-08-25 10:20:48 -07:00
|
|
|
# e.g. http://www.openssl.org/source/openssl-0.9.8s.tar.gz
|
2012-07-09 23:24:27 -05:00
|
|
|
m = /-([^-]+)/.match(stem)
|
|
|
|
return m.captures.first unless m.nil?
|
|
|
|
|
|
|
|
# e.g. astyle_1.23_macosx.tar.gz
|
|
|
|
m = /_([^_]+)/.match(stem)
|
|
|
|
return m.captures.first unless m.nil?
|
2012-10-16 10:31:03 +01:00
|
|
|
|
|
|
|
# e.g. http://mirrors.jenkins-ci.org/war/1.486/jenkins.war
|
2013-04-16 14:32:28 -05:00
|
|
|
m = /\/(\d\.\d+)\//.match(spec_s)
|
2012-10-16 10:31:03 +01:00
|
|
|
return m.captures.first unless m.nil?
|
2013-01-27 22:34:53 +00:00
|
|
|
|
|
|
|
# e.g. http://www.ijg.org/files/jpegsrc.v8d.tar.gz
|
|
|
|
m = /\.v(\d+[a-z]?)/.match(stem)
|
|
|
|
return m.captures.first unless m.nil?
|
2012-07-09 22:51:10 -05:00
|
|
|
end
|
|
|
|
end
|
2012-07-10 21:45:17 -05:00
|
|
|
|
|
|
|
class VersionSchemeDetector
|
|
|
|
def initialize scheme
|
|
|
|
@scheme = scheme
|
|
|
|
end
|
|
|
|
|
|
|
|
def detect
|
|
|
|
if @scheme.is_a? Class and @scheme.ancestors.include? Version
|
|
|
|
@scheme
|
|
|
|
elsif @scheme.is_a? Symbol then detect_from_symbol
|
|
|
|
else
|
|
|
|
raise "Unknown version scheme #{@scheme} was requested."
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def detect_from_symbol
|
|
|
|
raise "Unknown version scheme #{@scheme} was requested."
|
|
|
|
end
|
|
|
|
end
|