Parent

Included Modules

Class Index [+]

Quicksearch

Bundler::Definition

Attributes

dependencies[R]
platforms[R]
sources[R]

Public Class Methods

build(gemfile, lockfile, unlock) click to toggle source
    # File lib/bundler/definition.rb, line 10
10:     def self.build(gemfile, lockfile, unlock)
11:       unlock ||= {}
12:       gemfile = Pathname.new(gemfile).expand_path
13: 
14:       unless gemfile.file?
15:         raise GemfileNotFound, "#{gemfile} not found"
16:       end
17: 
18:       Dsl.evaluate(gemfile, lockfile, unlock)
19:     end
new(lockfile, dependencies, sources, unlock) click to toggle source
    # File lib/bundler/definition.rb, line 33
33:     def initialize(lockfile, dependencies, sources, unlock)
34:       @unlocking = unlock == true || !unlock.empty?
35: 
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 = Bundler.rubygems.platforms.map { |p| generic(p) }.compact.last
68:       @new_platform = !@platforms.include?(current_platform)
69:       @platforms |= [current_platform]
70: 
71:       @path_changes = @sources.any? do |source|
72:         next unless source.instance_of?(Source::Path)
73: 
74:         locked = @locked_sources.find do |ls|
75:           ls.class == source.class && ls.path == source.path
76:         end
77: 
78:         if locked
79:           unlocking = locked.specs.any? do |spec|
80:             @locked_specs.any? do |locked_spec|
81:               locked_spec.source != locked
82:             end
83:           end
84:         end
85: 
86:         !locked || unlocking || source.specs != locked.specs
87:       end
88:       eager_unlock = expand_dependencies(@unlock[:gems])
89:       @unlock[:gems] = @locked_specs.for(eager_unlock).map { |s| s.name }
90: 
91:       @source_changes = converge_sources
92:       @dependency_changes = converge_dependencies
93: 
94:       fixup_dependency_types!
95:     end

Public Instance Methods

current_dependencies() click to toggle source
     # File lib/bundler/definition.rb, line 165
165:     def current_dependencies
166:       dependencies.reject { |d| !d.should_include? }
167:     end
ensure_equivalent_gemfile_and_lockfile(explicit_flag = false) click to toggle source
     # File lib/bundler/definition.rb, line 290
290:     def ensure_equivalent_gemfile_and_lockfile(explicit_flag = false)
291:       changes = false
292: 
293:       msg = "You are trying to install in deployment mode after changing\n"              "your Gemfile. Run `bundle install` elsewhere and add the\n"              "updated Gemfile.lock to version control."
294: 
295:       unless explicit_flag
296:         msg += "\n\nIf this is a development machine, remove the Gemfile "                 "freeze \nby running `bundle install --no-deployment`."
297:       end
298: 
299:       added =   []
300:       deleted = []
301:       changed = []
302: 
303:       if @locked_sources != @sources
304:         new_sources = @sources - @locked_sources
305:         deleted_sources = @locked_sources - @sources
306: 
307:         if new_sources.any?
308:           added.concat new_sources.map { |source| "* source: #{source}" }
309:         end
310: 
311:         if deleted_sources.any?
312:           deleted.concat deleted_sources.map { |source| "* source: #{source}" }
313:         end
314: 
315:         changes = true
316:       end
317: 
318:       both_sources = Hash.new { |h,k| h[k] = ["no specified source", "no specified source"] }
319:       @dependencies.each { |d| both_sources[d.name][0] = d.source if d.source }
320:       @locked_deps.each  { |d| both_sources[d.name][1] = d.source if d.source }
321:       both_sources.delete_if { |k,v| v[0] == v[1] }
322: 
323:       if @dependencies != @locked_deps
324:         new_deps = @dependencies - @locked_deps
325:         deleted_deps = @locked_deps - @dependencies
326: 
327:         if new_deps.any?
328:           added.concat new_deps.map { |d| "* #{pretty_dep(d)}" }
329:         end
330: 
331:         if deleted_deps.any?
332:           deleted.concat deleted_deps.map { |d| "* #{pretty_dep(d)}" }
333:         end
334: 
335:         both_sources.each do |name, sources|
336:           changed << "* #{name} from `#{sources[0]}` to `#{sources[1]}`"
337:         end
338: 
339:         changes = true
340:       end
341: 
342:       msg << "\n\nYou have added to the Gemfile:\n"     << added.join("\n") if added.any?
343:       msg << "\n\nYou have deleted from the Gemfile:\n" << deleted.join("\n") if deleted.any?
344:       msg << "\n\nYou have changed in the Gemfile:\n"   << changed.join("\n") if changed.any?
345:       msg << "\n"
346: 
347:       raise ProductionError, msg if added.any? || deleted.any? || changed.any?
348:     end
fixup_dependency_types!() click to toggle source
     # File lib/bundler/definition.rb, line 97
 97:     def fixup_dependency_types!
 98:       # XXX This is a temporary workaround for a bug when using rubygems 1.8.15
 99:       # where Gem::Dependency#== matches Gem::Dependency#type. As the lockfile
