semver_dialects 3.0.2 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1d29656d2bd4bdc5bb1cd50c3cf3853e192fbb7de944b4495c816f424d710648
4
- data.tar.gz: adbbb1f25f05a91ac195a6e8becb823b4f412a40476a26697547d06556253868
3
+ metadata.gz: f1f8032a4c9d878a2d87171d58bcd60d34d23797e7a190bd4f71983ece8631d4
4
+ data.tar.gz: f14c6e7ffc8782d8c4c3c8a439cb4cf807470157e6cd86b420cf2b8aa32b9322
5
5
  SHA512:
6
- metadata.gz: 585e0ad23e05cbd4bade3aaf925bd38b07af390de78a7a28446cb6dad50b05a99155d8744d497fcbf6377e2013bb5740fc4bb140425f52217f5bb35312af3c53
7
- data.tar.gz: d17f636215c7c9d338819ab56ed8bbdc6f1349bfadb34c15a860d9398d2afb3a41f4c6bc521807e3e23ee36a19f9370c295c12485d9e7de5db95fef5af3b2c22
6
+ metadata.gz: e36e7b55574b064ac14c2a1bbe0e8d2bd9fcf5a22a155b42a1623029f939e54fdac6ac76ef19a6d391de0a0a4fa0801383b72627a583a2520b6cc94de72f55cb
7
+ data.tar.gz: af976bec11fc7bc8eba97c7afa17a207713ed22d386a8ae9701826cfd53c23ad86fb246fbebb84e77dca9c693422939ca639a5859ecabb3e5825fd9137bd8af9
@@ -0,0 +1,156 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'strscan'
4
+
5
+ module SemverDialects
6
+ module Rpm
7
+ module TokenPairComparison
8
+ # Token can be either alphabets, integers or tilde.
9
+ # Caret is currently not supported. More details here https://gitlab.com/gitlab-org/gitlab/-/issues/428941#note_1882343489
10
+ # Precedence: numeric token > string token > no token > tilda (~)
11
+ def compare_token_pair(a, b)
12
+ return 1 if a != '~' && b == '~'
13
+ return -1 if a == '~' && b != '~'
14
+
15
+ return 1 if !a.nil? && b.nil?
16
+ return -1 if a.nil? && !b.nil?
17
+
18
+ return 1 if a.is_a?(Integer) && b.is_a?(String)
19
+ return -1 if a.is_a?(String) && b.is_a?(Integer)
20
+
21
+ # Remaining scenario are tokens of the same type ie Integer or String. Use <=> to compare
22
+ a <=> b
23
+ end
24
+ end
25
+
26
+ # This implementation references `go-rpm-version` https://github.com/knqyf263/go-rpm-version
27
+ # Which is based on the official `rpmvercmp` https://github.com/rpm-software-management/rpm/blob/master/rpmio/rpmvercmp.c implementation
28
+ # rpm versioning schema can be found here https://github.com/rpm-software-management/rpm/blob/master/docs/manual/dependencies.md#versioning
29
+ # Details on how the caret and tilde symbols are handled can be found here https://docs.fedoraproject.org/en-US/packaging-guidelines/Versioning/#_handling_non_sorting_versions_with_tilde_dot_and_caret
30
+ class Version < BaseVersion
31
+ include TokenPairComparison
32
+
33
+ attr_reader :tokens, :addition, :epoch
34
+
35
+ def initialize(tokens, epoch: nil, release_tag: nil)
36
+ @tokens = tokens
37
+ @addition = release_tag
38
+ @epoch = epoch
39
+ end
40
+
41
+ def <=>(other)
42
+ # Compare epoch first
43
+ epoch_cmp = compare_epochs(epoch, other.epoch)
44
+ return epoch_cmp unless epoch_cmp.zero?
45
+
46
+ # Then compare version
47
+ cmp = compare_tokens(tokens, other.tokens)
48
+ return cmp unless cmp.zero?
49
+
50
+ # And finally compare release tags
51
+ compare_additions(addition, other.addition)
52
+ end
53
+
54
+ # Note that to_s does not accurately recreate the version string.
55
+ # More details here https://gitlab.com/gitlab-org/gitlab/-/issues/428941#note_1882343489
56
+ def to_s
57
+ main = if !epoch.nil?
58
+ "#{epoch}:" + tokens.join('.')
59
+ else
60
+ tokens.join('.')
61
+ end
62
+ main += "-#{addition.tokens.join('.')}" unless addition.nil?
63
+
64
+ # Remove . around ~
65
+ main.gsub(/\.~\./, '~')
66
+ end
67
+
68
+ private
69
+
70
+ def compare_epochs(a, b)
71
+ (a || 0) <=> (b || 0)
72
+ end
73
+ end
74
+
75
+ class ReleaseTag < BaseVersion
76
+ include TokenPairComparison
77
+
78
+ def initialize(tokens)
79
+ @tokens = tokens
80
+ end
81
+ end
82
+
83
+ class VersionParser
84
+ DASH = /-/
85
+ ALPHABET = /([a-zA-Z]+)/
86
+ TILDE = /~/
87
+ DIGIT = /([0-9]+)/
88
+ COLON = /:/
89
+ NON_ALPHANUMERIC_DASH_AND_TILDE = /[^a-zA-Z0-9~]+/
90
+
91
+ def self.parse(input)
92
+ new(input).parse
93
+ end
94
+
95
+ def initialize(input)
96
+ @scanner = StringScanner.new(input)
97
+ end
98
+
99
+ # parse splits the input string into epoch, version and release tag Eg: <epoch>:<version>-<release_tag>
100
+ # The version and release tag are split at the first `-` character if present
101
+ # With the segment before the first `-` being version while the other being release tag
102
+ # Subsequent `-` are disregarded
103
+ def parse
104
+ epoch = nil
105
+ if s = scanner.scan(/\d+:/)
106
+ epoch = s[..-2].to_i
107
+ end
108
+
109
+ # parse tokens until we reach the release tag, if any
110
+ tokens = parse_tokens(false)
111
+
112
+ # parse release tag
113
+ release_tag = nil
114
+ if scanner.rest?
115
+ release_tag = ReleaseTag.new(parse_tokens(true))
116
+ end
117
+
118
+ raise IncompleteScanError, scanner.rest if scanner.rest?
119
+
120
+ Version.new(tokens, epoch: epoch, release_tag: release_tag)
121
+ end
122
+
123
+ private
124
+
125
+ attr_reader :scanner
126
+
127
+ def parse_tokens(stop_at_release_tag)
128
+ tokens = []
129
+
130
+ until scanner.eos?
131
+ case
132
+ when (s = scanner.scan(DASH))
133
+ if !stop_at_release_tag
134
+ return tokens
135
+ end
136
+ # If release tag has been encountered, ignore subsequent dashes
137
+ when (s = scanner.scan(ALPHABET))
138
+ tokens << s
139
+ when (s = scanner.scan(TILDE))
140
+ tokens << s
141
+ when (s = scanner.scan(DIGIT))
142
+ tokens << s.to_i
143
+ when (s = scanner.scan(NON_ALPHANUMERIC_DASH_AND_TILDE))
144
+ # Non-ascii characters are considered equal
145
+ # so they are ignored when parsing versions
146
+ # https://github.com/rpm-software-management/rpm/blob/rpm-4.19.1.1-release/tests/rpmvercmp.at#L143
147
+ else
148
+ raise SemverDialects::IncompleteScanError, scanner.rest
149
+ end
150
+ end
151
+ tokens
152
+ end
153
+ end
154
+
155
+ end
156
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SemverDialects
4
- VERSION = '3.0.2'
4
+ VERSION = '3.1.0'
5
5
  end
