diff options
Diffstat (limited to 'lib/rubygems/dependency_installer.rb')
-rw-r--r-- | lib/rubygems/dependency_installer.rb | 176 |
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 |