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