lib/rubygems/dependency_installer.rb in rubygems-update-1.1.1 vs lib/rubygems/dependency_installer.rb in rubygems-update-1.2.0

- old
+ new

@@ -1,11 +1,14 @@ require 'rubygems' require 'rubygems/dependency_list' require 'rubygems/installer' -require 'rubygems/source_info_cache' +require 'rubygems/spec_fetcher' require 'rubygems/user_interaction' +## +# Installs a gem along with all its dependencies from local and remote gems. + class Gem::DependencyInstaller include Gem::UserInteraction attr_reader :gems_to_install @@ -23,40 +26,54 @@ ## # Creates a new installer instance. # # Options are: - # :env_shebang:: See Gem::Installer::new. + # :cache_dir:: Alternate repository path to store .gem files in. # :domain:: :local, :remote, or :both. :local only searches gems in the # current directory. :remote searches only gems in Gem::sources. # :both searches both. + # :env_shebang:: See Gem::Installer::new. # :force:: See Gem::Installer#install. # :format_executable:: See Gem::Installer#initialize. - # :ignore_dependencies: Don't install any dependencies. - # :install_dir: See Gem::Installer#install. - # :security_policy: See Gem::Installer::new and Gem::Security. - # :wrappers: See Gem::Installer::new + # :ignore_dependencies:: Don't install any dependencies. + # :install_dir:: See Gem::Installer#install. + # :security_policy:: See Gem::Installer::new and Gem::Security. + # :wrappers:: See Gem::Installer::new + def initialize(options = {}) options = DEFAULT_OPTIONS.merge options - @env_shebang = options[:env_shebang] + + @bin_dir = options[:bin_dir] + @development = options[:development] @domain = options[:domain] + @env_shebang = options[:env_shebang] @force = options[:force] @format_executable = options[:format_executable] @ignore_dependencies = options[:ignore_dependencies] - @install_dir = options[:install_dir] || Gem.dir @security_policy = options[:security_policy] @wrappers = options[:wrappers] - @bin_dir = options[:bin_dir] @installed_gems = [] + + @install_dir = options[:install_dir] || Gem.dir + @cache_dir = options[:cache_dir] || @install_dir + + if options[:install_dir] then + spec_dir = File.join @install_dir, 'specifications' + @source_index = Gem::SourceIndex.from_gems_in spec_dir + else + @source_index = Gem.source_index + end end ## # Returns a list of pairs of gemspecs and source_uris that match # Gem::Dependency +dep+ from both local (Dir.pwd) and remote (Gem.sources) # sources. Gems are sorted with newer gems prefered over older gems, and - # local gems prefered over remote gems. + # local gems preferred over remote gems. + def find_gems_with_sources(dep) gems_and_sources = [] if @domain == :both or @domain == :local then Dir[File.join(Dir.pwd, "#{dep.name}-[0-9]*.gem")].each do |gem_file| @@ -72,12 +89,11 @@ end all = requirements.length > 1 || (requirements.first != ">=" and requirements.first != ">") - found = Gem::SourceInfoCache.search_with_source dep, true, all - + found = Gem::SpecFetcher.fetcher.fetch dep, all gems_and_sources.push(*found) rescue Gem::RemoteFetcher::FetchError => e if Gem.configuration.really_verbose then say "Error fetching remote data:\t\t#{e.message}" @@ -93,10 +109,11 @@ end ## # Gathers all dependencies necessary for the installation from local and # remote sources unless the ignore_dependencies was given. + def gather_dependencies specs = @specs_and_sources.map { |spec,_| spec } dependency_list = Gem::DependencyList.new dependency_list.add(*specs) @@ -108,26 +125,42 @@ until to_do.empty? do spec = to_do.shift next if spec.nil? or seen[spec.name] seen[spec.name] = true - spec.dependencies.each do |dep| - results = find_gems_with_sources(dep).reverse # local gems first + deps = spec.runtime_dependencies + deps |= spec.development_dependencies if @development + deps.each do |dep| + results = find_gems_with_sources(dep).reverse + + results.reject! do |dep_spec,| + to_do.push dep_spec + + @source_index.any? do |_, installed_spec| + dep.name == installed_spec.name and + dep.version_requirements.satisfied_by? installed_spec.version + end + end + results.each do |dep_spec, source_uri| next if seen[dep_spec.name] @specs_and_sources << [dep_spec, source_uri] dependency_list.add dep_spec - to_do.push dep_spec end end end end @gems_to_install = dependency_list.dependency_order.reverse end + ## + # Finds a spec and the source_uri it came from for gem +gem_name+ and + # +version+. Returns an Array of specs and sources required for + # installation of the gem. + 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 @@ -158,42 +191,43 @@ } end if spec_and_source.nil? then raise Gem::GemNotFoundException, - "could not find #{gem_name} locally or in a repository" + "could not find gem #{gem_name} locally or in a repository" end @specs_and_sources = [spec_and_source] end ## - # Installs the gem and all its dependencies. + # Installs the gem and all its dependencies. Returns an Array of installed + # gems specifications. + 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 + @installed_gems = [] + gather_dependencies - spec_dir = File.join @install_dir, 'specifications' - source_index = Gem::SourceIndex.from_gems_in spec_dir - @gems_to_install.each do |spec| last = spec == @gems_to_install.last # HACK is this test for full_name acceptable? - next if source_index.any? { |n,_| n == spec.full_name } and not last + 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 begin local_gem_path = Gem::RemoteFetcher.fetcher.download spec, source_uri, - @install_dir + @cache_dir rescue Gem::RemoteFetcher::FetchError next if @force raise end @@ -203,15 +237,18 @@ :format_executable => @format_executable, :ignore_dependencies => @ignore_dependencies, :install_dir => @install_dir, :security_policy => @security_policy, :wrappers => @wrappers, - :bin_dir => @bin_dir + :bin_dir => @bin_dir, + :development => @development spec = inst.install @installed_gems << spec end + + @installed_gems end end