@@ -3,6 +3,7 @@
3
3
  require 'semver_dialects/version'
4
4
  require 'semver_dialects/base_version'
5
5
  require 'semver_dialects/maven'
6
+ require 'semver_dialects/rpm'
6
7
  require 'semver_dialects/semver2'
7
8
  require 'semver_dialects/semantic_version'
8
9
  require 'semver_dialects/boundary'
@@ -85,15 +86,23 @@ module SemverDialects
85
86
  end
86
87
 
87
88
  def self.os_pkg_version_satisfies?(typ, raw_ver, raw_constraint)
88
- return unless typ == 'deb'
89
+ return unless %w[deb rpm].include?(typ)
89
90
  # we only support the less than operator, because that's the only one currently output
90
91
  # by the advisory exporter for operating system packages.
91
92
  raise SemverDialects::InvalidConstraintError, raw_constraint unless raw_constraint[0] == '<'
92
93
 
93
- v1 = DebVersion.new(raw_ver)
94
- v2 = DebVersion.new(raw_constraint[1..])
94
+ case typ
95
+ when 'deb'
96
+ v1 = DebVersion.new(raw_ver)
97
+ v2 = DebVersion.new(raw_constraint[1..])
98
+
99
+ v1 < v2
100
+ when 'rpm'
101
+ v1 = Rpm::VersionParser.parse(raw_ver)
102
+ v2 = Rpm::VersionParser.parse(raw_constraint[1..])
95
103
 
96
- v1 < v2
104
+ v1 < v2
105
+ end
97
106
  end
98
107
 
99
108
  # Parse a version according to the syntax type.
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.0.2
4
+ version: 3.1.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-06-17 00:00:00.000000000 Z
13
+ date: 2024-06-26 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: pastel
@@ -187,6 +187,7 @@ files:
187
187
  - lib/semver_dialects/interval_set.rb
188
188
  - lib/semver_dialects/interval_set_parser.rb
189
189
  - lib/semver_dialects/maven.rb
190
+ - lib/semver_dialects/rpm.rb
190
191
  - lib/semver_dialects/semantic_version.rb
191
192
  - lib/semver_dialects/semver2.rb
192
193
  - lib/semver_dialects/version.rb