rubygems-update 2.4.5 → 2.4.6
Sign up to get free protection for your applications and to get access to all the features.
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:
|