100:       # doesn't carry a notion of the dependency type, if you use
101:       # add_development_dependency in a gemspec that's loaded with the gemspec
102:       # directive, the lockfile dependencies and resolved dependencies end up
103:       # with a mismatch on #type.
104:       # Test coverage to catch a regression on this is in gemspec_spec.rb
105:       @dependencies.each do |d|
106:         if ld = @locked_deps.find { |l| l.name == d.name }
107:           ld.instance_variable_set(:@type, d.type)
108:         end
109:       end
110:     end
groups() click to toggle source
     # File lib/bundler/definition.rb, line 228
228:     def groups
229:       dependencies.map { |d| d.groups }.flatten.uniq
230:     end
index() click to toggle source
     # File lib/bundler/definition.rb, line 197
197:     def index
198:       @index ||= Index.build do |idx|
199:         dependency_names = @dependencies.dup || []
200:         dependency_names.map! {|d| d.name }
201: 
202:         @sources.each do |s|
203:           if s.is_a?(Bundler::Source::Rubygems)
204:             s.dependency_names = dependency_names.uniq
205:             idx.add_source s.specs
206:           else
207:             source_index = s.specs
208:             dependency_names += source_index.unmet_dependency_names
209:             idx.add_source source_index
210:           end
211:         end
212:       end
213:     end
lock(file) click to toggle source
     # File lib/bundler/definition.rb, line 232
232:     def lock(file)
233:       contents = to_lock
234: 
235:       # Convert to \r\n if the existing lock has them
236:       # i.e., Windows with `git config core.autocrlf=true`
237:       contents.gsub!(/\n/, "\r\n") if @lockfile_contents.match("\r\n")
238: 
239:       return if @lockfile_contents == contents
240: 
241:       if Bundler.settings[:frozen]
242:         # TODO: Warn here if we got here.
243:         return
244:       end
245: 
246:       File.open(file, 'wb'){|f| f.puts(contents) }
247:     end
missing_specs() click to toggle source
     # File lib/bundler/definition.rb, line 151
151:     def missing_specs
152:       missing = []
153:       resolve.materialize(requested_dependencies, missing)
154:       missing
155:     end
new_platform?() click to toggle source
     # File lib/bundler/definition.rb, line 147
147:     def new_platform?
148:       @new_platform
149:     end
new_specs() click to toggle source
     # File lib/bundler/definition.rb, line 139
139:     def new_specs
140:       specs - @locked_specs
141:     end
no_sources?() click to toggle source
     # File lib/bundler/definition.rb, line 224
224:     def no_sources?
225:       @sources.length == 1 && @sources.first.remotes.empty?
226:     end
removed_specs() click to toggle source
     # File lib/bundler/definition.rb, line 143
143:     def removed_specs
144:       @locked_specs - specs
145:     end
requested_specs() click to toggle source
     # File lib/bundler/definition.rb, line 157
157:     def requested_specs
158:       @requested_specs ||= begin
159:         groups = self.groups - Bundler.settings.without
160:         groups.map! { |g| g.to_sym }
161:         specs_for(groups)
162:       end
163:     end
resolve() click to toggle source
     # File lib/bundler/definition.rb, line 175
175:     def resolve
176:       @resolve ||= begin
177:         if Bundler.settings[:frozen] || (!@unlocking && !@source_changes && !@dependency_changes && !@new_platform && !@path_changes)
178:           @locked_specs
179:         else
180:           last_resolve = converge_locked_specs
181: 
182:           # Record the specs available in each gem's source, so that those
183:           # specs will be available later when the resolver knows where to
184:           # look for that gemspec (or its dependencies)
185:           source_requirements = {}
186:           dependencies.each do |dep|
187:             next unless dep.source
188:             source_requirements[dep.name] = dep.source.specs
189:           end
190: 
191:           # Run a resolve against the locally available gems
192:           last_resolve.merge Resolver.resolve(expanded_dependencies, index, source_requirements, last_resolve)
193:         end
194:       end
195:     end
resolve_remotely!() click to toggle source
     # File lib/bundler/definition.rb, line 118
118:     def resolve_remotely!
119:       raise "Specs already loaded" if @specs
120:       @remote = true
121:       @sources.each { |s| s.remote! }
122:       specs
123:     end
resolve_with_cache!() click to toggle source
     # File lib/bundler/definition.rb, line 112
