semver_dialects 3.2.1 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/semver_dialects/apk.rb +242 -0
- data/lib/semver_dialects/version.rb +1 -1
- data/lib/semver_dialects.rb +17 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9358b5e27d5e1128e133c3ea3fc04bfdce8d35d8db3479a8edb367eba5d5b766
|
4
|
+
data.tar.gz: 334101a02b1af9ab5368ec7003c02d344d3f0e45294c107cda841da3b5e40c86
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94af1e53527c2b56ab22c0792bc085d9c594abd1a5285aa73d8b968cfee761566967d7b093aaa10353d79c684fec71f6ed3edf83f55e37cf02a054f7dcaa4c41
|
7
|
+
data.tar.gz: c4aefce6856543bae0aca7cc07f706b023ee9d345f3a18c2d68b3178be4f781963a32de3d75cdf179f2d9549985d217a8dc00c4588a0e0c35b4391eae3efaea6
|
@@ -0,0 +1,242 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'strscan'
|
4
|
+
|
5
|
+
module SemverDialects
|
6
|
+
module Apk
|
7
|
+
# This implementation references the version.c apk-tools implementation
|
8
|
+
# https://gitlab.alpinelinux.org/alpine/apk-tools/-/blob/6052bfef57a81d82451b4cad86f78a2d01959767/src/version.c
|
9
|
+
# apk version spec can be found here https://wiki.alpinelinux.org/wiki/APKBUILD_Reference#pkgver
|
10
|
+
class Version < BaseVersion
|
11
|
+
PRE_RELEASE_ORDER = { 'alpha' => 0, 'beta' => 1, 'pre' => 2, 'rc' => 3 }.freeze
|
12
|
+
POST_RELEASE_ORDER = { 'cvs' => 0, 'svn' => 1, 'git' => 2, 'hg' => 3, 'p' => 4 }.freeze
|
13
|
+
|
14
|
+
attr_reader :tokens, :pre_release, :post_release, :revision
|
15
|
+
|
16
|
+
def initialize(tokens, pre_release: [], post_release: [], revision: [])
|
17
|
+
@tokens = tokens
|
18
|
+
@pre_release = pre_release
|
19
|
+
@post_release = post_release
|
20
|
+
@revision = revision
|
21
|
+
end
|
22
|
+
|
23
|
+
def <=>(other)
|
24
|
+
cmp = compare_tokens(tokens, other.tokens)
|
25
|
+
return cmp unless cmp.zero?
|
26
|
+
|
27
|
+
cmp = compare_pre_release(pre_release, other.pre_release)
|
28
|
+
return cmp unless cmp.zero?
|
29
|
+
|
30
|
+
cmp = compare_post_release(post_release, other.post_release)
|
31
|
+
return cmp unless cmp.zero?
|
32
|
+
|
33
|
+
compare_revisions(revision, other.revision)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Note that to_s does not accurately recreate the version string
|
37
|
+
# if alphabets are present in the version segment.
|
38
|
+
# For instance 1.2.a or 1.2a would both be returned as 1.2.a with to_s
|
39
|
+
# More details in https://gitlab.com/gitlab-org/ruby/gems/semver_dialects/-/merge_requests/97#note_1989192447
|
40
|
+
def to_s
|
41
|
+
@to_s ||= begin
|
42
|
+
main = tokens.join('.')
|
43
|
+
main += "_#{pre_release.join('')}" unless pre_release.empty?
|
44
|
+
main += "_#{post_release.join('')}" unless post_release.empty?
|
45
|
+
main += "-#{revision.join('')}" unless revision.empty?
|
46
|
+
main
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
# Token can be either integer or string
|
53
|
+
# Precedence: numeric token > string token > no token
|
54
|
+
def compare_token_pair(a, b)
|
55
|
+
return 1 if !a.nil? && b.nil?
|
56
|
+
return -1 if a.nil? && !b.nil?
|
57
|
+
|
58
|
+
return 1 if a.is_a?(Integer) && b.is_a?(String)
|
59
|
+
return -1 if a.is_a?(String) && b.is_a?(Integer)
|
60
|
+
|
61
|
+
# Remaining scenario are tokens of the same type ie Integer or String. Use <=> to compare
|
62
|
+
a <=> b
|
63
|
+
end
|
64
|
+
|
65
|
+
# Precedence: post-release > no release > pre-release
|
66
|
+
# https://wiki.alpinelinux.org/wiki/APKBUILD_Reference#pkgver
|
67
|
+
def compare_pre_release(a, b)
|
68
|
+
return 0 if a.empty? && b.empty?
|
69
|
+
return -1 if !a.empty? && b.empty?
|
70
|
+
return 1 if a.empty? && !b.empty?
|
71
|
+
|
72
|
+
compare_suffix(a, b, PRE_RELEASE_ORDER)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Precedence: post-release > no release > pre-release
|
76
|
+
# https://wiki.alpinelinux.org/wiki/APKBUILD_Reference#pkgver
|
77
|
+
def compare_post_release(a, b)
|
78
|
+
return 0 if a.empty? && b.empty?
|
79
|
+
return 1 if !a.empty? && b.empty?
|
80
|
+
return -1 if a.empty? && !b.empty?
|
81
|
+
|
82
|
+
compare_suffix(a, b, POST_RELEASE_ORDER)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Pre-release precedence: alpha < beta < pre < rc
|
86
|
+
# Post-release precedence: cvs < svn < git < hg < p
|
87
|
+
# Precedence for releases with number eg alpha1:
|
88
|
+
# release without number < release with number
|
89
|
+
def compare_suffix(a, b, order)
|
90
|
+
a_suffix = order[a[0]]
|
91
|
+
b_suffix = order[b[0]]
|
92
|
+
|
93
|
+
return 1 if a_suffix > b_suffix
|
94
|
+
return -1 if a_suffix < b_suffix
|
95
|
+
|
96
|
+
a_value = a[1]
|
97
|
+
b_value = b[1]
|
98
|
+
|
99
|
+
return 1 if !a_value.nil? && b_value.nil?
|
100
|
+
return -1 if a_value.nil? && !b_value.nil?
|
101
|
+
|
102
|
+
(a_value || 0) <=> (b_value || 0)
|
103
|
+
end
|
104
|
+
|
105
|
+
def compare_revisions(a, b)
|
106
|
+
return 0 if a.empty? && b.empty?
|
107
|
+
return 1 if !a.empty? && b.empty?
|
108
|
+
return -1 if a.empty? && !b.empty?
|
109
|
+
|
110
|
+
a_value = a[1]
|
111
|
+
b_value = b[1]
|
112
|
+
|
113
|
+
return 1 if !a_value.nil? && b_value.nil?
|
114
|
+
return -1 if a_value.nil? && !b_value.nil?
|
115
|
+
|
116
|
+
(a_value || 0) <=> (b_value || 0)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class VersionParser
|
121
|
+
DASH = /-/
|
122
|
+
ALPHABETS = /([a-zA-Z]+)/
|
123
|
+
DIGITS = /([0-9]+)/
|
124
|
+
DIGIT = /[0-9]/
|
125
|
+
DOT = '.'
|
126
|
+
UNDERSCORE = '_'
|
127
|
+
PRE_RELEASE_SUFFIXES = %w[alpha beta pre rc].freeze
|
128
|
+
POST_RELEASE_SUFFIXES = %w[cvs svn git hg p].freeze
|
129
|
+
WHITE_SPACE = /\s/
|
130
|
+
|
131
|
+
def self.parse(input)
|
132
|
+
new(input).parse
|
133
|
+
end
|
134
|
+
|
135
|
+
attr_reader :scanner, :input
|
136
|
+
|
137
|
+
def initialize(input)
|
138
|
+
@input = input
|
139
|
+
@pre_release = []
|
140
|
+
@post_release = []
|
141
|
+
@revision = []
|
142
|
+
@scanner = StringScanner.new(input)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Parse splits the raw version string into:
|
146
|
+
# version, pre_release, post_release and revision
|
147
|
+
# Format: <version>_<release>-<revision>
|
148
|
+
# Note that version segment can contain alphabets
|
149
|
+
# Release is always preceded with `_`
|
150
|
+
# Revision is always preceded with `-`
|
151
|
+
def parse
|
152
|
+
tokens = parse_tokens
|
153
|
+
|
154
|
+
Version.new(tokens, pre_release: @pre_release, post_release: @post_release, revision: @revision)
|
155
|
+
end
|
156
|
+
|
157
|
+
private
|
158
|
+
|
159
|
+
def parse_tokens
|
160
|
+
tokens = []
|
161
|
+
|
162
|
+
until scanner.eos?
|
163
|
+
case
|
164
|
+
when (s = scanner.scan(ALPHABETS))
|
165
|
+
tokens << s
|
166
|
+
when (s = scanner.scan(DIGITS))
|
167
|
+
# TODO: add support to parse numbers with leading zero https://gitlab.com/gitlab-org/gitlab/-/issues/471509
|
168
|
+
raise SemverDialects::UnsupportedVersionError, input if s.start_with?('0') && s.length > 1
|
169
|
+
|
170
|
+
tokens << s.to_i
|
171
|
+
when (s = scanner.scan(UNDERSCORE))
|
172
|
+
parse_release
|
173
|
+
# Continue parsing if there's remaining tokens since revision which comes after release is optional
|
174
|
+
return tokens if scanner.eos?
|
175
|
+
when (s = scanner.scan(DASH))
|
176
|
+
parse_revision
|
177
|
+
return tokens
|
178
|
+
when (s = scanner.scan(WHITE_SPACE))
|
179
|
+
# Raise error if there's whitespace
|
180
|
+
raise SemverDialects::InvalidVersionError, input
|
181
|
+
when (s = scanner.scan(DOT))
|
182
|
+
# Skip parsing dot
|
183
|
+
else
|
184
|
+
raise SemverDialects::IncompleteScanError, scanner.rest
|
185
|
+
end
|
186
|
+
end
|
187
|
+
tokens
|
188
|
+
end
|
189
|
+
|
190
|
+
# PRE_RELEASE_SUFFIXES: alpha, beta, pre, rc
|
191
|
+
# POST_RELEASE_SUFFIXES: cvs, svn, git, hg, p
|
192
|
+
# No other suffixes are allowed
|
193
|
+
# Release can be either `<suffix>` or `<suffix><number>` with the number being optional
|
194
|
+
def parse_release
|
195
|
+
# TODO: Add support to parse version with multiple releases
|
196
|
+
raise SemverDialects::UnsupportedVersionError, input if !@pre_release.empty? || !@post_release.empty?
|
197
|
+
|
198
|
+
suffix_type = nil
|
199
|
+
until scanner.eos?
|
200
|
+
case
|
201
|
+
when (s = scanner.scan(ALPHABETS))
|
202
|
+
if PRE_RELEASE_SUFFIXES.include?(s)
|
203
|
+
suffix_type = :pre
|
204
|
+
@pre_release << s
|
205
|
+
elsif POST_RELEASE_SUFFIXES.include?(s)
|
206
|
+
suffix_type = :post
|
207
|
+
@post_release << s
|
208
|
+
else
|
209
|
+
raise SemverDialects::InvalidVersionError, input
|
210
|
+
end
|
211
|
+
return unless scanner.peek(1) =~ DIGIT
|
212
|
+
when (s = scanner.scan(DIGITS))
|
213
|
+
if suffix_type == :pre
|
214
|
+
@pre_release << s.to_i
|
215
|
+
return
|
216
|
+
elsif suffix_type == :post
|
217
|
+
@post_release << s.to_i
|
218
|
+
return
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
# Revision can be either `r` or `r<number>` with the number being optional
|
225
|
+
def parse_revision
|
226
|
+
until scanner.eos?
|
227
|
+
case
|
228
|
+
when (s = scanner.scan(ALPHABETS))
|
229
|
+
raise SemverDialects::InvalidVersionError, input unless s == 'r'
|
230
|
+
|
231
|
+
@revision << s
|
232
|
+
|
233
|
+
return unless scanner.peek(1) =~ DIGIT
|
234
|
+
when (s = scanner.scan(DIGITS))
|
235
|
+
@revision << s.to_i
|
236
|
+
return
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
data/lib/semver_dialects.rb
CHANGED
@@ -4,6 +4,7 @@ require 'semver_dialects/version'
|
|
4
4
|
require 'semver_dialects/base_version'
|
5
5
|
require 'semver_dialects/maven'
|
6
6
|
require 'semver_dialects/rpm'
|
7
|
+
require 'semver_dialects/apk'
|
7
8
|
require 'semver_dialects/semver2'
|
8
9
|
require 'semver_dialects/semantic_version'
|
9
10
|
require 'semver_dialects/boundary'
|
@@ -28,6 +29,16 @@ module SemverDialects
|
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
32
|
+
class UnsupportedVersionError < Error
|
33
|
+
def initialize(raw_version)
|
34
|
+
@raw_version = raw_version
|
35
|
+
end
|
36
|
+
|
37
|
+
def message
|
38
|
+
"unsupported version '#{@raw_version}'"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
31
42
|
class InvalidVersionError < Error
|
32
43
|
def initialize(raw_version)
|
33
44
|
@raw_version = raw_version
|
@@ -86,7 +97,7 @@ module SemverDialects
|
|
86
97
|
end
|
87
98
|
|
88
99
|
def self.os_pkg_version_satisfies?(typ, raw_ver, raw_constraint)
|
89
|
-
return unless %w[deb rpm].include?(typ)
|
100
|
+
return unless %w[deb rpm apk].include?(typ)
|
90
101
|
# we only support the less than operator, because that's the only one currently output
|
91
102
|
# by the advisory exporter for operating system packages.
|
92
103
|
raise SemverDialects::InvalidConstraintError, raw_constraint unless raw_constraint[0] == '<'
|
@@ -101,6 +112,11 @@ module SemverDialects
|
|
101
112
|
v1 = Rpm::VersionParser.parse(raw_ver)
|
102
113
|
v2 = Rpm::VersionParser.parse(raw_constraint[1..])
|
103
114
|
|
115
|
+
v1 < v2
|
116
|
+
when 'apk'
|
117
|
+
v1 = Apk::VersionParser.parse(raw_ver)
|
118
|
+
v2 = Apk::VersionParser.parse(raw_constraint[1..])
|
119
|
+
|
104
120
|
v1 < v2
|
105
121
|
end
|
106
122
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: semver_dialects
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julian Thome
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date: 2024-07-
|
13
|
+
date: 2024-07-10 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: pastel
|
@@ -177,6 +177,7 @@ extensions: []
|
|
177
177
|
extra_rdoc_files: []
|
178
178
|
files:
|
179
179
|
- lib/semver_dialects.rb
|
180
|
+
- lib/semver_dialects/apk.rb
|
180
181
|
- lib/semver_dialects/base_version.rb
|
181
182
|
- lib/semver_dialects/boundary.rb
|
182
183
|
- lib/semver_dialects/cli.rb
|