diff options
Diffstat (limited to 'lib/bundler/runtime.rb')
| -rw-r--r-- | lib/bundler/runtime.rb | 169 |
1 files changed, 92 insertions, 77 deletions
diff --git a/lib/bundler/runtime.rb b/lib/bundler/runtime.rb index f27597b854..5280e72aa2 100644 --- a/lib/bundler/runtime.rb +++ b/lib/bundler/runtime.rb @@ -10,96 +10,79 @@ module Bundler end def setup(*groups) - @definition.ensure_equivalent_gemfile_and_lockfile if Bundler.frozen? - - groups.map!(&:to_sym) + @definition.ensure_equivalent_gemfile_and_lockfile # Has to happen first clean_load_path - specs = groups.any? ? @definition.specs_for(groups) : requested_specs + specs = @definition.specs_for(groups) SharedHelpers.set_bundle_environment Bundler.rubygems.replace_entrypoints(specs) # Activate the specs load_paths = specs.map do |spec| - unless spec.loaded_from - raise GemNotFound, "#{spec.full_name} is missing. Run `bundle install` to get it." - end - check_for_activated_spec!(spec) Bundler.rubygems.mark_loaded(spec) spec.load_paths.reject {|path| $LOAD_PATH.include?(path) } end.reverse.flatten - # See Gem::Specification#add_self_to_load_path (since RubyGems 1.8) - if insert_index = Bundler.rubygems.load_path_insert_index - # Gem directories must come after -I and ENV['RUBYLIB'] - $LOAD_PATH.insert(insert_index, *load_paths) - else - # We are probably testing in core, -I and RUBYLIB don't apply - $LOAD_PATH.unshift(*load_paths) - end + Gem.add_to_load_path(*load_paths) setup_manpath - lock(:preserve_unknown_sections => true) + lock(preserve_unknown_sections: true) self end - REQUIRE_ERRORS = [ - /^no such file to load -- (.+)$/i, - /^Missing \w+ (?:file\s*)?([^\s]+.rb)$/i, - /^Missing API definition file in (.+)$/i, - /^cannot load such file -- (.+)$/i, - /^dlopen\([^)]*\): Library not loaded: (.+)$/i, - ].freeze - def require(*groups) groups.map!(&:to_sym) groups = [:default] if groups.empty? - @definition.dependencies.each do |dep| - # Skip the dependency if it is not in any of the requested groups, or - # not for the current platform, or doesn't match the gem constraints. - next unless (dep.groups & groups).any? && dep.should_include? - - required_file = nil + dependencies = @definition.dependencies.select do |dep| + # Select the dependency if it is in any of the requested groups, and + # for the current platform, and matches the gem constraints. + (dep.groups & groups).any? && dep.should_include? + end - begin - # Loop through all the specified autorequires for the - # dependency. If there are none, use the dependency's name - # as the autorequire. - Array(dep.autorequire || dep.name).each do |file| - # Allow `require: true` as an alias for `require: <name>` - file = dep.name if file == true - required_file = file - begin - Kernel.require file - rescue => e - raise e if e.is_a?(LoadError) # we handle this a little later + Plugin.hook(Plugin::Events::GEM_BEFORE_REQUIRE_ALL, dependencies) + + dependencies.each do |dep| + Plugin.hook(Plugin::Events::GEM_BEFORE_REQUIRE, dep) + + # Loop through all the specified autorequires for the + # dependency. If there are none, use the dependency's name + # as the autorequire. + Array(dep.autorequire || dep.name).each do |file| + # Allow `require: true` as an alias for `require: <name>` + file = dep.name if file == true + required_file = file + begin + Kernel.require required_file + rescue LoadError => e + if dep.autorequire.nil? && e.path == required_file + if required_file.include?("-") + required_file = required_file.tr("-", "/") + retry + end + else raise Bundler::GemRequireError.new e, "There was an error while trying to load the gem '#{file}'." end - end - rescue LoadError => e - REQUIRE_ERRORS.find {|r| r =~ e.message } - raise if dep.autorequire || $1 != required_file - - if dep.autorequire.nil? && dep.name.include?("-") - begin - namespaced_file = dep.name.tr("-", "/") - Kernel.require namespaced_file - rescue LoadError => e - REQUIRE_ERRORS.find {|r| r =~ e.message } - raise if $1 != namespaced_file - end + rescue StandardError => e + raise Bundler::GemRequireError.new e, + "There was an error while trying to load the gem '#{file}'." end end + + Plugin.hook(Plugin::Events::GEM_AFTER_REQUIRE, dep) end + + Plugin.hook(Plugin::Events::GEM_AFTER_REQUIRE_ALL, dependencies) + + dependencies end def self.definition_method(meth) @@ -117,13 +100,13 @@ module Bundler definition_method :requires def lock(opts = {}) - return if @definition.nothing_changed? && !@definition.unlocking? - @definition.lock(Bundler.default_lockfile, opts[:preserve_unknown_sections]) + return if @definition.no_resolve_needed? + @definition.lock(opts[:preserve_unknown_sections]) end alias_method :gems, :specs - def cache(custom_path = nil) + def cache(custom_path = nil, local = false) cache_path = Bundler.app_cache(custom_path) SharedHelpers.filesystem_access(cache_path) do |p| FileUtils.mkdir_p(p) @@ -131,12 +114,31 @@ module Bundler Bundler.ui.info "Updating files in #{Bundler.settings.app_cache_path}" - specs_to_cache = Bundler.settings[:cache_all_platforms] ? @definition.resolve.materialized_for_all_platforms : specs + specs_to_cache = if Bundler.settings[:cache_all_platforms] + @definition.resolve.materialized_for_all_platforms + else + begin + specs + rescue GemNotFound + if local + Bundler.ui.warn "Some gems seem to be missing from your #{Bundler.settings.app_cache_path} directory." + end + + raise + end + end + specs_to_cache.each do |spec| next if spec.name == "bundler" - next if spec.source.is_a?(Source::Gemspec) - spec.source.send(:fetch_gem, spec) if Bundler.settings[:cache_all_platforms] && spec.source.respond_to?(:fetch_gem, true) - spec.source.cache(spec, custom_path) if spec.source.respond_to?(:cache) + + source = spec.source + next if source.is_a?(Source::Gemspec) + + if source.respond_to?(:migrate_cache) + source.migrate_cache(custom_path, local: local) + elsif source.respond_to?(:cache) + source.cache(spec, custom_path) + end end Dir[cache_path.join("*/.git")].each do |git_dir| @@ -163,6 +165,7 @@ module Bundler gem_dirs = Dir["#{Gem.dir}/gems/*"] gem_files = Dir["#{Gem.dir}/cache/*.gem"] gemspec_files = Dir["#{Gem.dir}/specifications/*.gemspec"] + extension_dirs = Dir["#{Gem.dir}/extensions/*/*/*"] + Dir["#{Gem.dir}/bundler/gems/extensions/*/*/*"] spec_gem_paths = [] # need to keep git sources around spec_git_paths = @definition.spec_git_paths @@ -170,7 +173,15 @@ module Bundler spec_gem_executables = [] spec_cache_paths = [] spec_gemspec_paths = [] - specs.each do |spec| + spec_extension_paths = [] + specs_to_keep = Bundler.rubygems.add_default_gems_to(specs).values + + current_bundler = Bundler.rubygems.find_bundler(Bundler.gem_version) + if current_bundler + specs_to_keep << current_bundler + end + + specs_to_keep.each do |spec| spec_gem_paths << spec.full_gem_path # need to check here in case gems are nested like for the rails git repo md = %r{(.+bundler/gems/.+-[a-f0-9]{7,12})}.match(spec.full_gem_path) @@ -181,6 +192,7 @@ module Bundler end spec_cache_paths << spec.cache_file spec_gemspec_paths << spec.spec_file + spec_extension_paths << spec.extension_dir if spec.respond_to?(:extension_dir) spec_git_cache_dirs << spec.source.cache_path.to_s if spec.source.is_a?(Bundler::Source::Git) end spec_gem_paths.uniq! @@ -192,6 +204,7 @@ module Bundler stale_gem_dirs = gem_dirs - spec_gem_paths stale_gem_files = gem_files - spec_cache_paths stale_gemspec_files = gemspec_files - spec_gemspec_paths + stale_extension_dirs = extension_dirs - spec_extension_paths removed_stale_gem_dirs = stale_gem_dirs.collect {|dir| remove_dir(dir, dry_run) } removed_stale_git_dirs = stale_git_dirs.collect {|dir| remove_dir(dir, dry_run) } @@ -204,8 +217,10 @@ module Bundler FileUtils.rm(file) if File.exist?(file) end end - stale_git_cache_dirs.each do |cache_dir| - SharedHelpers.filesystem_access(cache_dir) do |dir| + + stale_dirs = stale_git_cache_dirs + stale_extension_dirs + stale_dirs.each do |stale_dir| + SharedHelpers.filesystem_access(stale_dir) do |dir| FileUtils.rm_rf(dir) if File.exist?(dir) end end @@ -214,7 +229,7 @@ module Bundler output end - private + private def prune_gem_cache(resolve, cache_path) cached = Dir["#{cache_path}/*.gem"] @@ -232,7 +247,11 @@ module Bundler cached.each do |path| Bundler.ui.info " * #{File.basename(path)}" - File.delete(path) + + begin + File.delete(path) + rescue Errno::ENOENT + end end end end @@ -262,14 +281,14 @@ module Bundler def setup_manpath # Add man/ subdirectories from activated bundles to MANPATH for man(1) - manuals = $LOAD_PATH.map do |path| + manuals = $LOAD_PATH.filter_map do |path| man_subdir = path.sub(/lib$/, "man") man_subdir unless Dir[man_subdir + "/man?/"].empty? - end.compact + end return if manuals.empty? Bundler::SharedHelpers.set_env "MANPATH", manuals.concat( - ENV["MANPATH"].to_s.split(File::PATH_SEPARATOR) + ENV["MANPATH"] ? ENV["MANPATH"].to_s.split(File::PATH_SEPARATOR) : [""] ).uniq.join(File::PATH_SEPARATOR) end @@ -295,7 +314,7 @@ module Bundler return unless activated_spec = Bundler.rubygems.loaded_specs(spec.name) return if activated_spec.version == spec.version - suggestion = if Bundler.rubygems.spec_default_gem?(activated_spec) + suggestion = if activated_spec.default_gem? "Since #{spec.name} is a default gem, you can either remove your dependency on it" \ " or try updating to a newer version of bundler that supports #{spec.name} as a default gem." else @@ -305,11 +324,7 @@ module Bundler e = Gem::LoadError.new "You have already activated #{activated_spec.name} #{activated_spec.version}, " \ "but your Gemfile requires #{spec.name} #{spec.version}. #{suggestion}" e.name = spec.name - if e.respond_to?(:requirement=) - e.requirement = Gem::Requirement.new(spec.version.to_s) - else - e.version_requirement = Gem::Requirement.new(spec.version.to_s) - end + e.requirement = Gem::Requirement.new(spec.version.to_s) raise e end end |