112:     def resolve_with_cache!
113:       raise "Specs already loaded" if @specs
114:       @sources.each { |s| s.cached! }
115:       specs
116:     end
rubygems_index() click to toggle source

used when frozen is enabled so we can find the bundler spec, even if (say) a git gem is not checked out.

     # File lib/bundler/definition.rb, line 217
217:     def rubygems_index
218:       @rubygems_index ||= Index.build do |idx|
219:         rubygems = @sources.find{|s| s.is_a?(Source::Rubygems) }
220:         idx.add_source rubygems.specs
221:       end
222:     end
specs() click to toggle source
     # File lib/bundler/definition.rb, line 125
125:     def specs
126:       @specs ||= begin
127:         specs = resolve.materialize(requested_dependencies)
128: 
129:         unless specs["bundler"].any?
130:           local = Bundler.settings[:frozen] ? rubygems_index : index
131:           bundler = local.search(Gem::Dependency.new('bundler', VERSION)).last
132:           specs["bundler"] = bundler if bundler
133:         end
134: 
135:         specs
136:       end
137:     end
specs_for(groups) click to toggle source
     # File lib/bundler/definition.rb, line 169
169:     def specs_for(groups)
170:       deps = dependencies.select { |d| (d.groups & groups).any? }
171:       deps.delete_if { |d| !d.should_include? }
172:       specs.for(expand_dependencies(deps))
173:     end
to_lock() click to toggle source
     # File lib/bundler/definition.rb, line 249
249:     def to_lock
250:       out = ""
251: 
252:       sorted_sources.each do |source|
253:         # Add the source header
254:         out << source.to_lock
255:         # Find all specs for this source
256:         resolve.
257:           select  { |s| s.source == source }.
258:           # This needs to be sorted by full name so that
259:           # gems with the same name, but different platform
260:           # are ordered consistantly
261:           sort_by { |s| s.full_name }.
262:           each do |spec|
263:             next if spec.name == 'bundler'
264:             out << spec.to_lock
265:         end
266:         out << "\n"
267:       end
268: 
269:       out << "PLATFORMS\n"
270: 
271:       platforms.map { |p| p.to_s }.sort.each do |p|
272:         out << "  #{p}\n"
273:       end
274: 
275:       out << "\n"
276:       out << "DEPENDENCIES\n"
277: 
278:       handled = []
279:       dependencies.
280:         sort_by { |d| d.to_s }.
281:         each do |dep|
282:           next if handled.include?(dep.name)
283:           out << dep.to_lock
284:           handled << dep.name
285:       end
286: 
287:       out
288:     end

Private Instance Methods

converge_dependencies() click to toggle source
     # File lib/bundler/definition.rb, line 400
400:     def converge_dependencies
401:       (@dependencies + @locked_deps).each do |dep|
402:         if dep.source
403:           dep.source = @sources.find { |s| dep.source == s }
404:         end
405:       end
406:       Set.new(@dependencies) != Set.new(@locked_deps)
407:     end
converge_locked_specs() click to toggle source

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 412
412:     def converge_locked_specs
413:       deps = []
414: 
415:       # Build a list of dependencies that are the same in the Gemfile
416:       # and Gemfile.lock. If the Gemfile modified a dependency, but
417:       # the gem in the Gemfile.lock still satisfies it, this is fine
418:       # too.
419:       @dependencies.each do |dep|
420:         locked_dep = @locked_deps.find { |d| dep == d }
421: 
422:         if in_locked_deps?(dep, locked_dep) || satisfies_locked_spec?(dep)
423:           deps << dep
424:         elsif dep.source.is_a?(Source::Path) && dep.current_platform? && (!locked_dep || dep.source != locked_dep.source)
425:           @locked_specs.each do |s|
426:             @unlock[:gems] << s.name if s.source == dep.source
427:           end
428: 
429:           dep.source.unlock! if dep.source.respond_to?(:unlock!)
430:           dep.source.specs.each { |s| @unlock[:gems] << s.name }
431:         end
432:       end
433: 
434:       converged = []
435:       @locked_specs.each do |s|
436:         s.source = @sources.find { |src| s.source == src }
437: 
438:         # Don't add a spec to the list if its source is expired. For example,
439:         # if you change a Git gem to Rubygems.
440:         next if s.source.nil? || @unlock[:sources].include?(s.name)
441:         # If the spec is from a path source and it doesn't exist anymore
442:         # then we just unlock it.
443: 
444:         # Path sources have special logic
445:         if s.source.instance_of?(Source::Path)
446:           other = s.source.specs[s].first
447: 
448:           # If the spec is no longer in the path source, unlock it. This
449:           # commonly happens if the version changed in the gemspec
450:           next unless other
451: 
452:           deps2 = other.dependencies.select { |d| d.type != :development }
453:           # If the dependencies of the path source have changed, unlock it
454:           next unless s.dependencies.sort == deps2.sort
455:         end
456: 
457:         converged << s
458:       end
459: 
460:       resolve = SpecSet.new(converged)
461:       resolve = resolve.for(expand_dependencies(deps, true), @unlock[:gems])
462:       diff    = @locked_specs.to_a - resolve.to_a
463: 
464:       # Now, we unlock any sources that do not have anymore gems pinned to it
465:       @sources.each do |source|
466:         next unless source.respond_to?(:unlock!)
467: 
468:         unless resolve.any? { |s| s.source == source }
469:           source.unlock! if !diff.empty? && diff.any? { |s| s.source == source }
470:         end
471:       end
472: 
473:       resolve
474:     end
converge_sources() click to toggle source
     # File lib/bundler/definition.rb, line 362
