232 lines
		
	
	
	
		
			8.2 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			232 lines
		
	
	
	
		
			8.2 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
--[[
 | 
						|
Checkout semver.lua semantic versioning library for LUA
 | 
						|
https://github.com/kikito/semver.lua
 | 
						|
 | 
						|
Copyright (c) 2011 Enrique García Cota
 | 
						|
 | 
						|
MIT LICENSE
 | 
						|
Permission is hereby granted, free of charge, to any person obtaining a
 | 
						|
copy of this software and associated documentation files (the
 | 
						|
"Software"), to deal in the Software without restriction, including
 | 
						|
without limitation the rights to use, copy, modify, merge, publish,
 | 
						|
distribute, sublicense, and/or sell copies of the Software, and to
 | 
						|
permit persons to whom the Software is furnished to do so, subject to
 | 
						|
the following conditions:
 | 
						|
 | 
						|
The above copyright notice and this permission notice shall be included
 | 
						|
in all copies or substantial portions of the Software.
 | 
						|
 | 
						|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 | 
						|
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | 
						|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 | 
						|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 | 
						|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 | 
						|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 | 
						|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
						|
]]
 | 
						|
 | 
						|
semver = {
 | 
						|
  _VERSION     = '1.2.1',
 | 
						|
  _DESCRIPTION = 'semver for Lua',
 | 
						|
  _URL         = 'https://github.com/kikito/semver.lua',
 | 
						|
  _LICENSE     = [[
 | 
						|
    MIT LICENSE
 | 
						|
    Copyright (c) 2015 Enrique García Cota
 | 
						|
    Permission is hereby granted, free of charge, to any person obtaining a
 | 
						|
    copy of tother software and associated documentation files (the
 | 
						|
    "Software"), to deal in the Software without restriction, including
 | 
						|
    without limitation the rights to use, copy, modify, merge, publish,
 | 
						|
    distribute, sublicense, and/or sell copies of the Software, and to
 | 
						|
    permit persons to whom the Software is furnished to do so, subject to
 | 
						|
    the following conditions:
 | 
						|
    The above copyright notice and tother permission notice shall be included
 | 
						|
    in all copies or substantial portions of the Software.
 | 
						|
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 | 
						|
    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | 
						|
    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 | 
						|
    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 | 
						|
    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 | 
						|
    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 | 
						|
    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
						|
  ]]
 | 
						|
}
 | 
						|
 | 
						|
local function checkPositiveInteger(number, name)
 | 
						|
  assert(number >= 0, name .. ' must be a valid positive number')
 | 
						|
  assert(math.floor(number) == number, name .. ' must be an integer')
 | 
						|
end
 | 
						|
 | 
						|
local function present(value)
 | 
						|
  return value and value ~= ''
 | 
						|
end
 | 
						|
 | 
						|
-- splitByDot("a.bbc.d") == {"a", "bbc", "d"}
 | 
						|
local function splitByDot(str)
 | 
						|
  str = str or ""
 | 
						|
  local t, count = {}, 0
 | 
						|
  str:gsub("([^%.]+)", function(c)
 | 
						|
    count = count + 1
 | 
						|
    t[count] = c
 | 
						|
  end)
 | 
						|
  return t
 | 
						|
end
 | 
						|
 | 
						|
local function parsePrereleaseAndBuildWithSign(str)
 | 
						|
  local prereleaseWithSign, buildWithSign = str:match("^(-[^+]+)(+.+)$")
 | 
						|
  if not (prereleaseWithSign and buildWithSign) then
 | 
						|
    prereleaseWithSign = str:match("^(-.+)$")
 | 
						|
    buildWithSign      = str:match("^(+.+)$")
 | 
						|
  end
 | 
						|
  assert(prereleaseWithSign or buildWithSign, ("The parameter %q must begin with + or - to denote a prerelease or a build"):format(str))
 | 
						|
  return prereleaseWithSign, buildWithSign
 | 
						|
end
 | 
						|
 | 
						|
local function parsePrerelease(prereleaseWithSign)
 | 
						|
  if prereleaseWithSign then
 | 
						|
    local prerelease = prereleaseWithSign:match("^-(%w[%.%w-]*)$")
 | 
						|
    assert(prerelease, ("The prerelease %q is not a slash followed by alphanumerics, dots and slashes"):format(prereleaseWithSign))
 | 
						|
    return prerelease
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
local function parseBuild(buildWithSign)
 | 
						|
  if buildWithSign then
 | 
						|
    local build = buildWithSign:match("^%+(%w[%.%w-]*)$")
 | 
						|
    assert(build, ("The build %q is not a + sign followed by alphanumerics, dots and slashes"):format(buildWithSign))
 | 
						|
    return build
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
local function parsePrereleaseAndBuild(str)
 | 
						|
  if not present(str) then return nil, nil end
 | 
						|
 | 
						|
  local prereleaseWithSign, buildWithSign = parsePrereleaseAndBuildWithSign(str)
 | 
						|
 | 
						|
  local prerelease = parsePrerelease(prereleaseWithSign)
 | 
						|
  local build = parseBuild(buildWithSign)
 | 
						|
 | 
						|
  return prerelease, build
 | 
						|
end
 | 
						|
 | 
						|
local function parseVersion(str)
 | 
						|
  local sMajor, sMinor, sPatch, sPrereleaseAndBuild = str:match("^(%d+)%.?(%d*)%.?(%d*)(.-)$")
 | 
						|
  assert(type(sMajor) == 'string', ("Could not extract version number(s) from %q"):format(str))
 | 
						|
  local major, minor, patch = tonumber(sMajor), tonumber(sMinor), tonumber(sPatch)
 | 
						|
  local prerelease, build = parsePrereleaseAndBuild(sPrereleaseAndBuild)
 | 
						|
  return major, minor, patch, prerelease, build
 | 
						|
