mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Merge bundler to standard libraries.
rubygems 2.7.x depends bundler-1.15.x. This is preparation for rubygems and bundler migration. * lib/bundler.rb, lib/bundler/*: files of bundler-1.15.4 * spec/bundler/*: rspec examples of bundler-1.15.4. I applied patches. * https://github.com/bundler/bundler/pull/6007 * Exclude not working examples on ruby repository. * Fake ruby interpriter instead of installed ruby. * Makefile.in: Added test task named `test-bundler`. This task is only working macOS/linux yet. I'm going to support Windows environment later. * tool/sync_default_gems.rb: Added sync task for bundler. [Feature #12733][ruby-core:77172] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59779 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
f2e04b77aa
commit
8598f8c2dc
409 changed files with 60699 additions and 1 deletions
320
lib/bundler/runtime.rb
Normal file
320
lib/bundler/runtime.rb
Normal file
|
@ -0,0 +1,320 @@
|
|||
# frozen_string_literal: true
|
||||
require "digest/sha1"
|
||||
|
||||
module Bundler
|
||||
class Runtime
|
||||
include SharedHelpers
|
||||
|
||||
def initialize(root, definition)
|
||||
@root = root
|
||||
@definition = definition
|
||||
end
|
||||
|
||||
def setup(*groups)
|
||||
@definition.ensure_equivalent_gemfile_and_lockfile if Bundler.settings[:frozen]
|
||||
|
||||
groups.map!(&:to_sym)
|
||||
|
||||
# Has to happen first
|
||||
clean_load_path
|
||||
|
||||
specs = groups.any? ? @definition.specs_for(groups) : requested_specs
|
||||
|
||||
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
|
||||
|
||||
setup_manpath
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
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
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.definition_method(meth)
|
||||
define_method(meth) do
|
||||
raise ArgumentError, "no definition when calling Runtime##{meth}" unless @definition
|
||||
@definition.send(meth)
|
||||
end
|
||||
end
|
||||
private_class_method :definition_method
|
||||
|
||||
definition_method :requested_specs
|
||||
definition_method :specs
|
||||
definition_method :dependencies
|
||||
definition_method :current_dependencies
|
||||
definition_method :requires
|
||||
|
||||
def lock(opts = {})
|
||||
return if @definition.nothing_changed? && !@definition.unlocking?
|
||||
@definition.lock(Bundler.default_lockfile, opts[:preserve_unknown_sections])
|
||||
end
|
||||
|
||||
alias_method :gems, :specs
|
||||
|
||||
def cache(custom_path = nil)
|
||||
cache_path = Bundler.app_cache(custom_path)
|
||||
SharedHelpers.filesystem_access(cache_path) do |p|
|
||||
FileUtils.mkdir_p(p)
|
||||
end unless File.exist?(cache_path)
|
||||
|
||||
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.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)
|
||||
end
|
||||
|
||||
Dir[cache_path.join("*/.git")].each do |git_dir|
|
||||
FileUtils.rm_rf(git_dir)
|
||||
FileUtils.touch(File.expand_path("../.bundlecache", git_dir))
|
||||
end
|
||||
|
||||
prune_cache(cache_path) unless Bundler.settings[:no_prune]
|
||||
end
|
||||
|
||||
def prune_cache(cache_path)
|
||||
SharedHelpers.filesystem_access(cache_path) do |p|
|
||||
FileUtils.mkdir_p(p)
|
||||
end unless File.exist?(cache_path)
|
||||
resolve = @definition.resolve
|
||||
prune_gem_cache(resolve, cache_path)
|
||||
prune_git_and_path_cache(resolve, cache_path)
|
||||
end
|
||||
|
||||
def clean(dry_run = false)
|
||||
gem_bins = Dir["#{Gem.dir}/bin/*"]
|
||||
git_dirs = Dir["#{Gem.dir}/bundler/gems/*"]
|
||||
git_cache_dirs = Dir["#{Gem.dir}/cache/bundler/git/*"]
|
||||
gem_dirs = Dir["#{Gem.dir}/gems/*"]
|
||||
gem_files = Dir["#{Gem.dir}/cache/*.gem"]
|
||||
gemspec_files = Dir["#{Gem.dir}/specifications/*.gemspec"]
|
||||
spec_gem_paths = []
|
||||
# need to keep git sources around
|
||||
spec_git_paths = @definition.spec_git_paths
|
||||
spec_git_cache_dirs = []
|
||||
spec_gem_executables = []
|
||||
spec_cache_paths = []
|
||||
spec_gemspec_paths = []
|
||||
specs.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)
|
||||
spec_git_paths << md[1] if md
|
||||
spec_gem_executables << spec.executables.collect do |executable|
|
||||
e = "#{Bundler.rubygems.gem_bindir}/#{executable}"
|
||||
[e, "#{e}.bat"]
|
||||
end
|
||||
spec_cache_paths << spec.cache_file
|
||||
spec_gemspec_paths << spec.spec_file
|
||||
spec_git_cache_dirs << spec.source.cache_path.to_s if spec.source.is_a?(Bundler::Source::Git)
|
||||
end
|
||||
spec_gem_paths.uniq!
|
||||
spec_gem_executables.flatten!
|
||||
|
||||
stale_gem_bins = gem_bins - spec_gem_executables
|
||||
stale_git_dirs = git_dirs - spec_git_paths - ["#{Gem.dir}/bundler/gems/extensions"]
|
||||
stale_git_cache_dirs = git_cache_dirs - spec_git_cache_dirs
|
||||
stale_gem_dirs = gem_dirs - spec_gem_paths
|
||||
stale_gem_files = gem_files - spec_cache_paths
|
||||
stale_gemspec_files = gemspec_files - spec_gemspec_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) }
|
||||
output = removed_stale_gem_dirs + removed_stale_git_dirs
|
||||
|
||||
unless dry_run
|
||||
stale_files = stale_gem_bins + stale_gem_files + stale_gemspec_files
|
||||
stale_files.each do |file|
|
||||
SharedHelpers.filesystem_access(File.dirname(file)) do |_p|
|
||||
FileUtils.rm(file) if File.exist?(file)
|
||||
end
|
||||
end
|
||||
stale_git_cache_dirs.each do |cache_dir|
|
||||
SharedHelpers.filesystem_access(cache_dir) do |dir|
|
||||
FileUtils.rm_rf(dir) if File.exist?(dir)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
output
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def prune_gem_cache(resolve, cache_path)
|
||||
cached = Dir["#{cache_path}/*.gem"]
|
||||
|
||||
cached = cached.delete_if do |path|
|
||||
spec = Bundler.rubygems.spec_from_gem path
|
||||
|
||||
resolve.any? do |s|
|
||||
s.name == spec.name && s.version == spec.version && !s.source.is_a?(Bundler::Source::Git)
|
||||
end
|
||||
end
|
||||
|
||||
if cached.any?
|
||||
Bundler.ui.info "Removing outdated .gem files from #{Bundler.settings.app_cache_path}"
|
||||
|
||||
cached.each do |path|
|
||||
Bundler.ui.info " * #{File.basename(path)}"
|
||||
File.delete(path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def prune_git_and_path_cache(resolve, cache_path)
|
||||
cached = Dir["#{cache_path}/*/.bundlecache"]
|
||||
|
||||
cached = cached.delete_if do |path|
|
||||
name = File.basename(File.dirname(path))
|
||||
|
||||
resolve.any? do |s|
|
||||
source = s.source
|
||||
source.respond_to?(:app_cache_dirname) && source.app_cache_dirname == name
|
||||
end
|
||||
end
|
||||
|
||||
if cached.any?
|
||||
Bundler.ui.info "Removing outdated git and path gems from #{Bundler.settings.app_cache_path}"
|
||||
|
||||
cached.each do |path|
|
||||
path = File.dirname(path)
|
||||
Bundler.ui.info " * #{File.basename(path)}"
|
||||
FileUtils.rm_rf(path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def setup_manpath
|
||||
# Store original MANPATH for restoration later in with_clean_env()
|
||||
ENV["BUNDLER_ORIG_MANPATH"] = ENV["MANPATH"]
|
||||
|
||||
# Add man/ subdirectories from activated bundles to MANPATH for man(1)
|
||||
manuals = $LOAD_PATH.map do |path|
|
||||
man_subdir = path.sub(/lib$/, "man")
|
||||
man_subdir unless Dir[man_subdir + "/man?/"].empty?
|
||||
end.compact
|
||||
|
||||
return if manuals.empty?
|
||||
ENV["MANPATH"] = manuals.concat(
|
||||
ENV["MANPATH"].to_s.split(File::PATH_SEPARATOR)
|
||||
).uniq.join(File::PATH_SEPARATOR)
|
||||
end
|
||||
|
||||
def remove_dir(dir, dry_run)
|
||||
full_name = Pathname.new(dir).basename.to_s
|
||||
|
||||
parts = full_name.split("-")
|
||||
name = parts[0..-2].join("-")
|
||||
version = parts.last
|
||||
output = "#{name} (#{version})"
|
||||
|
||||
if dry_run
|
||||
Bundler.ui.info "Would have removed #{output}"
|
||||
else
|
||||
Bundler.ui.info "Removing #{output}"
|
||||
FileUtils.rm_rf(dir)
|
||||
end
|
||||
|
||||
output
|
||||
end
|
||||
|
||||
def check_for_activated_spec!(spec)
|
||||
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)
|
||||
"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
|
||||
"Prepending `bundle exec` to your command may solve this."
|
||||
end
|
||||
|
||||
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
|
||||
raise e
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue