rubygems-update 2.1.11 → 2.2.0.rc.1

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.

Files changed (190) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.autotest +37 -12
  5. data/History.txt +99 -2
  6. data/MIT.txt +1 -0
  7. data/Manifest.txt +59 -19
  8. data/Rakefile +4 -6
  9. data/lib/gauntlet_rubygems.rb +1 -1
  10. data/lib/rubygems.rb +102 -80
  11. data/lib/rubygems/available_set.rb +2 -2
  12. data/lib/rubygems/basic_specification.rb +97 -8
  13. data/lib/rubygems/commands/install_command.rb +58 -15
  14. data/lib/rubygems/commands/list_command.rb +1 -7
  15. data/lib/rubygems/commands/outdated_command.rb +1 -1
  16. data/lib/rubygems/commands/pristine_command.rb +14 -1
  17. data/lib/rubygems/commands/push_command.rb +9 -4
  18. data/lib/rubygems/commands/query_command.rb +33 -17
  19. data/lib/rubygems/commands/search_command.rb +0 -6
  20. data/lib/rubygems/commands/specification_command.rb +1 -1
  21. data/lib/rubygems/commands/unpack_command.rb +1 -1
  22. data/lib/rubygems/commands/update_command.rb +4 -1
  23. data/lib/rubygems/commands/which_command.rb +5 -8
  24. data/lib/rubygems/compatibility.rb +3 -0
  25. data/lib/rubygems/core_ext/kernel_gem.rb +6 -0
  26. data/lib/rubygems/defaults.rb +19 -0
  27. data/lib/rubygems/dependency_installer.rb +28 -9
  28. data/lib/rubygems/doctor.rb +17 -11
  29. data/lib/rubygems/errors.rb +16 -3
  30. data/lib/rubygems/exceptions.rb +52 -5
  31. data/lib/rubygems/ext.rb +1 -2
  32. data/lib/rubygems/ext/build_error.rb +6 -0
  33. data/lib/rubygems/ext/builder.rb +50 -17
  34. data/lib/rubygems/ext/cmake_builder.rb +1 -1
  35. data/lib/rubygems/ext/configure_builder.rb +1 -3
  36. data/lib/rubygems/ext/ext_conf_builder.rb +9 -3
  37. data/lib/rubygems/ext/rake_builder.rb +2 -5
  38. data/lib/rubygems/gemcutter_utilities.rb +8 -1
  39. data/lib/rubygems/installer.rb +14 -4
  40. data/lib/rubygems/installer_test_case.rb +0 -5
  41. data/lib/rubygems/package.rb +11 -2
  42. data/lib/rubygems/psych_additions.rb +1 -1
  43. data/lib/rubygems/rdoc.rb +1 -1
  44. data/lib/rubygems/remote_fetcher.rb +3 -3
  45. data/lib/rubygems/request.rb +16 -8
  46. data/lib/rubygems/request_set.rb +133 -42
  47. data/lib/rubygems/request_set/gem_dependency_api.rb +493 -11
  48. data/lib/rubygems/request_set/lockfile.rb +579 -0
  49. data/lib/rubygems/requirement.rb +58 -30
  50. data/lib/rubygems/resolver.rb +471 -0
  51. data/lib/rubygems/resolver/activation_request.rb +165 -0
  52. data/lib/rubygems/resolver/api_set.rb +110 -0
  53. data/lib/rubygems/resolver/api_specification.rb +79 -0
  54. data/lib/rubygems/resolver/best_set.rb +31 -0
  55. data/lib/rubygems/resolver/composed_set.rb +39 -0
  56. data/lib/rubygems/resolver/conflict.rb +122 -0
  57. data/lib/rubygems/{dependency_resolver → resolver}/current_set.rb +1 -4
  58. data/lib/rubygems/{dependency_resolver → resolver}/dependency_request.rb +37 -7
  59. data/lib/rubygems/resolver/git_set.rb +119 -0
  60. data/lib/rubygems/resolver/git_specification.rb +35 -0
  61. data/lib/rubygems/resolver/index_set.rb +74 -0
  62. data/lib/rubygems/resolver/index_specification.rb +69 -0
  63. data/lib/rubygems/resolver/installed_specification.rb +40 -0
  64. data/lib/rubygems/{dependency_resolver → resolver}/installer_set.rb +18 -17
  65. data/lib/rubygems/resolver/local_specification.rb +16 -0
  66. data/lib/rubygems/resolver/lock_set.rb +78 -0
  67. data/lib/rubygems/resolver/lock_specification.rb +58 -0
  68. data/lib/rubygems/resolver/requirement_list.rb +81 -0
  69. data/lib/rubygems/resolver/set.rb +27 -0
  70. data/lib/rubygems/resolver/spec_specification.rb +58 -0
  71. data/lib/rubygems/resolver/specification.rb +89 -0
  72. data/lib/rubygems/resolver/stats.rb +44 -0
  73. data/lib/rubygems/resolver/vendor_set.rb +83 -0
  74. data/lib/rubygems/resolver/vendor_specification.rb +24 -0
  75. data/lib/rubygems/security/trust_dir.rb +16 -2
  76. data/lib/rubygems/source.rb +71 -18
  77. data/lib/rubygems/source/git.rb +218 -0
  78. data/lib/rubygems/source/installed.rb +8 -1
  79. data/lib/rubygems/source/local.rb +14 -8
  80. data/lib/rubygems/source/lock.rb +48 -0
  81. data/lib/rubygems/source/specific_file.rb +14 -3
  82. data/lib/rubygems/source/vendor.rb +27 -0
  83. data/lib/rubygems/source_list.rb +74 -12
  84. data/lib/rubygems/spec_fetcher.rb +36 -4
  85. data/lib/rubygems/specification.rb +214 -65
  86. data/lib/rubygems/stub_specification.rb +57 -1
  87. data/lib/rubygems/syck_hack.rb +3 -3
  88. data/lib/rubygems/test_case.rb +226 -59
  89. data/lib/rubygems/test_utilities.rb +198 -0
  90. data/lib/rubygems/uninstaller.rb +22 -10
  91. data/lib/rubygems/uri_formatter.rb +20 -0
  92. data/lib/rubygems/user_interaction.rb +193 -71
  93. data/lib/rubygems/util.rb +121 -0
  94. data/lib/rubygems/util/list.rb +4 -0
  95. data/lib/rubygems/util/stringio.rb +34 -0
  96. data/lib/rubygems/validator.rb +6 -2
  97. data/lib/rubygems/version.rb +4 -8
  98. data/test/rubygems/test_bundled_ca.rb +1 -1
  99. data/test/rubygems/test_gem.rb +137 -29
  100. data/test/rubygems/test_gem_available_set.rb +19 -0
  101. data/test/rubygems/test_gem_commands_build_command.rb +1 -1
  102. data/test/rubygems/test_gem_commands_cert_command.rb +2 -2
  103. data/test/rubygems/test_gem_commands_cleanup_command.rb +13 -13
  104. data/test/rubygems/test_gem_commands_dependency_command.rb +24 -34
  105. data/test/rubygems/test_gem_commands_fetch_command.rb +43 -48
  106. data/test/rubygems/test_gem_commands_install_command.rb +244 -279
  107. data/test/rubygems/test_gem_commands_list_command.rb +3 -3
  108. data/test/rubygems/test_gem_commands_outdated_command.rb +7 -12
  109. data/test/rubygems/test_gem_commands_pristine_command.rb +73 -27
  110. data/test/rubygems/test_gem_commands_push_command.rb +76 -8
  111. data/test/rubygems/test_gem_commands_query_command.rb +239 -49
  112. data/test/rubygems/test_gem_commands_sources_command.rb +10 -43
  113. data/test/rubygems/test_gem_commands_specification_command.rb +24 -47
  114. data/test/rubygems/test_gem_commands_stale_command.rb +2 -2
  115. data/test/rubygems/test_gem_commands_uninstall_command.rb +3 -3
  116. data/test/rubygems/test_gem_commands_unpack_command.rb +16 -30
  117. data/test/rubygems/test_gem_commands_update_command.rb +149 -134
  118. data/test/rubygems/test_gem_commands_which_command.rb +4 -2
  119. data/test/rubygems/test_gem_dependency_installer.rb +68 -0
  120. data/test/rubygems/test_gem_dependency_list.rb +17 -17
  121. data/test/rubygems/test_gem_dependency_resolution_error.rb +28 -0
  122. data/test/rubygems/test_gem_doctor.rb +1 -1
  123. data/test/rubygems/test_gem_ext_builder.rb +178 -8
  124. data/test/rubygems/test_gem_ext_cmake_builder.rb +1 -7
  125. data/test/rubygems/test_gem_ext_configure_builder.rb +8 -10
  126. data/test/rubygems/test_gem_ext_ext_conf_builder.rb +18 -21
  127. data/test/rubygems/test_gem_ext_rake_builder.rb +1 -3
  128. data/test/rubygems/test_gem_impossible_dependencies_error.rb +10 -6
  129. data/test/rubygems/test_gem_indexer.rb +6 -6
  130. data/test/rubygems/test_gem_installer.rb +29 -10
  131. data/test/rubygems/test_gem_local_remote_options.rb +1 -1
  132. data/test/rubygems/test_gem_package.rb +18 -0
  133. data/test/rubygems/test_gem_rdoc.rb +1 -1
  134. data/test/rubygems/test_gem_remote_fetcher.rb +1 -1
  135. data/test/rubygems/test_gem_request.rb +37 -10
  136. data/test/rubygems/test_gem_request_set.rb +271 -9
  137. data/test/rubygems/test_gem_request_set_gem_dependency_api.rb +684 -0
  138. data/test/rubygems/test_gem_request_set_lockfile.rb +849 -0
  139. data/test/rubygems/test_gem_requirement.rb +21 -0
  140. data/test/rubygems/{test_gem_dependency_resolver.rb → test_gem_resolver.rb} +231 -70
  141. data/test/rubygems/test_gem_resolver_activation_request.rb +63 -0
  142. data/test/rubygems/test_gem_resolver_api_set.rb +167 -0
  143. data/test/rubygems/test_gem_resolver_api_specification.rb +104 -0
  144. data/test/rubygems/test_gem_resolver_best_set.rb +30 -0
  145. data/test/rubygems/test_gem_resolver_conflict.rb +75 -0
  146. data/test/rubygems/test_gem_resolver_dependency_request.rb +20 -0
  147. data/test/rubygems/test_gem_resolver_git_set.rb +148 -0
  148. data/test/rubygems/test_gem_resolver_git_specification.rb +100 -0
  149. data/test/rubygems/test_gem_resolver_index_set.rb +28 -0
  150. data/test/rubygems/test_gem_resolver_index_specification.rb +89 -0
  151. data/test/rubygems/test_gem_resolver_installed_specification.rb +49 -0
  152. data/test/rubygems/test_gem_resolver_installer_set.rb +22 -0
  153. data/test/rubygems/test_gem_resolver_local_specification.rb +45 -0
  154. data/test/rubygems/test_gem_resolver_lock_set.rb +57 -0
  155. data/test/rubygems/test_gem_resolver_lock_specification.rb +87 -0
  156. data/test/rubygems/test_gem_resolver_requirement_list.rb +20 -0
  157. data/test/rubygems/test_gem_resolver_specification.rb +32 -0
  158. data/test/rubygems/test_gem_resolver_vendor_set.rb +67 -0
  159. data/test/rubygems/test_gem_resolver_vendor_specification.rb +83 -0
  160. data/test/rubygems/test_gem_server.rb +4 -4
  161. data/test/rubygems/test_gem_source.rb +54 -64
  162. data/test/rubygems/test_gem_source_git.rb +231 -0
  163. data/test/rubygems/test_gem_source_list.rb +24 -0
  164. data/test/rubygems/test_gem_source_local.rb +1 -1
  165. data/test/rubygems/test_gem_source_lock.rb +114 -0
  166. data/test/rubygems/test_gem_source_vendor.rb +27 -0
  167. data/test/rubygems/test_gem_spec_fetcher.rb +116 -61
  168. data/test/rubygems/test_gem_specification.rb +526 -94
  169. data/test/rubygems/test_gem_stub_specification.rb +123 -10
  170. data/test/rubygems/test_gem_uninstaller.rb +28 -2
  171. data/test/rubygems/test_gem_util.rb +31 -0
  172. data/test/rubygems/test_gem_validator.rb +9 -0
  173. data/util/update_bundled_ca_certificates.rb +8 -1
  174. metadata +89 -29
  175. metadata.gz.sig +2 -4
  176. data/lib/rubygems/dependency_resolver.rb +0 -254
  177. data/lib/rubygems/dependency_resolver/activation_request.rb +0 -109
  178. data/lib/rubygems/dependency_resolver/api_set.rb +0 -65
  179. data/lib/rubygems/dependency_resolver/api_specification.rb +0 -39
  180. data/lib/rubygems/dependency_resolver/composed_set.rb +0 -18
  181. data/lib/rubygems/dependency_resolver/dependency_conflict.rb +0 -85
  182. data/lib/rubygems/dependency_resolver/index_set.rb +0 -64
  183. data/lib/rubygems/dependency_resolver/index_specification.rb +0 -60
  184. data/lib/rubygems/dependency_resolver/installed_specification.rb +0 -52
  185. data/test/rubygems/test_gem_dependency_resolver_api_specification.rb +0 -33
  186. data/test/rubygems/test_gem_dependency_resolver_dependency_conflict.rb +0 -36
  187. data/test/rubygems/test_gem_dependency_resolver_index_set.rb +0 -53
  188. data/test/rubygems/test_gem_dependency_resolver_index_specification.rb +0 -73
  189. data/test/rubygems/test_gem_dependency_resolver_installed_specification.rb +0 -19
  190. data/test/rubygems/test_gem_dependency_resolver_installer_set.rb +0 -28
