metadata-json-lint 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +13 -5
- data/lib/metadata_json_lint.rb +2 -18
- metadata +7 -37
- data/.gitignore +0 -4
- data/Gemfile +0 -3
- data/LICENSE +0 -13
- data/README.md +0 -62
- data/lib/metadata-json-lint/semantic/version.rb +0 -170
- data/lib/metadata-json-lint/semantic/version_range.rb +0 -423
- data/metadata-json-lint.gemspec +0 -17
- data/tests/metadata-bad_license.json +0 -87
- data/tests/metadata-broken.json +0 -87
- data/tests/metadata-duplicate-dep.json +0 -91
- data/tests/metadata-multiple_problems.json +0 -86
- data/tests/metadata-noname.json +0 -86
- data/tests/metadata-openenddep.json +0 -87
- data/tests/metadata-perfect.json +0 -87
- data/tests/metadata-types.json +0 -88
- data/tests/test.sh +0 -83
checksums.yaml
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NTcyZGJkMmRhYjQ4YzU5NjYyODc3MmQ4MDcyOGQ5NWVlODA5NjFkNQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
OWQ4YmQzYjQ2ZDkxNzA2MDA2NzVhZjczODg0ZWQ3OTk5YjA1OTk5ZA==
|
5
7
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NjUzZmVlNGExZjU2ZjA1ZjFmZmU5MWU3NmNjZTc1YTNhMDNmOGIyYjM2MmFk
|
10
|
+
YWZmMjZlYjY1MzgzYzJlZDA4Yzg3ZTUyMWI0Mjk5MTUyMTU5ZTE1YzIxYjE0
|
11
|
+
N2M4MjE5MGZlZTYxNDVmMDI2ODU1OTQ3YzA0NWE3YzZiNDRhMzk=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NzAxYjEwZjEzOTIyZjgzNzg4ZWRkZThjMDZhZDYwMTNjNDgxMTZlYzNhMzc4
|
14
|
+
MmZlZDNkNGUzMWNmYWNiN2JmMTE2ZjJjN2Q0NDExZDA1NDA3ZTI4N2MxODFl
|
15
|
+
ZjMwNDI5ZDhlMDA2ZWY2OTA4MjExNjIyM2FjZGQ3YjllOTU3MTY=
|
data/lib/metadata_json_lint.rb
CHANGED
@@ -1,15 +1,12 @@
|
|
1
1
|
require 'json'
|
2
2
|
require 'spdx-licenses'
|
3
3
|
require 'optparse'
|
4
|
-
require 'metadata-json-lint/semantic/version'
|
5
|
-
require 'metadata-json-lint/semantic/version_range'
|
6
4
|
|
7
5
|
module MetadataJsonLint
|
8
6
|
def run
|
9
7
|
options = {
|
10
|
-
:fail_on_warnings
|
11
|
-
:strict_license
|
12
|
-
:strict_dependency => false
|
8
|
+
:fail_on_warnings => true,
|
9
|
+
:strict_license => true
|
13
10
|
}
|
14
11
|
|
15
12
|
OptionParser.new do |opts|
|
@@ -19,10 +16,6 @@ module MetadataJsonLint
|
|
19
16
|
options[:strict_license] = v
|
20
17
|
end
|
21
18
|
|
22
|
-
opts.on("--[no-]strict-dependency", "Strict dependency version checking") do |v|
|
23
|
-
options[:strict_dependency] = v
|
24
|
-
end
|
25
|
-
|
26
19
|
opts.on("--[no-]fail-on-warnings", "Fail on any warnings") do |v|
|
27
20
|
options[:fail_on_warnings] = v
|
28
21
|
end
|
@@ -70,15 +63,6 @@ module MetadataJsonLint
|
|
70
63
|
dep_names << dep['name']
|
71
64
|
end
|
72
65
|
|
73
|
-
# Check for open endend versions in dependencies.
|
74
|
-
# https://docs.puppetlabs.com/puppet/latest/reference/modules_publishing.html#dependencies-in-metadatajson
|
75
|
-
deps.each do |dep|
|
76
|
-
if Semantic::VersionRange.parse(dep['version_requirement']).open_end?
|
77
|
-
puts "Warning: Dependency #{dep['name']} has an open ended dependency version requirement #{dep['version_requirement']}"
|
78
|
-
error_state = true if @options[:strict_dependency]
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
66
|
# Deprecated fields
|
83
67
|
# From: https://docs.puppetlabs.com/puppet/latest/reference/modules_publishing.html#write-a-metadatajson-file
|
84
68
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: metadata-json-lint
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Spencer Krum
|
@@ -15,42 +15,28 @@ dependencies:
|
|
15
15
|
name: spdx-licenses
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- -
|
18
|
+
- - ~>
|
19
19
|
- !ruby/object:Gem::Version
|
20
20
|
version: '1.0'
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
|
-
- -
|
26
|
-
- !ruby/object:Gem::Version
|
27
|
-
version: '1.0'
|
28
|
-
- !ruby/object:Gem::Dependency
|
29
|
-
name: semantic
|
30
|
-
requirement: !ruby/object:Gem::Requirement
|
31
|
-
requirements:
|
32
|
-
- - "~>"
|
33
|
-
- !ruby/object:Gem::Version
|
34
|
-
version: '1.0'
|
35
|
-
type: :runtime
|
36
|
-
prerelease: false
|
37
|
-
version_requirements: !ruby/object:Gem::Requirement
|
38
|
-
requirements:
|
39
|
-
- - "~>"
|
25
|
+
- - ~>
|
40
26
|
- !ruby/object:Gem::Version
|
41
27
|
version: '1.0'
|
42
28
|
- !ruby/object:Gem::Dependency
|
43
29
|
name: json
|
44
30
|
requirement: !ruby/object:Gem::Requirement
|
45
31
|
requirements:
|
46
|
-
- -
|
32
|
+
- - ! '>='
|
47
33
|
- !ruby/object:Gem::Version
|
48
34
|
version: '0'
|
49
35
|
type: :runtime
|
50
36
|
prerelease: false
|
51
37
|
version_requirements: !ruby/object:Gem::Requirement
|
52
38
|
requirements:
|
53
|
-
- -
|
39
|
+
- - ! '>='
|
54
40
|
- !ruby/object:Gem::Version
|
55
41
|
version: '0'
|
56
42
|
description: Utility to verify Puppet metadata.json files
|
@@ -60,25 +46,9 @@ executables:
|
|
60
46
|
extensions: []
|
61
47
|
extra_rdoc_files: []
|
62
48
|
files:
|
63
|
-
- ".gitignore"
|
64
|
-
- Gemfile
|
65
|
-
- LICENSE
|
66
|
-
- README.md
|
67
49
|
- bin/metadata-json-lint
|
68
50
|
- lib/metadata-json-lint/rake_task.rb
|
69
|
-
- lib/metadata-json-lint/semantic/version.rb
|
70
|
-
- lib/metadata-json-lint/semantic/version_range.rb
|
71
51
|
- lib/metadata_json_lint.rb
|
72
|
-
- metadata-json-lint.gemspec
|
73
|
-
- tests/metadata-bad_license.json
|
74
|
-
- tests/metadata-broken.json
|
75
|
-
- tests/metadata-duplicate-dep.json
|
76
|
-
- tests/metadata-multiple_problems.json
|
77
|
-
- tests/metadata-noname.json
|
78
|
-
- tests/metadata-openenddep.json
|
79
|
-
- tests/metadata-perfect.json
|
80
|
-
- tests/metadata-types.json
|
81
|
-
- tests/test.sh
|
82
52
|
homepage: http://github.com/nibalizer/metadata-json-lint
|
83
53
|
licenses:
|
84
54
|
- Apache-2.0
|
@@ -89,12 +59,12 @@ require_paths:
|
|
89
59
|
- lib
|
90
60
|
required_ruby_version: !ruby/object:Gem::Requirement
|
91
61
|
requirements:
|
92
|
-
- -
|
62
|
+
- - ! '>='
|
93
63
|
- !ruby/object:Gem::Version
|
94
64
|
version: '0'
|
95
65
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
66
|
requirements:
|
97
|
-
- -
|
67
|
+
- - ! '>='
|
98
68
|
- !ruby/object:Gem::Version
|
99
69
|
version: '0'
|
100
70
|
requirements: []
|
data/.gitignore
DELETED
data/Gemfile
DELETED
data/LICENSE
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
Copyright 2014 HP Development Corporation L.P.
|
2
|
-
|
3
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
-
you may not use this software except in compliance with the License.
|
5
|
-
You may obtain a copy of the License at
|
6
|
-
|
7
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
-
|
9
|
-
Unless required by applicable law or agreed to in writing, software
|
10
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
-
See the License for the specific language governing permissions and
|
13
|
-
limitations under the License.
|
data/README.md
DELETED
@@ -1,62 +0,0 @@
|
|
1
|
-
metadata-json-linter
|
2
|
-
--------------------
|
3
|
-
|
4
|
-
Simple tool to validate and lint metadata.json files in Puppet modules.
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
install
|
9
|
-
-------
|
10
|
-
|
11
|
-
```shell
|
12
|
-
gem install metadata-json-lint
|
13
|
-
```
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
usage
|
18
|
-
-----
|
19
|
-
|
20
|
-
```shell
|
21
|
-
metadata-json-lint /path/too/metadata.json
|
22
|
-
```
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
rake
|
27
|
-
----
|
28
|
-
|
29
|
-
|
30
|
-
```ruby
|
31
|
-
task :metadata do
|
32
|
-
sh "metadata-json-lint metadata.json"
|
33
|
-
end
|
34
|
-
```
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
options
|
39
|
-
-------
|
40
|
-
|
41
|
-
|
42
|
-
```
|
43
|
-
--no-fail-on-warnings
|
44
|
-
--strict-dependency
|
45
|
-
--no-strict-license
|
46
|
-
```
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
contributors
|
51
|
-
------------
|
52
|
-
|
53
|
-
A Big thank you to the code contributors:
|
54
|
-
|
55
|
-
Richard Pijnenburg
|
56
|
-
Dominic Cleal
|
57
|
-
Igor Galić
|
58
|
-
Mike Arnold
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
@@ -1,170 +0,0 @@
|
|
1
|
-
require 'semantic'
|
2
|
-
module MetadataJsonLint
|
3
|
-
module Semantic
|
4
|
-
|
5
|
-
# @note Semantic::Version subclasses Numeric so that it has sane Range
|
6
|
-
# semantics in Ruby 1.9+.
|
7
|
-
class Version < Numeric
|
8
|
-
include Comparable
|
9
|
-
|
10
|
-
class ValidationFailure < ArgumentError; end
|
11
|
-
|
12
|
-
class << self
|
13
|
-
LOOSE_REGEX = /
|
14
|
-
\A
|
15
|
-
(\d+)[.](\d+)[.](\d+) # Major . Minor . Patch
|
16
|
-
(?: [-](.*?))? # Prerelease
|
17
|
-
(?: [+](.*?))? # Build
|
18
|
-
\Z
|
19
|
-
/x
|
20
|
-
|
21
|
-
# Parse a Semantic Version string.
|
22
|
-
#
|
23
|
-
# @param ver [String] the version string to parse
|
24
|
-
# @return [Version] a comparable {Version} object
|
25
|
-
def parse(ver)
|
26
|
-
match, major, minor, patch, prerelease, build = *ver.match(LOOSE_REGEX)
|
27
|
-
|
28
|
-
if match.nil?
|
29
|
-
raise 'Version numbers MUST begin with three dot-separated numbers'
|
30
|
-
elsif [major, minor, patch].any? { |x| x =~ /^0\d+/ }
|
31
|
-
raise 'Version numbers MUST NOT contain leading zeroes'
|
32
|
-
end
|
33
|
-
|
34
|
-
prerelease = parse_prerelease(prerelease) if prerelease
|
35
|
-
build = parse_build_metadata(build) if build
|
36
|
-
|
37
|
-
self.new(major.to_i, minor.to_i, patch.to_i, prerelease, build)
|
38
|
-
end
|
39
|
-
|
40
|
-
private
|
41
|
-
def parse_prerelease(prerelease)
|
42
|
-
subject = 'Prerelease identifiers'
|
43
|
-
prerelease = prerelease.split('.', -1)
|
44
|
-
|
45
|
-
if prerelease.empty? or prerelease.any? { |x| x.empty? }
|
46
|
-
raise "#{subject} MUST NOT be empty"
|
47
|
-
elsif prerelease.any? { |x| x =~ /[^0-9a-zA-Z-]/ }
|
48
|
-
raise "#{subject} MUST use only ASCII alphanumerics and hyphens"
|
49
|
-
elsif prerelease.any? { |x| x =~ /^0\d+$/ }
|
50
|
-
raise "#{subject} MUST NOT contain leading zeroes"
|
51
|
-
end
|
52
|
-
|
53
|
-
return prerelease.map { |x| x =~ /^\d+$/ ? x.to_i : x }
|
54
|
-
end
|
55
|
-
|
56
|
-
def parse_build_metadata(build)
|
57
|
-
subject = 'Build identifiers'
|
58
|
-
build = build.split('.', -1)
|
59
|
-
|
60
|
-
if build.empty? or build.any? { |x| x.empty? }
|
61
|
-
raise "#{subject} MUST NOT be empty"
|
62
|
-
elsif build.any? { |x| x =~ /[^0-9a-zA-Z-]/ }
|
63
|
-
raise "#{subject} MUST use only ASCII alphanumerics and hyphens"
|
64
|
-
end
|
65
|
-
|
66
|
-
return build
|
67
|
-
end
|
68
|
-
|
69
|
-
def raise(msg)
|
70
|
-
super ValidationFailure, msg, caller.drop_while { |x| x !~ /\bparse\b/ }
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
attr_reader :major, :minor, :patch
|
75
|
-
|
76
|
-
def initialize(major, minor, patch, prerelease = nil, build = nil)
|
77
|
-
@major = major
|
78
|
-
@minor = minor
|
79
|
-
@patch = patch
|
80
|
-
@prerelease = prerelease
|
81
|
-
@build = build
|
82
|
-
end
|
83
|
-
|
84
|
-
def next(part)
|
85
|
-
case part
|
86
|
-
when :major
|
87
|
-
self.class.new(@major.next, 0, 0)
|
88
|
-
when :minor
|
89
|
-
self.class.new(@major, @minor.next, 0)
|
90
|
-
when :patch
|
91
|
-
self.class.new(@major, @minor, @patch.next)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
def prerelease
|
96
|
-
@prerelease && @prerelease.join('.')
|
97
|
-
end
|
98
|
-
|
99
|
-
# @return [Boolean] true if this is a stable release
|
100
|
-
def stable?
|
101
|
-
@prerelease.nil?
|
102
|
-
end
|
103
|
-
|
104
|
-
def build
|
105
|
-
@build && @build.join('.')
|
106
|
-
end
|
107
|
-
|
108
|
-
def <=>(other)
|
109
|
-
return self.major <=> other.major unless self.major == other.major
|
110
|
-
return self.minor <=> other.minor unless self.minor == other.minor
|
111
|
-
return self.patch <=> other.patch unless self.patch == other.patch
|
112
|
-
return compare_prerelease(other)
|
113
|
-
end
|
114
|
-
|
115
|
-
def to_s
|
116
|
-
"#{major}.#{minor}.#{patch}" +
|
117
|
-
(@prerelease.nil? || prerelease.empty? ? '' : "-" + prerelease) +
|
118
|
-
(@build.nil? || build.empty? ? '' : "+" + build )
|
119
|
-
end
|
120
|
-
|
121
|
-
def hash
|
122
|
-
self.to_s.hash
|
123
|
-
end
|
124
|
-
|
125
|
-
private
|
126
|
-
# This is a hack; tildes sort later than any valid identifier. The
|
127
|
-
# advantage is that we don't need to handle stable vs. prerelease
|
128
|
-
# comparisons separately.
|
129
|
-
@@STABLE_RELEASE = [ '~' ].freeze
|
130
|
-
|
131
|
-
def compare_prerelease(other)
|
132
|
-
all_mine = @prerelease || @@STABLE_RELEASE
|
133
|
-
all_yours = other.instance_variable_get(:@prerelease) || @@STABLE_RELEASE
|
134
|
-
|
135
|
-
# Precedence is determined by comparing each dot separated identifier from
|
136
|
-
# left to right...
|
137
|
-
size = [ all_mine.size, all_yours.size ].max
|
138
|
-
Array.new(size).zip(all_mine, all_yours) do |_, mine, yours|
|
139
|
-
|
140
|
-
# ...until a difference is found.
|
141
|
-
next if mine == yours
|
142
|
-
|
143
|
-
# Numbers are compared numerically, strings are compared ASCIIbetically.
|
144
|
-
if mine.class == yours.class
|
145
|
-
return mine <=> yours
|
146
|
-
|
147
|
-
# A larger set of pre-release fields has a higher precedence.
|
148
|
-
elsif mine.nil?
|
149
|
-
return -1
|
150
|
-
elsif yours.nil?
|
151
|
-
return 1
|
152
|
-
|
153
|
-
# Numeric identifiers always have lower precedence than non-numeric.
|
154
|
-
elsif mine.is_a? Numeric
|
155
|
-
return -1
|
156
|
-
elsif yours.is_a? Numeric
|
157
|
-
return 1
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
return 0
|
162
|
-
end
|
163
|
-
|
164
|
-
def first_prerelease
|
165
|
-
self.class.new(@major, @minor, @patch, [])
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
end
|
@@ -1,423 +0,0 @@
|
|
1
|
-
require 'semantic'
|
2
|
-
module MetadataJsonLint
|
3
|
-
module Semantic
|
4
|
-
class VersionRange < Range
|
5
|
-
class << self
|
6
|
-
# Parses a version range string into a comparable {VersionRange} instance.
|
7
|
-
#
|
8
|
-
# Currently parsed version range string may take any of the following:
|
9
|
-
# forms:
|
10
|
-
#
|
11
|
-
# * Regular Semantic Version strings
|
12
|
-
# * ex. `"1.0.0"`, `"1.2.3-pre"`
|
13
|
-
# * Partial Semantic Version strings
|
14
|
-
# * ex. `"1.0.x"`, `"1"`, `"2.X"`
|
15
|
-
# * Inequalities
|
16
|
-
# * ex. `"> 1.0.0"`, `"<3.2.0"`, `">=4.0.0"`
|
17
|
-
# * Approximate Versions
|
18
|
-
# * ex. `"~1.0.0"`, `"~ 3.2.0"`, `"~4.0.0"`
|
19
|
-
# * Inclusive Ranges
|
20
|
-
# * ex. `"1.0.0 - 1.3.9"`
|
21
|
-
# * Range Intersections
|
22
|
-
# * ex. `">1.0.0 <=2.3.0"`
|
23
|
-
#
|
24
|
-
# @param range_str [String] the version range string to parse
|
25
|
-
# @return [VersionRange] a new {VersionRange} instance
|
26
|
-
def parse(range_str)
|
27
|
-
partial = '\d+(?:[.]\d+)?(?:[.][x]|[.]\d+(?:[-][0-9a-z.-]*)?)?'
|
28
|
-
exact = '\d+[.]\d+[.]\d+(?:[-][0-9a-z.-]*)?'
|
29
|
-
|
30
|
-
range = range_str.gsub(/([(><=~])[ ]+/, '\1')
|
31
|
-
range = range.gsub(/ - /, '#').strip
|
32
|
-
|
33
|
-
return case range
|
34
|
-
when /\A(#{partial})\Z/i
|
35
|
-
parse_loose_version_expression($1)
|
36
|
-
when /\A([><][=]?)(#{exact})\Z/i
|
37
|
-
parse_inequality_expression($1, $2)
|
38
|
-
when /\A~(#{partial})\Z/i
|
39
|
-
parse_reasonably_close_expression($1)
|
40
|
-
when /\A(#{exact})#(#{exact})\Z/i
|
41
|
-
parse_inclusive_range_expression($1, $2)
|
42
|
-
when /[ ]+/
|
43
|
-
parse_intersection_expression(range)
|
44
|
-
else
|
45
|
-
raise ArgumentError
|
46
|
-
end
|
47
|
-
|
48
|
-
rescue ArgumentError
|
49
|
-
raise ArgumentError, "Unparsable version range: #{range_str.inspect}"
|
50
|
-
end
|
51
|
-
|
52
|
-
private
|
53
|
-
|
54
|
-
# Creates a new {VersionRange} from a range intersection expression.
|
55
|
-
#
|
56
|
-
# @param expr [String] a range intersection expression
|
57
|
-
# @return [VersionRange] a version range representing `expr`
|
58
|
-
def parse_intersection_expression(expr)
|
59
|
-
expr.split(/[ ]+/).map { |x| parse(x) }.inject { |a,b| a & b }
|
60
|
-
end
|
61
|
-
|
62
|
-
# Creates a new {VersionRange} from a "loose" description of a Semantic
|
63
|
-
# Version number.
|
64
|
-
#
|
65
|
-
# @see .process_loose_expr
|
66
|
-
#
|
67
|
-
# @param expr [String] a "loose" version expression
|
68
|
-
# @return [VersionRange] a version range representing `expr`
|
69
|
-
def parse_loose_version_expression(expr)
|
70
|
-
start, finish = process_loose_expr(expr)
|
71
|
-
|
72
|
-
if start.stable?
|
73
|
-
start = start.send(:first_prerelease)
|
74
|
-
end
|
75
|
-
|
76
|
-
if finish.stable?
|
77
|
-
exclude = true
|
78
|
-
finish = finish.send(:first_prerelease)
|
79
|
-
end
|
80
|
-
|
81
|
-
self.new(start, finish, exclude)
|
82
|
-
end
|
83
|
-
|
84
|
-
# Creates an open-ended version range from an inequality expression.
|
85
|
-
#
|
86
|
-
# @overload parse_inequality_expression('<', expr)
|
87
|
-
# {include:.parse_lt_expression}
|
88
|
-
#
|
89
|
-
# @overload parse_inequality_expression('<=', expr)
|
90
|
-
# {include:.parse_lte_expression}
|
91
|
-
#
|
92
|
-
# @overload parse_inequality_expression('>', expr)
|
93
|
-
# {include:.parse_gt_expression}
|
94
|
-
#
|
95
|
-
# @overload parse_inequality_expression('>=', expr)
|
96
|
-
# {include:.parse_gte_expression}
|
97
|
-
#
|
98
|
-
# @param comp ['<', '<=', '>', '>='] an inequality operator
|
99
|
-
# @param expr [String] a "loose" version expression
|
100
|
-
# @return [VersionRange] a range covering all versions in the inequality
|
101
|
-
def parse_inequality_expression(comp, expr)
|
102
|
-
case comp
|
103
|
-
when '>'
|
104
|
-
parse_gt_expression(expr)
|
105
|
-
when '>='
|
106
|
-
parse_gte_expression(expr)
|
107
|
-
when '<'
|
108
|
-
parse_lt_expression(expr)
|
109
|
-
when '<='
|
110
|
-
parse_lte_expression(expr)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
# Returns a range covering all versions greater than the given `expr`.
|
115
|
-
#
|
116
|
-
# @param expr [String] the version to be greater than
|
117
|
-
# @return [VersionRange] a range covering all versions greater than the
|
118
|
-
# given `expr`
|
119
|
-
def parse_gt_expression(expr)
|
120
|
-
if expr =~ /^[^+]*-/
|
121
|
-
start = Version.parse("#{expr}.0")
|
122
|
-
else
|
123
|
-
start = process_loose_expr(expr).last.send(:first_prerelease)
|
124
|
-
end
|
125
|
-
|
126
|
-
self.new(start, MAX_VERSION)
|
127
|
-
end
|
128
|
-
|
129
|
-
# Returns a range covering all versions greater than or equal to the given
|
130
|
-
# `expr`.
|
131
|
-
#
|
132
|
-
# @param expr [String] the version to be greater than or equal to
|
133
|
-
# @return [VersionRange] a range covering all versions greater than or
|
134
|
-
# equal to the given `expr`
|
135
|
-
def parse_gte_expression(expr)
|
136
|
-
if expr =~ /^[^+]*-/
|
137
|
-
start = Version.parse(expr)
|
138
|
-
else
|
139
|
-
start = process_loose_expr(expr).first.send(:first_prerelease)
|
140
|
-
end
|
141
|
-
|
142
|
-
self.new(start, MAX_VERSION)
|
143
|
-
end
|
144
|
-
|
145
|
-
# Returns a range covering all versions less than the given `expr`.
|
146
|
-
#
|
147
|
-
# @param expr [String] the version to be less than
|
148
|
-
# @return [VersionRange] a range covering all versions less than the
|
149
|
-
# given `expr`
|
150
|
-
def parse_lt_expression(expr)
|
151
|
-
if expr =~ /^[^+]*-/
|
152
|
-
finish = Version.parse(expr)
|
153
|
-
else
|
154
|
-
finish = process_loose_expr(expr).first.send(:first_prerelease)
|
155
|
-
end
|
156
|
-
|
157
|
-
self.new(MIN_VERSION, finish, true)
|
158
|
-
end
|
159
|
-
|
160
|
-
# Returns a range covering all versions less than or equal to the given
|
161
|
-
# `expr`.
|
162
|
-
#
|
163
|
-
# @param expr [String] the version to be less than or equal to
|
164
|
-
# @return [VersionRange] a range covering all versions less than or equal
|
165
|
-
# to the given `expr`
|
166
|
-
def parse_lte_expression(expr)
|
167
|
-
if expr =~ /^[^+]*-/
|
168
|
-
finish = Version.parse(expr)
|
169
|
-
self.new(MIN_VERSION, finish)
|
170
|
-
else
|
171
|
-
finish = process_loose_expr(expr).last.send(:first_prerelease)
|
172
|
-
self.new(MIN_VERSION, finish, true)
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
# The "reasonably close" expression is used to designate ranges that have
|
177
|
-
# a reasonable proximity to the given "loose" version number. These take
|
178
|
-
# the form:
|
179
|
-
#
|
180
|
-
# ~[Version]
|
181
|
-
#
|
182
|
-
# The general semantics of these expressions are that the given version
|
183
|
-
# forms a lower bound for the range, and the upper bound is either the
|
184
|
-
# next version number increment (at whatever precision the expression
|
185
|
-
# provides) or the next stable version (in the case of a prerelease
|
186
|
-
# version).
|
187
|
-
#
|
188
|
-
# @example "Reasonably close" major version
|
189
|
-
# "~1" # => (>=1.0.0 <2.0.0)
|
190
|
-
# @example "Reasonably close" minor version
|
191
|
-
# "~1.2" # => (>=1.2.0 <1.3.0)
|
192
|
-
# @example "Reasonably close" patch version
|
193
|
-
# "~1.2.3" # => (1.2.3)
|
194
|
-
# @example "Reasonably close" prerelease version
|
195
|
-
# "~1.2.3-alpha" # => (>=1.2.3-alpha <1.2.4)
|
196
|
-
#
|
197
|
-
# @param expr [String] a "loose" expression to build the range around
|
198
|
-
# @return [VersionRange] a "reasonably close" version range
|
199
|
-
def parse_reasonably_close_expression(expr)
|
200
|
-
parsed, succ = process_loose_expr(expr)
|
201
|
-
|
202
|
-
if parsed.stable?
|
203
|
-
parsed = parsed.send(:first_prerelease)
|
204
|
-
succ = succ.send(:first_prerelease)
|
205
|
-
self.new(parsed, succ, true)
|
206
|
-
else
|
207
|
-
self.new(parsed, succ.next(:patch).send(:first_prerelease), true)
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
# An "inclusive range" expression takes two version numbers (or partial
|
212
|
-
# version numbers) and creates a range that covers all versions between
|
213
|
-
# them. These take the form:
|
214
|
-
#
|
215
|
-
# [Version] - [Version]
|
216
|
-
#
|
217
|
-
# @param start [String] a "loose" expresssion for the start of the range
|
218
|
-
# @param finish [String] a "loose" expression for the end of the range
|
219
|
-
# @return [VersionRange] a {VersionRange} covering `start` to `finish`
|
220
|
-
def parse_inclusive_range_expression(start, finish)
|
221
|
-
start, _ = process_loose_expr(start)
|
222
|
-
_, finish = process_loose_expr(finish)
|
223
|
-
|
224
|
-
start = start.send(:first_prerelease) if start.stable?
|
225
|
-
if finish.stable?
|
226
|
-
exclude = true
|
227
|
-
finish = finish.send(:first_prerelease)
|
228
|
-
end
|
229
|
-
|
230
|
-
self.new(start, finish, exclude)
|
231
|
-
end
|
232
|
-
|
233
|
-
# A "loose expression" is one that takes the form of all or part of a
|
234
|
-
# valid Semantic Version number. Particularly:
|
235
|
-
#
|
236
|
-
# * [Major].[Minor].[Patch]-[Prerelease]
|
237
|
-
# * [Major].[Minor].[Patch]
|
238
|
-
# * [Major].[Minor]
|
239
|
-
# * [Major]
|
240
|
-
#
|
241
|
-
# Various placeholders are also permitted in "loose expressions"
|
242
|
-
# (typically an 'x' or an asterisk).
|
243
|
-
#
|
244
|
-
# This method parses these expressions into a minimal and maximal version
|
245
|
-
# number pair.
|
246
|
-
#
|
247
|
-
# @todo Stabilize whether the second value is inclusive or exclusive
|
248
|
-
#
|
249
|
-
# @param expr [String] a string containing a "loose" version expression
|
250
|
-
# @return [(VersionNumber, VersionNumber)] a minimal and maximal
|
251
|
-
# version pair for the given expression
|
252
|
-
def process_loose_expr(expr)
|
253
|
-
case expr
|
254
|
-
when /^(\d+)(?:[.][xX*])?$/
|
255
|
-
expr = "#{$1}.0.0"
|
256
|
-
arity = :major
|
257
|
-
when /^(\d+[.]\d+)(?:[.][xX*])?$/
|
258
|
-
expr = "#{$1}.0"
|
259
|
-
arity = :minor
|
260
|
-
when /^\d+[.]\d+[.]\d+$/
|
261
|
-
arity = :patch
|
262
|
-
end
|
263
|
-
|
264
|
-
version = next_version = Version.parse(expr)
|
265
|
-
|
266
|
-
if arity
|
267
|
-
next_version = version.next(arity)
|
268
|
-
end
|
269
|
-
|
270
|
-
[ version, next_version ]
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
274
|
-
# Computes the intersection of a pair of ranges. If the ranges have no
|
275
|
-
# useful intersection, an empty range is returned.
|
276
|
-
#
|
277
|
-
# @param other [VersionRange] the range to intersect with
|
278
|
-
# @return [VersionRange] the common subset
|
279
|
-
def intersection(other)
|
280
|
-
raise NOT_A_VERSION_RANGE unless other.kind_of?(VersionRange)
|
281
|
-
|
282
|
-
if self.begin < other.begin
|
283
|
-
return other.intersection(self)
|
284
|
-
end
|
285
|
-
|
286
|
-
unless include?(other.begin) || other.include?(self.begin)
|
287
|
-
return EMPTY_RANGE
|
288
|
-
end
|
289
|
-
|
290
|
-
endpoint = ends_before?(other) ? self : other
|
291
|
-
VersionRange.new(self.begin, endpoint.end, endpoint.exclude_end?)
|
292
|
-
end
|
293
|
-
alias :& :intersection
|
294
|
-
|
295
|
-
# Returns a string representation of this range, prefering simple common
|
296
|
-
# expressions for comprehension.
|
297
|
-
#
|
298
|
-
# @return [String] a range expression representing this VersionRange
|
299
|
-
def to_s
|
300
|
-
start, finish = self.begin, self.end
|
301
|
-
inclusive = exclude_end? ? '' : '='
|
302
|
-
|
303
|
-
case
|
304
|
-
when EMPTY_RANGE == self
|
305
|
-
"<0.0.0"
|
306
|
-
when exact_version?, patch_version?
|
307
|
-
"#{ start }"
|
308
|
-
when minor_version?
|
309
|
-
"#{ start }".sub(/.0$/, '.x')
|
310
|
-
when major_version?
|
311
|
-
"#{ start }".sub(/.0.0$/, '.x')
|
312
|
-
when open_end? && start.to_s =~ /-.*[.]0$/
|
313
|
-
">#{ start }".sub(/.0$/, '')
|
314
|
-
when open_end?
|
315
|
-
">=#{ start }"
|
316
|
-
when open_begin?
|
317
|
-
"<#{ inclusive }#{ finish }"
|
318
|
-
else
|
319
|
-
">=#{ start } <#{ inclusive }#{ finish }"
|
320
|
-
end
|
321
|
-
end
|
322
|
-
alias :inspect :to_s
|
323
|
-
|
324
|
-
# The lowest precedence Version possible
|
325
|
-
MIN_VERSION = Version.new(0, 0, 0, []).freeze
|
326
|
-
|
327
|
-
# The highest precedence Version possible
|
328
|
-
MAX_VERSION = Version.new((1.0/0.0), 0, 0).freeze
|
329
|
-
|
330
|
-
# Determines whether this {VersionRange} has an earlier endpoint than the
|
331
|
-
# give `other` range.
|
332
|
-
#
|
333
|
-
# @param other [VersionRange] the range to compare against
|
334
|
-
# @return [Boolean] true if the endpoint for this range is less than or
|
335
|
-
# equal to the endpoint of the `other` range.
|
336
|
-
def ends_before?(other)
|
337
|
-
self.end < other.end || (self.end == other.end && self.exclude_end?)
|
338
|
-
end
|
339
|
-
|
340
|
-
# Describes whether this range has an upper limit.
|
341
|
-
# @return [Boolean] true if this range has no upper limit
|
342
|
-
def open_end?
|
343
|
-
self.end == MAX_VERSION
|
344
|
-
end
|
345
|
-
|
346
|
-
# Describes whether this range has a lower limit.
|
347
|
-
# @return [Boolean] true if this range has no lower limit
|
348
|
-
def open_begin?
|
349
|
-
self.begin == MIN_VERSION
|
350
|
-
end
|
351
|
-
|
352
|
-
# Describes whether this range follows the patterns for matching all
|
353
|
-
# releases with the same exact version.
|
354
|
-
# @return [Boolean] true if this range matches only a single exact version
|
355
|
-
def exact_version?
|
356
|
-
self.begin == self.end
|
357
|
-
end
|
358
|
-
|
359
|
-
# Describes whether this range follows the patterns for matching all
|
360
|
-
# releases with the same major version.
|
361
|
-
# @return [Boolean] true if this range matches only a single major version
|
362
|
-
def major_version?
|
363
|
-
start, finish = self.begin, self.end
|
364
|
-
|
365
|
-
exclude_end? &&
|
366
|
-
start.major.next == finish.major &&
|
367
|
-
same_minor? && start.minor == 0 &&
|
368
|
-
same_patch? && start.patch == 0 &&
|
369
|
-
[start.prerelease, finish.prerelease] == ['', '']
|
370
|
-
end
|
371
|
-
|
372
|
-
# Describes whether this range follows the patterns for matching all
|
373
|
-
# releases with the same minor version.
|
374
|
-
# @return [Boolean] true if this range matches only a single minor version
|
375
|
-
def minor_version?
|
376
|
-
start, finish = self.begin, self.end
|
377
|
-
|
378
|
-
exclude_end? &&
|
379
|
-
same_major? &&
|
380
|
-
start.minor.next == finish.minor &&
|
381
|
-
same_patch? && start.patch == 0 &&
|
382
|
-
[start.prerelease, finish.prerelease] == ['', '']
|
383
|
-
end
|
384
|
-
|
385
|
-
# Describes whether this range follows the patterns for matching all
|
386
|
-
# releases with the same patch version.
|
387
|
-
# @return [Boolean] true if this range matches only a single patch version
|
388
|
-
def patch_version?
|
389
|
-
start, finish = self.begin, self.end
|
390
|
-
|
391
|
-
exclude_end? &&
|
392
|
-
same_major? &&
|
393
|
-
same_minor? &&
|
394
|
-
start.patch.next == finish.patch &&
|
395
|
-
[start.prerelease, finish.prerelease] == ['', '']
|
396
|
-
end
|
397
|
-
|
398
|
-
# @return [Boolean] true if `begin` and `end` share the same major verion
|
399
|
-
def same_major?
|
400
|
-
self.begin.major == self.end.major
|
401
|
-
end
|
402
|
-
|
403
|
-
# @return [Boolean] true if `begin` and `end` share the same minor verion
|
404
|
-
def same_minor?
|
405
|
-
self.begin.minor == self.end.minor
|
406
|
-
end
|
407
|
-
|
408
|
-
# @return [Boolean] true if `begin` and `end` share the same patch verion
|
409
|
-
def same_patch?
|
410
|
-
self.begin.patch == self.end.patch
|
411
|
-
end
|
412
|
-
|
413
|
-
undef :to_a
|
414
|
-
|
415
|
-
NOT_A_VERSION_RANGE = ArgumentError.new("value must be a #{VersionRange}")
|
416
|
-
|
417
|
-
public
|
418
|
-
|
419
|
-
# A range that matches no versions
|
420
|
-
EMPTY_RANGE = VersionRange.parse('< 0.0.0').freeze
|
421
|
-
end
|
422
|
-
end
|
423
|
-
end
|