Object
# File lib/bundler/definition.rb, line 9
9: def self.build(gemfile, lockfile, unlock)
10: unlock ||= {}
11: gemfile = Pathname.new(gemfile).expand_path
12:
13: unless gemfile.file?
14: raise GemfileNotFound, "#{gemfile} not found"
15: end
16:
17: Dsl.evaluate(gemfile, lockfile, unlock)
18: end
# File lib/bundler/definition.rb, line 32
32: def initialize(lockfile, dependencies, sources, unlock)
33: @dependencies, @sources, @unlock = dependencies, sources, unlock
34: @remote = false
35: @specs = nil
36: @lockfile_contents = ""
37:
38: if lockfile && File.exists?(lockfile)
39: @lockfile_contents = Bundler.read_file(lockfile)
40: locked = LockfileParser.new(@lockfile_contents)
41: @platforms = locked.platforms
42:
43: if unlock != true
44: @locked_deps = locked.dependencies
45: @locked_specs = SpecSet.new(locked.specs)
46: @locked_sources = locked.sources
47: else
48: @unlock = {}
49: @locked_deps = []
50: @locked_specs = SpecSet.new([])
51: @locked_sources = []
52: end
53: else
54: @unlock = {}
55: @platforms = []
56: @locked_deps = []
57: @locked_specs = SpecSet.new([])
58: @locked_sources = []
59: end
60:
61: @unlock[:gems] ||= []
62: @unlock[:sources] ||= []
63:
64: current_platform = Gem.platforms.map { |p| generic(p) }.compact.last
65: @new_platform = !@platforms.include?(current_platform)
66: @platforms |= [current_platform]
67:
68: eager_unlock = expand_dependencies(@unlock[:gems])
69: @unlock[:gems] = @locked_specs.for(eager_unlock).map { |s| s.name }
70:
71: converge_sources
72: converge_dependencies
73: end
# File lib/bundler/definition.rb, line 128
128: def current_dependencies
129: dependencies.reject { |d| !d.should_include? }
130: end
# File lib/bundler/definition.rb, line 238
238: def ensure_equivalent_gemfile_and_lockfile
239: changes = false
240:
241: msg = "You have modified your Gemfile in development but did not check\n" "the resulting snapshot (Gemfile.lock) into version control"
242:
243: added = []
244: deleted = []
245: changed = []
246:
247: if @locked_sources != @sources
248: new_sources = @sources - @locked_sources
249: deleted_sources = @locked_sources - @sources
250:
251: if new_sources.any?
252: added.concat new_sources.map { |source| "* source: #{source}" }
253: end
254:
255: if deleted_sources.any?
256: deleted.concat deleted_sources.map { |source| "* source: #{source}" }
257: end
258:
259: changes = true
260: end
261:
262: both_sources = Hash.new { |h,k| h[k] = ["no specified source", "no specified source"] }
263: @dependencies.each { |d| both_sources[d.name][0] = d.source if d.source }
264: @locked_deps.each { |d| both_sources[d.name][1] = d.source if d.source }
265: both_sources.delete_if { |k,v| v[0] == v[1] }
266:
267: if @dependencies != @locked_deps
268: new_deps = @dependencies - @locked_deps
269: deleted_deps = @locked_deps - @dependencies
270:
271: if new_deps.any?
272: added.concat new_deps.map { |d| "* #{pretty_dep(d)}" }
273: end
274:
275: if deleted_deps.any?
276: deleted.concat deleted_deps.map { |d| "* #{pretty_dep(d)}" }
277: end
278:
279: both_sources.each do |name, sources|
280: changed << "* #{name} from `#{sources[0]}` to `#{sources[1]}`"
281: end
282:
283: changes = true
284: end
285:
286: msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any?
287: msg << "\n\nYou have deleted from the Gemfile:\n" << deleted.join("\n") if deleted.any?
288: msg << "\n\nYou have changed in the Gemfile:\n" << changed.join("\n") if changed.any?
289:
290: raise ProductionError, msg if added.any? || deleted.any? || changed.any?
291: end
# File lib/bundler/definition.rb, line 176
176: def groups
177: dependencies.map { |d| d.groups }.flatten.uniq
178: end
# File lib/bundler/definition.rb, line 156
156: def index
157: @index ||= Index.build do |idx|
158: @sources.each do |s|
159: idx.use s.specs
160: end
161: end
162: end
# File lib/bundler/definition.rb, line 180
180: def lock(file)
181: contents = to_lock
182:
183: return if @lockfile_contents == contents
184:
185: if Bundler.settings[:frozen]
186: # TODO: Warn here if we got here.
187: return
188: end
189:
190: # Convert to \r\n if the existing lock has them
191: # i.e., Windows with `git config core.autocrlf=true`
192: contents.gsub!(/\n/, "\r\n") if @lockfile_contents.match("\r\n")
193:
194: File.open(file, 'wb'){|f| f.puts(contents) }
195: end
# File lib/bundler/definition.rb, line 114
114: def missing_specs
115: missing = []
116: resolve.materialize(requested_dependencies, missing)
117: missing
118: end
# File lib/bundler/definition.rb, line 110
110: def new_platform?
111: @new_platform
112: end
# File lib/bundler/definition.rb, line 102
102: def new_specs
103: specs - @locked_specs
104: end
# File lib/bundler/definition.rb, line 172
172: def no_sources?
173: @sources.length == 1 && @sources.first.remotes.empty?
174: end
# File lib/bundler/definition.rb, line 106
106: def removed_specs
107: @locked_specs - specs
108: end
# File lib/bundler/definition.rb, line 120
120: def requested_specs
121: @requested_specs ||= begin
122: groups = self.groups - Bundler.settings.without
123: groups.map! { |g| g.to_sym }
124: specs_for(groups)
125: end
126: end
# File lib/bundler/definition.rb, line 138
138: def resolve
139: @resolve ||= begin
140: if Bundler.settings[:frozen]
141: @locked_specs
142: else
143: last_resolve = converge_locked_specs
144: source_requirements = {}
145: dependencies.each do |dep|
146: next unless dep.source
147: source_requirements[dep.name] = dep.source.specs
148: end
149:
150: # Run a resolve against the locally available gems
151: last_resolve.merge Resolver.resolve(expanded_dependencies, index, source_requirements, last_resolve)
152: end
153: end
154: end
# File lib/bundler/definition.rb, line 81
81: def resolve_remotely!
82: raise "Specs already loaded" if @specs
83: @remote = true
84: @sources.each { |s| s.remote! }
85: specs
86: end
# File lib/bundler/definition.rb, line 75
75: def resolve_with_cache!
76: raise "Specs already loaded" if @specs
77: @sources.each { |s| s.cached! }
78: specs
79: end
# File lib/bundler/definition.rb, line 164
164: def rubygems_index
165: @rubygems_index ||= Index.build do |idx|
166: @sources.find_all{|s| s.is_a?(Source::Rubygems) }.each do |s|
167: idx.use s.specs
168: end
169: end
170: end
# File lib/bundler/definition.rb, line 88
88: def specs
89: @specs ||= begin
90: specs = resolve.materialize(requested_dependencies)
91:
92: unless specs["bundler"].any?
93: local = Bundler.settings[:frozen] ? rubygems_index : index
94: bundler = local.search(Gem::Dependency.new('bundler', VERSION)).last
95: specs["bundler"] = bundler if bundler
96: end
97:
98: specs
99: end
100: end
# File lib/bundler/definition.rb, line 132
132: def specs_for(groups)
133: deps = dependencies.select { |d| (d.groups & groups).any? }
134: deps.delete_if { |d| !d.should_include? }
135: specs.for(expand_dependencies(deps))
136: end
# File lib/bundler/definition.rb, line 197
197: def to_lock
198: out = ""
199:
200: sorted_sources.each do |source|
201: # Add the source header
202: out << source.to_lock
203: # Find all specs for this source
204: resolve.
205: select { |s| s.source == source }.
206: # This needs to be sorted by full name so that
207: # gems with the same name, but different platform
208: # are ordered consistantly
209: sort_by { |s| s.full_name }.
210: each do |spec|
211: next if spec.name == 'bundler'
212: out << spec.to_lock
213: end
214: out << "\n"
215: end
216:
217: out << "PLATFORMS\n"
218:
219: platforms.map { |p| p.to_s }.sort.each do |p|
220: out << " #{p}\n"
221: end
222:
223: out << "\n"
224: out << "DEPENDENCIES\n"
225:
226: handled = []
227: dependencies.
228: sort_by { |d| d.name }.
229: each do |dep|
230: next if handled.include?(dep.name)
231: out << dep.to_lock
232: handled << dep.name
233: end
234:
235: out
236: end
# File lib/bundler/definition.rb, line 320
320: def converge_dependencies
321: (@dependencies + @locked_deps).each do |dep|
322: if dep.source
323: dep.source = @sources.find { |s| dep.source == s }
324: end
325: end
326: end
Remove elements from the locked specs that are expired. This will most commonly happen if the Gemfile has changed since the lockfile was last generated
# File lib/bundler/definition.rb, line 331
331: def converge_locked_specs
332: deps = []
333:
334: # Build a list of dependencies that are the same in the Gemfile
335: # and Gemfile.lock. If the Gemfile modified a dependency, but
336: # the gem in the Gemfile.lock still satisfies it, this is fine
337: # too.
338: @dependencies.each do |dep|
339: locked_dep = @locked_deps.find { |d| dep == d }
340:
341: if in_locked_deps?(dep, locked_dep) || satisfies_locked_spec?(dep)
342: deps << dep
343: elsif dep.source.is_a?(Source::Path) && dep.current_platform? && (!locked_dep || dep.source != locked_dep.source)
344: @locked_specs.each do |s|
345: @unlock[:gems] << s.name if s.source == dep.source
346: end
347:
348: dep.source.unlock! if dep.source.respond_to?(:unlock!)
349: dep.source.specs.each { |s| @unlock[:gems] << s.name }
350: end
351: end
352:
353: converged = []
354: @locked_specs.each do |s|
355: s.source = @sources.find { |src| s.source == src }
356:
357: # Don't add a spec to the list if its source is expired. For example,
358: # if you change a Git gem to Rubygems.
359: next if s.source.nil? || @unlock[:sources].include?(s.name)
360: # If the spec is from a path source and it doesn't exist anymore
361: # then we just unlock it.
362:
363: # Path sources have special logic
364: if s.source.instance_of?(Source::Path)
365: other = s.source.specs[s].first
366:
367: # If the spec is no longer in the path source, unlock it. This
368: # commonly happens if the version changed in the gemspec
369: next unless other
370: # If the dependencies of the path source have changed, unlock it
371: next unless s.dependencies.sort == other.dependencies.sort
372: end
373:
374: converged << s
375: end
376:
377: resolve = SpecSet.new(converged)
378: resolve = resolve.for(expand_dependencies(deps, true), @unlock[:gems])
379: diff = @locked_specs.to_a - resolve.to_a
380:
381: # Now, we unlock any sources that do not have anymore gems pinned to it
382: @sources.each do |source|
383: next unless source.respond_to?(:unlock!)
384:
385: unless resolve.any? { |s| s.source == source }
386: source.unlock! if !diff.empty? && diff.any? { |s| s.source == source }
387: end
388: end
389:
390: resolve
391: end
# File lib/bundler/definition.rb, line 303
303: def converge_sources
304: locked_gem = @locked_sources.find { |s| Source::Rubygems === s }
305: actual_gem = @sources.find { |s| Source::Rubygems === s }
306:
307: if locked_gem && actual_gem
308: locked_gem.merge_remotes actual_gem
309: end
310:
311: @sources.map! do |source|
312: @locked_sources.find { |s| s == source } || source
313: end
314:
315: @sources.each do |source|
316: source.unlock! if source.respond_to?(:unlock!) && @unlock[:sources].include?(source.name)
317: end
318: end
# File lib/bundler/definition.rb, line 405
405: def expand_dependencies(dependencies, remote = false)
406: deps = []
407: dependencies.each do |dep|
408: dep = Dependency.new(dep, ">= 0") unless dep.respond_to?(:name)
409: dep.gem_platforms(@platforms).each do |p|
410: deps << DepProxy.new(dep, p) if remote || p == generic(Gem::Platform.local)
411: end
412: end
413: deps
414: end
# File lib/bundler/definition.rb, line 401
401: def expanded_dependencies
402: @expanded_dependencies ||= expand_dependencies(dependencies, @remote)
403: end
# File lib/bundler/definition.rb, line 393
393: def in_locked_deps?(dep, d)
394: d && dep.source == d.source
395: end
# File lib/bundler/definition.rb, line 296
296: def pretty_dep(dep, source = false)
297: msg = "#{dep.name}"
298: msg << " (#{dep.requirement})" unless dep.requirement == Gem::Requirement.default
299: msg << " from the `#{dep.source}` source" if source && dep.source
300: msg
301: end
# File lib/bundler/definition.rb, line 423
423: def requested_dependencies
424: groups = self.groups - Bundler.settings.without
425: groups.map! { |g| g.to_sym }
426: dependencies.reject { |d| !d.should_include? || (d.groups & groups).empty? }
427: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.