summaryrefslogtreecommitdiff
path: root/lib/rubygems/dependency_installer.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rubygems/dependency_installer.rb')
-rw-r--r--lib/rubygems/dependency_installer.rb176
1 files changed, 72 insertions, 104 deletions
diff --git a/lib/rubygems/dependency_installer.rb b/lib/rubygems/dependency_installer.rb
index ec8a50d912..26ef41b2f1 100644
--- a/lib/rubygems/dependency_installer.rb
+++ b/lib/rubygems/dependency_installer.rb
@@ -22,8 +22,7 @@ class Gem::DependencyInstaller
}
##
- # Creates a new installer instance that will install +gem_name+ using
- # version requirement +version+ and +options+.
+ # Creates a new installer instance.
#
# Options are:
# :env_shebang:: See Gem::Installer::new.
@@ -36,7 +35,7 @@ class Gem::DependencyInstaller
# :install_dir: See Gem::Installer#install.
# :security_policy: See Gem::Installer::new and Gem::Security.
# :wrappers: See Gem::Installer::new
- def initialize(gem_name, version = nil, options = {})
+ def initialize(options = {})
options = DEFAULT_OPTIONS.merge options
@env_shebang = options[:env_shebang]
@domain = options[:domain]
@@ -46,49 +45,9 @@ class Gem::DependencyInstaller
@install_dir = options[:install_dir] || Gem.dir
@security_policy = options[:security_policy]
@wrappers = options[:wrappers]
+ @bin_dir = options[:bin_dir]
@installed_gems = []
-
- spec_and_source = nil
-
- glob = if File::ALT_SEPARATOR then
- gem_name.gsub File::ALT_SEPARATOR, File::SEPARATOR
- else
- gem_name
- end
-
- local_gems = Dir["#{glob}*"].sort.reverse
-
- unless local_gems.empty? then
- local_gems.each do |gem_file|
- next unless gem_file =~ /gem$/
- begin
- spec = Gem::Format.from_file_by_path(gem_file).spec
- spec_and_source = [spec, gem_file]
- break
- rescue SystemCallError, Gem::Package::FormatError
- end
- end
- end
-
- if spec_and_source.nil? then
- version ||= Gem::Requirement.default
- @dep = Gem::Dependency.new gem_name, version
- spec_and_sources = find_gems_with_sources(@dep).reverse
-
- spec_and_source = spec_and_sources.find do |spec, source|
- Gem::Platform.match spec.platform
- end
- end
-
- if spec_and_source.nil? then
- raise Gem::GemNotFoundException,
- "could not find #{gem_name} locally or in a repository"
- end
-
- @specs_and_sources = [spec_and_source]
-
- gather_dependencies
end
##
@@ -107,71 +66,30 @@ class Gem::DependencyInstaller
end
if @domain == :both or @domain == :remote then
- gems_and_sources.push(*Gem::SourceInfoCache.search_with_source(dep, true))
- end
-
- gems_and_sources.sort_by do |gem, source|
- [gem, source !~ /^http:\/\// ? 1 : 0] # local gems win
- end
- end
-
- ##
- # Moves the gem +spec+ from +source_uri+ to the cache dir unless it is
- # already there. If the source_uri is local the gem cache dir copy is
- # always replaced.
- def download(spec, source_uri)
- gem_file_name = "#{spec.full_name}.gem"
- local_gem_path = File.join @install_dir, 'cache', gem_file_name
-
- Gem.ensure_gem_subdirectories @install_dir
-
- source_uri = URI.parse source_uri unless URI::Generic === source_uri
- scheme = source_uri.scheme
-
- # URI.parse gets confused by MS Windows paths with forward slashes.
- scheme = nil if scheme =~ /^[a-z]$/i
-
- case scheme
- when 'http' then
- unless File.exist? local_gem_path then
- begin
- say "Downloading gem #{gem_file_name}" if
- Gem.configuration.really_verbose
-
- remote_gem_path = source_uri + "gems/#{gem_file_name}"
-
- gem = Gem::RemoteFetcher.fetcher.fetch_path remote_gem_path
- rescue Gem::RemoteFetcher::FetchError
- raise if spec.original_platform == spec.platform
-
- alternate_name = "#{spec.name}-#{spec.version}-#{spec.original_platform}.gem"
+ begin
+ requirements = dep.version_requirements.requirements.map do |req, ver|
+ req
+ end
- say "Failed, downloading gem #{alternate_name}" if
- Gem.configuration.really_verbose
+ all = requirements.length > 1 ||
+ requirements.first != ">=" || requirements.first != ">"
- remote_gem_path = source_uri + "gems/#{alternate_name}"
+ found = Gem::SourceInfoCache.search_with_source dep, true, all
- gem = Gem::RemoteFetcher.fetcher.fetch_path remote_gem_path
- end
+ gems_and_sources.push(*found)
- File.open local_gem_path, 'wb' do |fp|
- fp.write gem
+ rescue Gem::RemoteFetcher::FetchError => e
+ if Gem.configuration.really_verbose then
+ say "Error fetching remote data:\t\t#{e.message}"
+ say "Falling back to local-only install"
end
+ @domain = :local
end
- when nil, 'file' then # TODO test for local overriding cache
- begin
- FileUtils.cp source_uri.to_s, local_gem_path
- rescue Errno::EACCES
- local_gem_path = source_uri.to_s
- end
-
- say "Using local gem #{local_gem_path}" if
- Gem.configuration.really_verbose
- else
- raise Gem::InstallError, "unsupported URI scheme #{source_uri.scheme}"
end
- local_gem_path
+ gems_and_sources.sort_by do |gem, source|
+ [gem, source =~ /^http:\/\// ? 0 : 1] # local gems win
+ end
end
##
@@ -208,9 +126,57 @@ class Gem::DependencyInstaller
@gems_to_install = dependency_list.dependency_order.reverse
end
+ def find_spec_by_name_and_version gem_name, version = Gem::Requirement.default
+ spec_and_source = nil
+
+ glob = if File::ALT_SEPARATOR then
+ gem_name.gsub File::ALT_SEPARATOR, File::SEPARATOR
+ else
+ gem_name
+ end
+
+ local_gems = Dir["#{glob}*"].sort.reverse
+
+ unless local_gems.empty? then
+ local_gems.each do |gem_file|
+ next unless gem_file =~ /gem$/
+ begin
+ spec = Gem::Format.from_file_by_path(gem_file).spec
+ spec_and_source = [spec, gem_file]
+ break
+ rescue SystemCallError, Gem::Package::FormatError
+ end
+ end
+ end
+
+ if spec_and_source.nil? then
+ dep = Gem::Dependency.new gem_name, version
+ spec_and_sources = find_gems_with_sources(dep).reverse
+
+ spec_and_source = spec_and_sources.find { |spec, source|
+ Gem::Platform.match spec.platform
+ }
+ end
+
+ if spec_and_source.nil? then
+ raise Gem::GemNotFoundException,
+ "could not find #{gem_name} locally or in a repository"
+ end
+
+ @specs_and_sources = [spec_and_source]
+ end
+
##
# Installs the gem and all its dependencies.
- def install
+ def install dep_or_name, version = Gem::Requirement.default
+ if String === dep_or_name then
+ find_spec_by_name_and_version dep_or_name, version
+ else
+ @specs_and_sources = [find_gems_with_sources(dep_or_name).last]
+ end
+
+ gather_dependencies
+
spec_dir = File.join @install_dir, 'specifications'
source_index = Gem::SourceIndex.from_gems_in spec_dir
@@ -219,10 +185,11 @@ class Gem::DependencyInstaller
# HACK is this test for full_name acceptable?
next if source_index.any? { |n,_| n == spec.full_name } and not last
+ # TODO: make this sorta_verbose so other users can benefit from it
say "Installing gem #{spec.full_name}" if Gem.configuration.really_verbose
_, source_uri = @specs_and_sources.assoc spec
- local_gem_path = download spec, source_uri
+ local_gem_path = Gem::RemoteFetcher.fetcher.download spec, source_uri
inst = Gem::Installer.new local_gem_path,
:env_shebang => @env_shebang,
@@ -231,7 +198,8 @@ class Gem::DependencyInstaller
:ignore_dependencies => @ignore_dependencies,
:install_dir => @install_dir,
:security_policy => @security_policy,
- :wrappers => @wrappers
+ :wrappers => @wrappers,
+ :bin_dir => @bin_dir
spec = inst.install