rubygems-update 2.4.5 → 2.4.6
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.
Potentially problematic release.
This version of rubygems-update might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/History.txt +27 -0
- data/Manifest.txt +4 -0
- data/lib/rubygems.rb +2 -2
- data/lib/rubygems/basic_specification.rb +2 -3
- data/lib/rubygems/commands/help_command.rb +2 -2
- data/lib/rubygems/commands/open_command.rb +3 -1
- data/lib/rubygems/commands/yank_command.rb +1 -1
- data/lib/rubygems/compatibility.rb +1 -2
- data/lib/rubygems/dependency_installer.rb +11 -1
- data/lib/rubygems/installer.rb +1 -1
- data/lib/rubygems/package.rb +2 -1
- data/lib/rubygems/package/tar_writer.rb +4 -4
- data/lib/rubygems/path_support.rb +0 -7
- data/lib/rubygems/psych_additions.rb +1 -1
- data/lib/rubygems/remote_fetcher.rb +1 -1
- data/lib/rubygems/request_set.rb +10 -4
- data/lib/rubygems/request_set/gem_dependency_api.rb +4 -4
- data/lib/rubygems/request_set/lockfile.rb +52 -464
- data/lib/rubygems/request_set/lockfile/parser.rb +334 -0
- data/lib/rubygems/request_set/lockfile/tokenizer.rb +108 -0
- data/lib/rubygems/requirement.rb +12 -1
- data/lib/rubygems/security/signer.rb +1 -1
- data/lib/rubygems/specification.rb +12 -12
- data/lib/rubygems/test_case.rb +18 -1
- data/lib/rubygems/user_interaction.rb +0 -8
- data/test/rubygems/test_gem.rb +2 -5
- data/test/rubygems/test_gem_commands_open_command.rb +9 -3
- data/test/rubygems/test_gem_commands_pristine_command.rb +2 -2
- data/test/rubygems/test_gem_commands_unpack_command.rb +2 -2
- data/test/rubygems/test_gem_dependency_installer.rb +27 -1
- data/test/rubygems/test_gem_ext_cmake_builder.rb +1 -1
- data/test/rubygems/test_gem_installer.rb +1 -1
- data/test/rubygems/test_gem_package.rb +1 -1
- data/test/rubygems/test_gem_request_set_gem_dependency_api.rb +30 -11
- data/test/rubygems/test_gem_request_set_lockfile.rb +19 -824
- data/test/rubygems/test_gem_request_set_lockfile_parser.rb +543 -0
- data/test/rubygems/test_gem_request_set_lockfile_tokenizer.rb +305 -0
- data/test/rubygems/test_gem_requirement.rb +10 -0
- data/test/rubygems/test_gem_specification.rb +7 -1
- data/test/rubygems/test_gem_stub_specification.rb +1 -1
- data/test/rubygems/test_gem_uninstaller.rb +2 -2
- metadata +8 -2
@@ -0,0 +1,334 @@
|
|
1
|
+
class Gem::RequestSet::Lockfile::Parser
|
2
|
+
###
|
3
|
+
# Parses lockfiles
|
4
|
+
|
5
|
+
def initialize tokenizer, set, platforms, filename = nil
|
6
|
+
@tokens = tokenizer
|
7
|
+
@filename = filename
|
8
|
+
@set = set
|
9
|
+
@platforms = platforms
|
10
|
+
end
|
11
|
+
|
12
|
+
def parse
|
13
|
+
until @tokens.empty? do
|
14
|
+
type, data, column, line = get
|
15
|
+
|
16
|
+
case type
|
17
|
+
when :section then
|
18
|
+
@tokens.skip :newline
|
19
|
+
|
20
|
+
case data
|
21
|
+
when 'DEPENDENCIES' then
|
22
|
+
parse_DEPENDENCIES
|
23
|
+
when 'GIT' then
|
24
|
+
parse_GIT
|
25
|
+
when 'GEM' then
|
26
|
+
parse_GEM
|
27
|
+
when 'PATH' then
|
28
|
+
parse_PATH
|
29
|
+
when 'PLATFORMS' then
|
30
|
+
parse_PLATFORMS
|
31
|
+
else
|
32
|
+
type, = get until @tokens.empty? or peek.first == :section
|
33
|
+
end
|
34
|
+
else
|
35
|
+
raise "BUG: unhandled token #{type} (#{data.inspect}) at line #{line} column #{column}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# Gets the next token for a Lockfile
|
42
|
+
|
43
|
+
def get expected_types = nil, expected_value = nil # :nodoc:
|
44
|
+
current_token = @tokens.shift
|
45
|
+
|
46
|
+
type, value, column, line = current_token
|
47
|
+
|
48
|
+
if expected_types and not Array(expected_types).include? type then
|
49
|
+
unget current_token
|
50
|
+
|
51
|
+
message = "unexpected token [#{type.inspect}, #{value.inspect}], " +
|
52
|
+
"expected #{expected_types.inspect}"
|
53
|
+
|
54
|
+
raise Gem::RequestSet::Lockfile::ParseError.new message, column, line, @filename
|
55
|
+
end
|
56
|
+
|
57
|
+
if expected_value and expected_value != value then
|
58
|
+
unget current_token
|
59
|
+
|
60
|
+
message = "unexpected token [#{type.inspect}, #{value.inspect}], " +
|
61
|
+
"expected [#{expected_types.inspect}, " +
|
62
|
+
"#{expected_value.inspect}]"
|
63
|
+
|
64
|
+
raise Gem::RequestSet::Lockfile::ParseError.new message, column, line, @filename
|
65
|
+
end
|
66
|
+
|
67
|
+
current_token
|
68
|
+
end
|
69
|
+
|
70
|
+
def parse_DEPENDENCIES # :nodoc:
|
71
|
+
while not @tokens.empty? and :text == peek.first do
|
72
|
+
_, name, = get :text
|
73
|
+
|
74
|
+
requirements = []
|
75
|
+
|
76
|
+
case peek[0]
|
77
|
+
when :bang then
|
78
|
+
get :bang
|
79
|
+
|
80
|
+
requirements << pinned_requirement(name)
|
81
|
+
when :l_paren then
|
82
|
+
get :l_paren
|
83
|
+
|
84
|
+
loop do
|
85
|
+
_, op, = get :requirement
|
86
|
+
_, version, = get :text
|
87
|
+
|
88
|
+
requirements << "#{op} #{version}"
|
89
|
+
|
90
|
+
break unless peek[0] == :comma
|
91
|
+
|
92
|
+
get :comma
|
93
|
+
end
|
94
|
+
|
95
|
+
get :r_paren
|
96
|
+
|
97
|
+
if peek[0] == :bang then
|
98
|
+
requirements.clear
|
99
|
+
requirements << pinned_requirement(name)
|
100
|
+
|
101
|
+
get :bang
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
@set.gem name, *requirements
|
106
|
+
|
107
|
+
skip :newline
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def parse_GEM # :nodoc:
|
112
|
+
sources = []
|
113
|
+
|
114
|
+
while [:entry, 'remote'] == peek.first(2) do
|
115
|
+
get :entry, 'remote'
|
116
|
+
_, data, = get :text
|
117
|
+
skip :newline
|
118
|
+
|
119
|
+
sources << Gem::Source.new(data)
|
120
|
+
end
|
121
|
+
|
122
|
+
sources << Gem::Source.new(Gem::DEFAULT_HOST) if sources.empty?
|
123
|
+
|
124
|
+
get :entry, 'specs'
|
125
|
+
|
126
|
+
skip :newline
|
127
|
+
|
128
|
+
set = Gem::Resolver::LockSet.new sources
|
129
|
+
last_specs = nil
|
130
|
+
|
131
|
+
while not @tokens.empty? and :text == peek.first do
|
132
|
+
_, name, column, = get :text
|
133
|
+
|
134
|
+
case peek[0]
|
135
|
+
when :newline then
|
136
|
+
last_specs.each do |spec|
|
137
|
+
spec.add_dependency Gem::Dependency.new name if column == 6
|
138
|
+
end
|
139
|
+
when :l_paren then
|
140
|
+
get :l_paren
|
141
|
+
|
142
|
+
type, data, = get [:text, :requirement]
|
143
|
+
|
144
|
+
if type == :text and column == 4 then
|
145
|
+
version, platform = data.split '-', 2
|
146
|
+
|
147
|
+
platform =
|
148
|
+
platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY
|
149
|
+
|
150
|
+
last_specs = set.add name, version, platform
|
151
|
+
else
|
152
|
+
dependency = parse_dependency name, data
|
153
|
+
|
154
|
+
last_specs.each do |spec|
|
155
|
+
spec.add_dependency dependency
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
get :r_paren
|
160
|
+
else
|
161
|
+
raise "BUG: unknown token #{peek}"
|
162
|
+
end
|
163
|
+
|
164
|
+
skip :newline
|
165
|
+
end
|
166
|
+
|
167
|
+
@set.sets << set
|
168
|
+
end
|
169
|
+
|
170
|
+
def parse_GIT # :nodoc:
|
171
|
+
get :entry, 'remote'
|
172
|
+
_, repository, = get :text
|
173
|
+
|
174
|
+
skip :newline
|
175
|
+
|
176
|
+
get :entry, 'revision'
|
177
|
+
_, revision, = get :text
|
178
|
+
|
179
|
+
skip :newline
|
180
|
+
|
181
|
+
type, value = peek.first 2
|
182
|
+
if type == :entry and %w[branch ref tag].include? value then
|
183
|
+
get
|
184
|
+
get :text
|
185
|
+
|
186
|
+
skip :newline
|
187
|
+
end
|
188
|
+
|
189
|
+
get :entry, 'specs'
|
190
|
+
|
191
|
+
skip :newline
|
192
|
+
|
193
|
+
set = Gem::Resolver::GitSet.new
|
194
|
+
set.root_dir = @set.install_dir
|
195
|
+
|
196
|
+
last_spec = nil
|
197
|
+
|
198
|
+
while not @tokens.empty? and :text == peek.first do
|
199
|
+
_, name, column, = get :text
|
200
|
+
|
201
|
+
case peek[0]
|
202
|
+
when :newline then
|
203
|
+
last_spec.add_dependency Gem::Dependency.new name if column == 6
|
204
|
+
when :l_paren then
|
205
|
+
get :l_paren
|
206
|
+
|
207
|
+
type, data, = get [:text, :requirement]
|
208
|
+
|
209
|
+
if type == :text and column == 4 then
|
210
|
+
last_spec = set.add_git_spec name, data, repository, revision, true
|
211
|
+
else
|
212
|
+
dependency = parse_dependency name, data
|
213
|
+
|
214
|
+
last_spec.add_dependency dependency
|
215
|
+
end
|
216
|
+
|
217
|
+
get :r_paren
|
218
|
+
else
|
219
|
+
raise "BUG: unknown token #{peek}"
|
220
|
+
end
|
221
|
+
|
222
|
+
skip :newline
|
223
|
+
end
|
224
|
+
|
225
|
+
@set.sets << set
|
226
|
+
end
|
227
|
+
|
228
|
+
def parse_PATH # :nodoc:
|
229
|
+
get :entry, 'remote'
|
230
|
+
_, directory, = get :text
|
231
|
+
|
232
|
+
skip :newline
|
233
|
+
|
234
|
+
get :entry, 'specs'
|
235
|
+
|
236
|
+
skip :newline
|
237
|
+
|
238
|
+
set = Gem::Resolver::VendorSet.new
|
239
|
+
last_spec = nil
|
240
|
+
|
241
|
+
while not @tokens.empty? and :text == peek.first do
|
242
|
+
_, name, column, = get :text
|
243
|
+
|
244
|
+
case peek[0]
|
245
|
+
when :newline then
|
246
|
+
last_spec.add_dependency Gem::Dependency.new name if column == 6
|
247
|
+
when :l_paren then
|
248
|
+
get :l_paren
|
249
|
+
|
250
|
+
type, data, = get [:text, :requirement]
|
251
|
+
|
252
|
+
if type == :text and column == 4 then
|
253
|
+
last_spec = set.add_vendor_gem name, directory
|
254
|
+
else
|
255
|
+
dependency = parse_dependency name, data
|
256
|
+
|
257
|
+
last_spec.dependencies << dependency
|
258
|
+
end
|
259
|
+
|
260
|
+
get :r_paren
|
261
|
+
else
|
262
|
+
raise "BUG: unknown token #{peek}"
|
263
|
+
end
|
264
|
+
|
265
|
+
skip :newline
|
266
|
+
end
|
267
|
+
|
268
|
+
@set.sets << set
|
269
|
+
end
|
270
|
+
|
271
|
+
def parse_PLATFORMS # :nodoc:
|
272
|
+
while not @tokens.empty? and :text == peek.first do
|
273
|
+
_, name, = get :text
|
274
|
+
|
275
|
+
@platforms << name
|
276
|
+
|
277
|
+
skip :newline
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
##
|
282
|
+
# Parses the requirements following the dependency +name+ and the +op+ for
|
283
|
+
# the first token of the requirements and returns a Gem::Dependency object.
|
284
|
+
|
285
|
+
def parse_dependency name, op # :nodoc:
|
286
|
+
return Gem::Dependency.new name, op unless peek[0] == :text
|
287
|
+
|
288
|
+
_, version, = get :text
|
289
|
+
|
290
|
+
requirements = ["#{op} #{version}"]
|
291
|
+
|
292
|
+
while peek[0] == :comma do
|
293
|
+
get :comma
|
294
|
+
_, op, = get :requirement
|
295
|
+
_, version, = get :text
|
296
|
+
|
297
|
+
requirements << "#{op} #{version}"
|
298
|
+
end
|
299
|
+
|
300
|
+
Gem::Dependency.new name, requirements
|
301
|
+
end
|
302
|
+
|
303
|
+
private
|
304
|
+
|
305
|
+
def skip type # :nodoc:
|
306
|
+
@tokens.skip type
|
307
|
+
end
|
308
|
+
|
309
|
+
##
|
310
|
+
# Peeks at the next token for Lockfile
|
311
|
+
|
312
|
+
def peek # :nodoc:
|
313
|
+
@tokens.peek
|
314
|
+
end
|
315
|
+
|
316
|
+
def pinned_requirement name # :nodoc:
|
317
|
+
spec = @set.sets.select { |set|
|
318
|
+
Gem::Resolver::GitSet === set or
|
319
|
+
Gem::Resolver::VendorSet === set
|
320
|
+
}.map { |set|
|
321
|
+
set.specs[name]
|
322
|
+
}.compact.first
|
323
|
+
|
324
|
+
spec.version
|
325
|
+
end
|
326
|
+
|
327
|
+
##
|
328
|
+
# Ungets the last token retrieved by #get
|
329
|
+
|
330
|
+
def unget token # :nodoc:
|
331
|
+
@tokens.unshift token
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'strscan'
|
2
|
+
require 'rubygems/request_set/lockfile/parser'
|
3
|
+
|
4
|
+
class Gem::RequestSet::Lockfile::Tokenizer
|
5
|
+
def self.from_file file
|
6
|
+
new File.read(file), file
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize input, filename = nil, line = 0, pos = 0
|
10
|
+
@line = line
|
11
|
+
@line_pos = pos
|
12
|
+
@tokens = []
|
13
|
+
@filename = filename
|
14
|
+
tokenize input
|
15
|
+
end
|
16
|
+
|
17
|
+
def make_parser set, platforms
|
18
|
+
Gem::RequestSet::Lockfile::Parser.new self, set, platforms, @filename
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_a
|
22
|
+
@tokens
|
23
|
+
end
|
24
|
+
|
25
|
+
def skip type
|
26
|
+
@tokens.shift while not @tokens.empty? and peek.first == type
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Calculates the column (by byte) and the line of the current token based on
|
31
|
+
# +byte_offset+.
|
32
|
+
|
33
|
+
def token_pos byte_offset # :nodoc:
|
34
|
+
[byte_offset - @line_pos, @line]
|
35
|
+
end
|
36
|
+
|
37
|
+
def empty?
|
38
|
+
@tokens.empty?
|
39
|
+
end
|
40
|
+
|
41
|
+
def unshift token
|
42
|
+
@tokens.unshift token
|
43
|
+
end
|
44
|
+
|
45
|
+
def next_token
|
46
|
+
@tokens.shift
|
47
|
+
end
|
48
|
+
alias :shift :next_token
|
49
|
+
|
50
|
+
def peek
|
51
|
+
@tokens.first || [:EOF]
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def tokenize input
|
57
|
+
s = StringScanner.new input
|
58
|
+
|
59
|
+
until s.eos? do
|
60
|
+
pos = s.pos
|
61
|
+
|
62
|
+
pos = s.pos if leading_whitespace = s.scan(/ +/)
|
63
|
+
|
64
|
+
if s.scan(/[<|=>]{7}/) then
|
65
|
+
message = "your #{@filename} contains merge conflict markers"
|
66
|
+
column, line = token_pos pos
|
67
|
+
|
68
|
+
raise Gem::RequestSet::Lockfile::ParseError.new message, column, line, @filename
|
69
|
+
end
|
70
|
+
|
71
|
+
@tokens <<
|
72
|
+
case
|
73
|
+
when s.scan(/\r?\n/) then
|
74
|
+
token = [:newline, nil, *token_pos(pos)]
|
75
|
+
@line_pos = s.pos
|
76
|
+
@line += 1
|
77
|
+
token
|
78
|
+
when s.scan(/[A-Z]+/) then
|
79
|
+
if leading_whitespace then
|
80
|
+
text = s.matched
|
81
|
+
text += s.scan(/[^\s)]*/).to_s # in case of no match
|
82
|
+
[:text, text, *token_pos(pos)]
|
83
|
+
else
|
84
|
+
[:section, s.matched, *token_pos(pos)]
|
85
|
+
end
|
86
|
+
when s.scan(/([a-z]+):\s/) then
|
87
|
+
s.pos -= 1 # rewind for possible newline
|
88
|
+
[:entry, s[1], *token_pos(pos)]
|
89
|
+
when s.scan(/\(/) then
|
90
|
+
[:l_paren, nil, *token_pos(pos)]
|
91
|
+
when s.scan(/\)/) then
|
92
|
+
[:r_paren, nil, *token_pos(pos)]
|
93
|
+
when s.scan(/<=|>=|=|~>|<|>|!=/) then
|
94
|
+
[:requirement, s.matched, *token_pos(pos)]
|
95
|
+
when s.scan(/,/) then
|
96
|
+
[:comma, nil, *token_pos(pos)]
|
97
|
+
when s.scan(/!/) then
|
98
|
+
[:bang, nil, *token_pos(pos)]
|
99
|
+
when s.scan(/[^\s),!]*/) then
|
100
|
+
[:text, s.matched, *token_pos(pos)]
|
101
|
+
else
|
102
|
+
raise "BUG: can't create token for: #{s.string[s.pos..-1].inspect}"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
@tokens
|
107
|
+
end
|
108
|
+
end
|
data/lib/rubygems/requirement.rb
CHANGED
@@ -23,6 +23,8 @@ class Gem::Requirement
|
|
23
23
|
"~>" => lambda { |v, r| v >= r && v.release < r.bump }
|
24
24
|
}
|
25
25
|
|
26
|
+
SOURCE_SET_REQUIREMENT = Struct.new(:for_lockfile).new "!" # :nodoc:
|
27
|
+
|
26
28
|
quoted = OPS.keys.map { |k| Regexp.quote k }.join "|"
|
27
29
|
PATTERN_RAW = "\\s*(#{quoted})?\\s*(#{Gem::Version::VERSION_PATTERN})\\s*" # :nodoc:
|
28
30
|
|
@@ -54,6 +56,8 @@ class Gem::Requirement
|
|
54
56
|
input
|
55
57
|
when Gem::Version, Array then
|
56
58
|
new input
|
59
|
+
when '!' then
|
60
|
+
source_set
|
57
61
|
else
|
58
62
|
if input.respond_to? :to_str then
|
59
63
|
new [input.to_str]
|
@@ -70,6 +74,13 @@ class Gem::Requirement
|
|
70
74
|
new '>= 0'
|
71
75
|
end
|
72
76
|
|
77
|
+
###
|
78
|
+
# A source set requirement, used for Gemfiles and lockfiles
|
79
|
+
|
80
|
+
def self.source_set # :nodoc:
|
81
|
+
SOURCE_SET_REQUIREMENT
|
82
|
+
end
|
83
|
+
|
73
84
|
##
|
74
85
|
# Parse +obj+, returning an <tt>[op, version]</tt> pair. +obj+ can
|
75
86
|
# be a String or a Gem::Version.
|
@@ -171,7 +182,7 @@ class Gem::Requirement
|
|
171
182
|
end
|
172
183
|
|
173
184
|
def hash # :nodoc:
|
174
|
-
requirements.hash
|
185
|
+
requirements.sort.hash
|
175
186
|
end
|
176
187
|
|
177
188
|
def marshal_dump # :nodoc:
|