@@ -0,0 +1,579 @@
1
+ require 'strscan'
2
+
3
+ ##
4
+ # Parses a gem.deps.rb.lock file and constructs a LockSet containing the
5
+ # dependencies found inside. If the lock file is missing no LockSet is
6
+ # constructed.
7
+
8
+ class Gem::RequestSet::Lockfile
9
+
10
+ ##
11
+ # Raised when a lockfile cannot be parsed
12
+
13
+ class ParseError < Gem::Exception
14
+
15
+ ##
16
+ # The column where the error was encountered
17
+
18
+ attr_reader :column
19
+
20
+ ##
21
+ # The line where the error was encountered
22
+
23
+ attr_reader :line
24
+
25
+ ##
26
+ # The location of the lock file
27
+
28
+ attr_reader :path
29
+
30
+ ##
31
+ # Raises a ParseError with the given +message+ which was encountered at a
32
+ # +line+ and +column+ while parsing.
33
+
34
+ def initialize message, column, line, path
35
+ @line = line
36
+ @column = column
37
+ @path = path
38
+ super "#{message} (at line #{line} column #{column})"
39
+ end
40
+
41
+ end
42
+
43
+ ##
44
+ # The platforms for this Lockfile
45
+
46
+ attr_reader :platforms
47
+
48
+ ##
49
+ # Creates a new Lockfile for the given +request_set+ and +gem_deps_file+
50
+ # location.
51
+
52
+ def initialize request_set, gem_deps_file
53
+ @set = request_set
54
+ @gem_deps_file = File.expand_path(gem_deps_file)
55
+ @gem_deps_dir = File.dirname(@gem_deps_file)
56
+
57
+ @current_token = nil
58
+ @line = 0
59
+ @line_pos = 0
60
+ @platforms = []
61
+ @tokens = []
62
+ end
63
+
64
+ def add_DEPENDENCIES out # :nodoc:
65
+ out << "DEPENDENCIES"
66
+
67
+ @requests.sort_by { |r| r.name }.each do |request|
68
+ spec = request.spec
69
+
70
+ if [Gem::Resolver::VendorSpecification,
71
+ Gem::Resolver::GitSpecification].include? spec.class then
72
+ out << " #{request.name}!"
73
+ else
74
+ requirement = request.request.dependency.requirement
75
+
76
+ out << " #{request.name}#{requirement.for_lockfile}"
77
+ end
78
+ end
79
+
80
+ out << nil
81
+ end
82
+
83
+ def add_GEM out # :nodoc:
84
+ return if @spec_groups.empty?
85
+
86
+ source_groups = @spec_groups.values.flatten.group_by do |request|
87
+ request.spec.source.uri
88
+ end
89
+
90
+ source_groups.sort_by { |group,| group.to_s }.map do |group, requests|
91
+ out << "GEM"
92
+ out << " remote: #{group}"
93
+ out << " specs:"
94
+
95
+ requests.sort_by { |request| request.name }.each do |request|
96
+ platform = "-#{request.spec.platform}" unless
97
+ Gem::Platform::RUBY == request.spec.platform
98
+
99
+ out << " #{request.name} (#{request.version}#{platform})"
100
+
101
+ request.full_spec.dependencies.sort.each do |dependency|
102
+ requirement = dependency.requirement
103
+ out << " #{dependency.name}#{requirement.for_lockfile}"
104
+ end
105
+ end
106
+ out << nil
107
+ end
108
+ end
109
+
110
+ def add_GIT out
111
+ return unless git_requests =
112
+ @spec_groups.delete(Gem::Resolver::GitSpecification)
113
+
114
+ by_repository_revision = git_requests.group_by do |request|
115
+ source = request.spec.source
116
+ [source.repository, source.rev_parse]
117
+ end
118
+
119
+ out << "GIT"
120
+ by_repository_revision.each do |(repository, revision), requests|
121
+ out << " remote: #{repository}"
122
+ out << " revision: #{revision}"
123
+ out << " specs:"
124
+
125
+ requests.sort_by { |request| request.name }.each do |request|
126
+ out << " #{request.name} (#{request.version})"
127
+
128
+ dependencies = request.spec.dependencies.sort_by { |dep| dep.name }
129
+ dependencies.each do |dep|
130
+ out << " #{dep.name}#{dep.requirement.for_lockfile}"
131
+ end
132
+ end
133
+ end
134
+
135
+ out << nil
136
+ end
137
+
138
+ def relative_path_from dest, base # :nodoc:
139
+ dest = File.expand_path(dest)
140
+ base = File.expand_path(base)
141
+
142
+ if dest.index(base) == 0
143
+ return dest[base.size+1..-1]
144
+ else
145
+ dest
146
+ end
147
+ end
148
+
149
+ def add_PATH out # :nodoc:
150
+ return unless path_requests =
151
+ @spec_groups.delete(Gem::Resolver::VendorSpecification)
152
+
153
+ out << "PATH"
154
+ path_requests.each do |request|
155
+ directory = File.expand_path(request.spec.source.uri)
156
+
157
+ out << " remote: #{relative_path_from directory, @gem_deps_dir}"
158
+ out << " specs:"
159
+ out << " #{request.name} (#{request.version})"
160
+ end
161
+
162
+ out << nil
163
+ end
164
+
165
+ def add_PLATFORMS out # :nodoc:
166
+ out << "PLATFORMS"
167
+
168
+ platforms = @requests.map { |request| request.spec.platform }.uniq
169
+ platforms.delete Gem::Platform::RUBY if platforms.length > 1
170
+
171
+ platforms.each do |platform|
172
+ out << " #{platform}"
173
+ end
174
+
175
+ out << nil
176
+ end
177
+
178
+ ##
179
+ # Gets the next token for a Lockfile
180
+
181
+ def get expected_types = nil, expected_value = nil # :nodoc:
182
+ @current_token = @tokens.shift
183
+
184
+ type, value, column, line = @current_token
185
+
186
+ if expected_types and not Array(expected_types).include? type then
187
+ unget
188
+
189
+ message = "unexpected token [#{type.inspect}, #{value.inspect}], " +
190
+ "expected #{expected_types.inspect}"
191
+
192
+ raise ParseError.new message, column, line, "#{@gem_deps_file}.lock"
193
+ end
194
+
195
+ if expected_value and expected_value != value then
196
+ unget
197
+
198
+ message = "unexpected token [#{type.inspect}, #{value.inspect}], " +
199
+ "expected [#{expected_types.inspect}, " +
200
+ "#{expected_value.inspect}]"
201
+
202
+ raise ParseError.new message, column, line, "#{@gem_deps_file}.lock"
203
+ end
204
+
205
+ @current_token
206
+ end
207
+
208
+ def parse # :nodoc:
209
+ tokenize
210
+
211
+ until @tokens.empty? do
212
+ type, data, column, line = get
213
+
214
+ case type
215
+ when :section then
216
+ skip :newline
217
+
218
+ case data
219
+ when 'DEPENDENCIES' then
220
+ parse_DEPENDENCIES
221
+ when 'GIT' then
222
+ parse_GIT
223
+ when 'GEM' then
224
+ parse_GEM
225
+ when 'PATH' then
226
+ parse_PATH
227
+ when 'PLATFORMS' then
228
+ parse_PLATFORMS
229
+ else
230
+ type, = get until @tokens.empty? or peek.first == :section
231
+ end
232
+ else
233
+ raise "BUG: unhandled token #{type} (#{data.inspect}) at line #{line} column #{column}"
234
+ end
235
+ end
236
+ end
237
+
238
+ def parse_DEPENDENCIES # :nodoc:
239
+ while not @tokens.empty? and :text == peek.first do
240
+ _, name, = get :text
241
+
242
+ requirements = []
243
+
244
+ case peek[0]
245
+ when :bang then
246
+ get :bang
247
+
248
+ spec = @set.sets.select { |set|
249
+ Gem::Resolver::GitSet === set or
250
+ Gem::Resolver::VendorSet === set
251
+ }.map { |set|
252
+ set.specs[name]
253
+ }.first
254
+
255
+ requirements << spec.version
256
+ when :l_paren then
257
+ get :l_paren
258
+
259
+ loop do
260
+ _, op, = get :requirement
261
+ _, version, = get :text
262
+
263
+ requirements << "#{op} #{version}"
264
+
265
+ break unless peek[0] == :comma
266
+
267
+ get :comma
268
+ end
269
+
270
+ get :r_paren
271
+ end
272
+
273
+ @set.gem name, *requirements
274
+
275
+ skip :newline
276
+ end
277
+ end
278
+
279
+ def parse_GEM # :nodoc:
280
+ get :entry, 'remote'
281
+ _, data, = get :text
282
+
283
+ source = Gem::Source.new data
284
+
285
+ skip :newline
286
+
287
+ get :entry, 'specs'
288
+
289
+ skip :newline
290
+
291
+ set = Gem::Resolver::LockSet.new source
292
+ last_spec = nil
293
+
294
+ while not @tokens.empty? and :text == peek.first do
295
+ _, name, column, = get :text
296
+
297
+ case peek[0]
298
+ when :newline then
299
+ last_spec.add_dependency Gem::Dependency.new name if column == 6
300
+ when :l_paren then
301
+ get :l_paren
302
+
303
+ type, data, = get [:text, :requirement]
304
+
305
+ if type == :text and column == 4 then
306
+ last_spec = set.add name, data, Gem::Platform::RUBY
307
+ else
308
+ dependency = parse_dependency name, data
309
+
310
+ last_spec.add_dependency dependency
311
+ end
312
+
313
+ get :r_paren
314
+ else
315
+ raise "BUG: unknown token #{peek}"
316
+ end
317
+
318
+ skip :newline
319
+ end
320
+
321
+ @set.sets << set
322
+ end
323
+
324
+ def parse_GIT # :nodoc:
325
+ get :entry, 'remote'
326
+ _, repository, = get :text
327
+
328
+ skip :newline
329
+
330
+ get :entry, 'revision'
331
+ _, revision, = get :text
332
+
333
+ skip :newline
334
+
335
+ get :entry, 'specs'
336
+
337
+ skip :newline
338
+
339
+ set = Gem::Resolver::GitSet.new
340
+ last_spec = nil
341
+
342
+ while not @tokens.empty? and :text == peek.first do
343
+ _, name, column, = get :text
344
+
345
+ case peek[0]
346
+ when :newline then
347
+ last_spec.add_dependency Gem::Dependency.new name if column == 6
348
+ when :l_paren then
349
+ get :l_paren
350
+
351
+ type, data, = get [:text, :requirement]
352
+
353
+ if type == :text and column == 4 then
354
+ last_spec = set.add_git_spec name, data, repository, revision, true
355
+ else
356
+ dependency = parse_dependency name, data
357
+
358
+ last_spec.spec.dependencies << dependency
359
+ end
360
+
361
+ get :r_paren
362
+ else
363
+ raise "BUG: unknown token #{peek}"
364
+ end
365
+
366
+ skip :newline
367
+ end
368
+
369
+ @set.sets << set
370
+ end
371
+
372
+ def parse_PATH # :nodoc:
373
+ get :entry, 'remote'
374
+ _, directory, = get :text
375
+
376
+ skip :newline
377
+
378
+ get :entry, 'specs'
379
+
380
+ skip :newline
381
+
382
+ set = Gem::Resolver::VendorSet.new
383
+ last_spec = nil
384
+
385
+ while not @tokens.empty? and :text == peek.first do
386
+ _, name, column, = get :text
387
+
388
+ case peek[0]
389
+ when :newline then
390
+ last_spec.add_dependency Gem::Dependency.new name if column == 6
391
+ when :l_paren then
392
+ get :l_paren
393
+
394
+ type, data, = get [:text, :requirement]
395
+
396
+ if type == :text and column == 4 then
397
+ last_spec = set.add_vendor_gem name, directory
398
+ else
399
+ dependency = parse_dependency name, data
400
+
401
+ last_spec.spec.dependencies << dependency
402
+ end
403
+
404
+ get :r_paren
405
+ else
406
+ raise "BUG: unknown token #{peek}"
407
+ end
408
+
409
+ skip :newline
410
+ end
411
+
412
+ @set.sets << set
413
+ end
414
+
415
+ def parse_PLATFORMS # :nodoc:
416
+ while not @tokens.empty? and :text == peek.first do
417
+ _, name, = get :text
418
+
419
+ @platforms << name
420
+
421
+ skip :newline
422
+ end
423
+ end
424
+
425
+ ##
426
+ # Parses the requirements following the dependency +name+ and the +op+ for
427
+ # the first token of the requirements and returns a Gem::Dependency object.
428
+
429
+ def parse_dependency name, op # :nodoc:
430
+ return Gem::Dependency.new name unless peek[0] == :text
431
+
432
+ _, version, = get :text
433
+
434
+ requirements = ["#{op} #{version}"]
435
+
436
+ while peek[0] == :comma do
437
+ get :comma
438
+ _, op, = get :requirement
439
+ _, version, = get :text
440
+
441
+ requirements << "#{op} #{version}"
442
+ end
443
+
444
+ Gem::Dependency.new name, requirements
445
+ end
446
+
447
+ ##
448
+ # Peeks at the next token for Lockfile
449
+
450
+ def peek # :nodoc:
451
+ @tokens.first || [:EOF]
452
+ end
453
+
454
+ def skip type # :nodoc:
455
+ get while not @tokens.empty? and peek.first == type
456
+ end
457
+
458
+ ##
459
+ # The contents of the lock file.
460
+
461
+ def to_s
462
+ @set.resolve
463
+
464
+ out = []
465
+
466
+ @requests = @set.sorted_requests
467
+
468
+ @spec_groups = @requests.group_by do |request|
469
+ request.spec.class
470
+ end
471
+
472
+ add_PATH out
473
+
474
+ add_GIT out
475
+
476
+ add_GEM out
477
+
478
+ add_PLATFORMS out
479
+
480
+ add_DEPENDENCIES out
481
+
482
+ out.join "\n"
483
+ end
484
+
485
+ ##
486
+ # Calculates the column (by byte) and the line of the current token based on
487
+ # +byte_offset+.
488
+
489
+ def token_pos byte_offset # :nodoc:
490
+ [byte_offset - @line_pos, @line]
491
+ end
492
+
493
+ ##
494
+ # Converts a lock file into an Array of tokens. If the lock file is missing
495
+ # an empty Array is returned.
496
+
497
+ def tokenize # :nodoc:
498
+ @line = 0
499
+ @line_pos = 0
500
+
501
+ @platforms = []
502
+ @tokens = []
503
+ @current_token = nil
504
+
505
+ lock_file = "#{@gem_deps_file}.lock"
506
+
507
+ @input = File.read lock_file
508
+ s = StringScanner.new @input
509
+
510
+ until s.eos? do
511
+ pos = s.pos
512
+
513
+ pos = s.pos if leading_whitespace = s.scan(/ +/)
514
+
515
+ if s.scan(/[<|=>]{7}/) then
516
+ message = "your #{lock_file} contains merge conflict markers"
517
+ column, line = token_pos pos
518
+
519
+ raise ParseError.new message, column, line, lock_file
520
+ end
521
+
522
+ @tokens <<
523
+ case
524
+ when s.scan(/\r?\n/) then
525
+ token = [:newline, nil, *token_pos(pos)]
526
+ @line_pos = s.pos
527
+ @line += 1
528
+ token
529
+ when s.scan(/[A-Z]+/) then
530
+ if leading_whitespace then
531
+ text = s.matched
532
+ text += s.scan(/[^\s)]*/).to_s # in case of no match
533
+ [:text, text, *token_pos(pos)]
534
+ else
535
+ [:section, s.matched, *token_pos(pos)]
536
+ end
537
+ when s.scan(/([a-z]+):\s/) then
538
+ s.pos -= 1 # rewind for possible newline
539
+ [:entry, s[1], *token_pos(pos)]
540
+ when s.scan(/\(/) then
541
+ [:l_paren, nil, *token_pos(pos)]
542
+ when s.scan(/\)/) then
543
+ [:r_paren, nil, *token_pos(pos)]
544
+ when s.scan(/<=|>=|=|~>|<|>|!=/) then
545
+ [:requirement, s.matched, *token_pos(pos)]
546
+ when s.scan(/,/) then
547
+ [:comma, nil, *token_pos(pos)]
548
+ when s.scan(/!/) then
549
+ [:bang, nil, *token_pos(pos)]
550
+ when s.scan(/[^\s),!]*/) then
551
+ [:text, s.matched, *token_pos(pos)]
552
+ else
553
+ raise "BUG: can't create token for: #{s.string[s.pos..-1].inspect}"
554
+ end
555
+ end
556
+
557
+ @tokens
558
+ rescue Errno::ENOENT
559
+ @tokens
560
+ end
561
+
562
+ ##
563
+ # Ungets the last token retrieved by #get
564
+
565
+ def unget # :nodoc:
566
+ @tokens.unshift @current_token
567
+ end
568
+
569
+ ##
570
+ # Writes the lock file alongside the gem dependencies file
571
+
572
+ def write
573
+ open "#{@gem_deps_file}.lock", 'w' do |io|
574
+ io.write to_s
575
+ end
576
+ end
577
+
578
+ end
579
+