end
 | 
						|
 | 
						|
 | 
						|
-- return 0 if a == b, -1 if a < b, and 1 if a > b
 | 
						|
local function compare(a,b)
 | 
						|
  return a == b and 0 or a < b and -1 or 1
 | 
						|
end
 | 
						|
 | 
						|
local function compareIds(myId, otherId)
 | 
						|
  if myId == otherId then return  0
 | 
						|
  elseif not myId    then return -1
 | 
						|
  elseif not otherId then return  1
 | 
						|
  end
 | 
						|
 | 
						|
  local selfNumber, otherNumber = tonumber(myId), tonumber(otherId)
 | 
						|
 | 
						|
  if selfNumber and otherNumber then -- numerical comparison
 | 
						|
    return compare(selfNumber, otherNumber)
 | 
						|
  -- numericals are always smaller than alphanums
 | 
						|
  elseif selfNumber then
 | 
						|
    return -1
 | 
						|
  elseif otherNumber then
 | 
						|
    return 1
 | 
						|
  else
 | 
						|
    return compare(myId, otherId) -- alphanumerical comparison
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
local function smallerIdList(myIds, otherIds)
 | 
						|
  local myLength = #myIds
 | 
						|
  local comparison
 | 
						|
 | 
						|
  for i=1, myLength do
 | 
						|
    comparison = compareIds(myIds[i], otherIds[i])
 | 
						|
    if comparison ~= 0 then
 | 
						|
      return comparison == -1
 | 
						|
    end
 | 
						|
    -- if comparison == 0, continue loop
 | 
						|
  end
 | 
						|
 | 
						|
  return myLength < #otherIds
 | 
						|
end
 | 
						|
 | 
						|
local function smallerPrerelease(mine, other)
 | 
						|
  if mine == other or not mine then return false
 | 
						|
  elseif not other then return true
 | 
						|
  end
 | 
						|
 | 
						|
  return smallerIdList(splitByDot(mine), splitByDot(other))
 | 
						|
end
 | 
						|
 | 
						|
local methods = {}
 | 
						|
 | 
						|
function methods:nextMajor()
 | 
						|
  return semver(self.major + 1, 0, 0)
 | 
						|
end
 | 
						|
function methods:nextMinor()
 | 
						|
  return semver(self.major, self.minor + 1, 0)
 | 
						|
end
 | 
						|
function methods:nextPatch()
 | 
						|
  return semver(self.major, self.minor, self.patch + 1)
 | 
						|
end
 | 
						|
 | 
						|
local mt = { __index = methods }
 | 
						|
function mt:__eq(other)
 | 
						|
  return self.major == other.major and
 | 
						|
         self.minor == other.minor and
 | 
						|
         self.patch == other.patch and
 | 
						|
         self.prerelease == other.prerelease
 | 
						|
         -- notice that build is ignored for precedence in semver 2.0.0
 | 
						|
end
 | 
						|
function mt:__lt(other)
 | 
						|
  if self.major ~= other.major then return self.major < other.major end
 | 
						|
  if self.minor ~= other.minor then return self.minor < other.minor end
 | 
						|
  if self.patch ~= other.patch then return self.patch < other.patch end
 | 
						|
  return smallerPrerelease(self.prerelease, other.prerelease)
 | 
						|
  -- notice that build is ignored for precedence in semver 2.0.0
 | 
						|
end
 | 
						|
-- This works like the "pessimisstic operator" in Rubygems.
 | 
						|
-- if a and b are versions, a ^ b means "b is backwards-compatible with a"
 | 
						|
-- in other words, "it's safe to upgrade from a to b"
 | 
						|
function mt:__pow(other)
 | 
						|
  if self.major == 0 then
 | 
						|
    return self == other
 | 
						|
  end
 | 
						|
  return self.major == other.major and
 | 
						|
         self.minor <= other.minor
 | 
						|
end
 | 
						|
function mt:__tostring()
 | 
						|
  local buffer = { ("%d.%d.%d"):format(self.major, self.minor, self.patch) }
 | 
						|
  if self.prerelease then table.insert(buffer, "-" .. self.prerelease) end
 | 
						|
  if self.build      then table.insert(buffer, "+" .. self.build) end
 | 
						|
  return table.concat(buffer)
 | 
						|
end
 | 
						|
 | 
						|
local function new(major, minor, patch, prerelease, build)
 | 
						|
  assert(major, "At least one parameter is needed")
 | 
						|
 | 
						|
  if type(major) == 'string' then
 | 
						|
    major,minor,patch,prerelease,build = parseVersion(major)
 | 
						|
  end
 | 
						|
  patch = patch or 0
 | 
						|
  minor = minor or 0
 | 
						|
 | 
						|
  checkPositiveInteger(major, "major")
 | 
						|
  checkPositiveInteger(minor, "minor")
 | 
						|
  checkPositiveInteger(patch, "patch")
 | 
						|
 | 
						|
  local result = {major=major, minor=minor, patch=patch, prerelease=prerelease, build=build}
 | 
						|
  return setmetatable(result, mt)
 | 
						|
end
 | 
						|
 | 
						|
setmetatable(semver, { __call = function(_, ...) return new(...) end })
 | 
						|
semver._VERSION= semver(semver._VERSION)
 | 
						|
 | 
						|
return semver
 |