module Puppet::Util::Package::Version
class Debian < Numeric
include Comparable
# Version string matching regexes
REGEX_EPOCH = '(?:([0-9]+):)?'
# alphanumerics and the characters . + - ~ , starts with a digit, ~ only of debian_revision is present
REGEX_UPSTREAM_VERSION = '([\.\+~0-9a-zA-Z-]+?)'
#alphanumerics and the characters + . ~
REGEX_DEBIAN_REVISION = '(?:-([\.\+~0-9a-zA-Z]*))?'
REGEX_FULL = REGEX_EPOCH + REGEX_UPSTREAM_VERSION + REGEX_DEBIAN_REVISION.freeze
REGEX_FULL_RX = /\A#{REGEX_FULL}\Z/
class ValidationFailure < ArgumentError; end
def self.parse(ver)
raise ValidationFailure, "Unable to parse '#{ver}' as a string" unless ver.is_a?(String)
match, epoch, upstream_version, debian_revision = *ver.match(REGEX_FULL_RX)
raise ValidationFailure, "Unable to parse '#{ver}' as a debian version identifier" unless match
new(epoch.to_i, upstream_version, debian_revision).freeze
end
def to_s
s = @upstream_version
s = "#{@epoch}:#{s}" if @epoch != 0
s = "#{s}-#{@debian_revision}" if @debian_revision
s
end
alias inspect to_s
def eql?(other)
other.is_a?(self.class) &&
@epoch.eql?(other.epoch) &&
@upstream_version.eql?(other.upstream_version) &&
@debian_revision.eql?(other.debian_revision)
end
alias == eql?
def <=>(other)
return nil unless other.is_a?(self.class)
cmp = @epoch <=> other.epoch
if cmp == 0
cmp = compare_upstream_version(other)
if cmp == 0
cmp = compare_debian_revision(other)
end
end
cmp
end
attr_reader :epoch, :upstream_version, :debian_revision
private
def initialize(epoch, upstream_version, debian_revision)
@epoch = epoch
@upstream_version = upstream_version
@debian_revision = debian_revision
end
def compare_upstream_version(other)
mine = @upstream_version
yours = other.upstream_version
compare_debian_versions(mine, yours)
end
def compare_debian_revision(other)
mine = @debian_revision
yours = other.debian_revision
compare_debian_versions(mine, yours)
end
def compare_debian_versions(mine, yours)
# First the initial part of each string consisting entirely of non-digit characters is determined.
# These two parts (one of which may be empty) are compared lexically. If a difference is found it is
# returned. The lexical comparison is a comparison of ASCII values modified so that all the letters
# sort earlier than all the non-letters and so that a tilde sorts before anything, even the end of a
# part. For example, the following parts are in sorted order from earliest to latest: ~~, ~~a, ~, the
# empty part, a.
#
# Then the initial part of the remainder of each string which consists entirely of digit characters
# is determined. The numerical values of these two parts are compared, and any difference found is
# returned as the result of the comparison. For these purposes an empty string (which can only occur
# at the end of one or both version strings being compared) counts as zero.
#
# These two steps (comparing and removing initial non-digit strings and initial digit strings) are
# repeated until a difference is found or both strings are exhausted.
mine_index = 0
yours_index = 0
cmp = 0
mine ||= ''
yours ||= ''
while mine_index < mine.length && yours_index < yours.length && cmp == 0
#handle ~
_mymatch, mytilde = *match_tildes(mine.slice(mine_index..-1))
mytilde ||= ''
_yoursmatch, yourstilde = *match_tildes(yours.slice(yours_index..-1))
yourstilde ||= ''
cmp = -1 * (mytilde.length <=> yourstilde.length)
mine_index += mytilde.length
yours_index += yourstilde.length
if cmp == 0 # handle letters
_mymatch, myletters = *match_letters(mine.slice(mine_index..-1))
myletters ||= ''
_yoursmatch, yoursletters = *match_letters(yours.slice(yours_index..-1))
yoursletters ||= ''
cmp = myletters <=> yoursletters
mine_index += myletters.length
yours_index += yoursletters.length
if cmp == 0 # handle nonletters except tilde
_mymatch, mynon_letters = *match_non_letters(mine.slice(mine_index..-1))
mynon_letters ||= ''
_yoursmatch, yoursnon_letters = *match_non_letters(yours.slice(yours_index..-1))
yoursnon_letters ||= ''
cmp = mynon_letters <=> yoursnon_letters
mine_index += mynon_letters.length
yours_index += yoursnon_letters.length
if cmp == 0 # handle digits
_mymatch, mydigits = *match_digits(mine.slice(mine_index..-1))
mydigits ||= ''
_yoursmatch, yoursdigits = *match_digits(yours.slice(yours_index..-1))
yoursdigits ||= ''
cmp = mydigits.to_i <=> yoursdigits.to_i
mine_index += mydigits.length
yours_index += yoursdigits.length
end
end
end
end
if cmp == 0
if mine_index < mine.length && match_tildes(mine[mine_index])
cmp = -1
elsif yours_index < yours.length && match_tildes(yours[yours_index])
cmp = 1
else
cmp = mine.length <=> yours.length
end
end
cmp
end
def match_digits(a)
a.match(/^([0-9]+)/)
end
def match_non_letters(a)
a.match(/^([\.\+-]+)/)
end
def match_tildes(a)
a.match(/^(~+)/)
end
def match_letters(a)
a.match(/^([A-Za-z]+)/)
end
end
end
Anons79 File Manager Version 1.0, Coded By Anons79
Email: [email protected]