362:     def converge_sources
363:       changes = false
364: 
365:       # Get the Rubygems source from the Gemfile.lock
366:       locked_gem = @locked_sources.find { |s| Source::Rubygems === s }
367: 
368:       # Get the Rubygems source from the Gemfile
369:       actual_gem = @sources.find { |s| Source::Rubygems === s }
370: 
371:       # If there is a Rubygems source in both
372:       if locked_gem && actual_gem
373:         # Merge the remotes from the Gemfile into the Gemfile.lock
374:         changes = changes | locked_gem.replace_remotes(actual_gem)
375:       end
376: 
377:       # Replace the sources from the Gemfile with the sources from the Gemfile.lock,
378:       # if they exist in the Gemfile.lock and are `==`. If you can't find an equivalent
379:       # source in the Gemfile.lock, use the one from the Gemfile.
380:       @sources.map! do |source|
381:         @locked_sources.find { |s| s == source } || source
382:       end
383:       changes = changes | (Set.new(@sources) != Set.new(@locked_sources))
384: 
385:       @sources.each do |source|
386:         # If the source is unlockable and the current command allows an unlock of
387:         # the source (for example, you are doing a `bundle update <foo>` of a git-pinned
388:         # gem), unlock it. For git sources, this means to unlock the revision, which
389:         # will cause the `ref` used to be the most recent for the branch (or master) if
390:         # an explicit `ref` is not used.
391:         if source.respond_to?(:unlock!) && @unlock[:sources].include?(source.name)
392:           source.unlock!
393:           changes = true
394:         end
395:       end
396: 
397:       changes
398:     end
expand_dependencies(dependencies, remote = false) click to toggle source
     # File lib/bundler/definition.rb, line 488
488:     def expand_dependencies(dependencies, remote = false)
489:       deps = []
490:       dependencies.each do |dep|
491:         dep = Dependency.new(dep, ">= 0") unless dep.respond_to?(:name)
492:         dep.gem_platforms(@platforms).each do |p|
493:           deps << DepProxy.new(dep, p) if remote || p == generic(Gem::Platform.local)
494:         end
495:       end
496:       deps
497:     end
expanded_dependencies() click to toggle source
     # File lib/bundler/definition.rb, line 484
484:     def expanded_dependencies
485:       @expanded_dependencies ||= expand_dependencies(dependencies, @remote)
486:     end
in_locked_deps?(dep, d) click to toggle source
     # File lib/bundler/definition.rb, line 476
476:     def in_locked_deps?(dep, d)
477:       d && dep.source == d.source
478:     end
pretty_dep(dep, source = false) click to toggle source
     # File lib/bundler/definition.rb, line 355
355:     def pretty_dep(dep, source = false)
356:       msg  = "#{dep.name}"
357:       msg << " (#{dep.requirement})" unless dep.requirement == Gem::Requirement.default
358:       msg << " from the `#{dep.source}` source" if source && dep.source
359:       msg
360:     end
requested_dependencies() click to toggle source
     # File lib/bundler/definition.rb, line 506
506:     def requested_dependencies
507:       groups = self.groups - Bundler.settings.without
508:       groups.map! { |g| g.to_sym }
509:       dependencies.reject { |d| !d.should_include? || (d.groups & groups).empty? }
510:     end
satisfies_locked_spec?(dep) click to toggle source
     # File lib/bundler/definition.rb, line 480
480:     def satisfies_locked_spec?(dep)
481:       @locked_specs.any? { |s| s.satisfies?(dep) && (!dep.source || s.source == dep.source) }
482:     end
sorted_sources() click to toggle source
     # File lib/bundler/definition.rb, line 499
499:     def sorted_sources
500:       @sources.sort_by do |s|
501:         # Place GEM at the top
502:         [ s.is_a?(Source::Rubygems) ? 1 : 0, s.to_s ]
503:       end
504:     end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.