Class: Gem::RemoteInstaller

Inherits:
Object
  • Object
show all
Includes:
UserInteraction
Defined in:
lib/rubygems/remote_installer.rb

Instance Method Summary collapse

Methods included from DefaultUserInteraction

#ui, ui, #ui=, ui=, #use_ui, use_ui

Constructor Details

#initialize(options = {}) ⇒ RemoteInstaller

options[:http_proxy]
  • [String]: explicit specification of proxy; overrides any environment variable setting

  • nil: respect environment variables (HTTP_PROXY, HTTP_PROXY_USER, HTTP_PROXY_PASS)

  • :no_proxy: ignore environment variables and _don’t_ use a proxy

  • :cache_dir: override where downloaded gems are cached.



34
35
36
37
# File 'lib/rubygems/remote_installer.rb', line 34

def initialize(options={})
  @options = options
  @source_index_hash = nil
end

Instance Method Details

#download_gem(destination_file, source, spec) ⇒ Object



183
184
185
186
187
188
# File 'lib/rubygems/remote_installer.rb', line 183

def download_gem(destination_file, source, spec)
  return if File.exist? destination_file
  uri = source + "/gems/#{spec.full_name}.gem"
  response = Gem::RemoteFetcher.fetcher.fetch_path uri
  write_gem_to_file response, destination_file
end

#find_dependencies_not_installed(dependencies) ⇒ Object



148
149
150
151
152
153
154
155
156
# File 'lib/rubygems/remote_installer.rb', line 148

def find_dependencies_not_installed(dependencies)
  to_install = []
  dependencies.each do |dependency|
    srcindex = Gem::SourceIndex.from_installed_gems
    matches = srcindex.find_name(dependency.name, dependency.requirement_list)
    to_install.push dependency if matches.empty?
  end
  to_install
end

#find_gem_to_install(gem_name, version_requirement) ⇒ Object

Find a gem to be installed by interacting with the user.



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/rubygems/remote_installer.rb', line 113

def find_gem_to_install(gem_name, version_requirement)
  specs_n_sources = specs_n_sources_matching gem_name, version_requirement

  top_3_versions = specs_n_sources.map{|gs| gs.first.version}.uniq[0..3]
  specs_n_sources.reject!{|gs| !top_3_versions.include?(gs.first.version)}

  binary_gems = specs_n_sources.reject { |item|
    item[0].platform.nil? || item[0].platform==Platform::RUBY
  }

  # only non-binary gems...return latest
  return specs_n_sources.first if binary_gems.empty?

  list = specs_n_sources.collect { |spec, source_uri|
    "#{spec.name} #{spec.version} (#{spec.platform})"
  }

  list << "Skip this gem"
  list << "Cancel installation"

  string, index = choose_from_list(
    "Select which gem to install for your platform (#{RUBY_PLATFORM})",
    list)

  if index.nil? or index == (list.size - 1) then
    raise RemoteInstallationCancelled, "Installation of #{gem_name} cancelled."
  end

  if index == (list.size - 2) then
    raise RemoteInstallationSkipped, "Installation of #{gem_name} skipped."
  end

  specs_n_sources[index]
end

#install(gem_name, version_requirement = "> 0.0.0", force = false, install_dir = Gem.dir, install_stub = true) ⇒ Object

This method will install package_name onto the local system.

gem_name
String

Name of the Gem to install

version_requirement
default = “> 0.0.0”

Gem version requirement to install

Returns

an array of Gem::Specification objects, one for each gem installed.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/rubygems/remote_installer.rb', line 50

def install(gem_name, version_requirement = "> 0.0.0", force=false,
            install_dir=Gem.dir, install_stub=true)
  unless version_requirement.respond_to?(:satisfied_by?)
    version_requirement = Version::Requirement.new [version_requirement]
  end
  installed_gems = []
  begin
    spec, source = find_gem_to_install(gem_name, version_requirement)
    dependencies = find_dependencies_not_installed(spec.dependencies)

    installed_gems << install_dependencies(dependencies, force, install_dir)

    cache_dir = @options[:cache_dir] || File.join(install_dir, "cache")
    destination_file = File.join(cache_dir, spec.full_name + ".gem")

    download_gem(destination_file, source, spec)

    installer = new_installer(destination_file)
    installed_gems.unshift installer.install(force, install_dir, install_stub)
  rescue RemoteInstallationSkipped => e
    puts e.message
  end
  installed_gems.flatten
end

#install_dependencies(dependencies, force, install_dir) ⇒ Object

Install all the given dependencies. Returns an array of Gem::Specification objects, one for each dependency installed.

TODO: For now, we recursively install, but this is not the right way to do things (e.g. if a package fails to download, we shouldn’t install anything).



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/rubygems/remote_installer.rb', line 164

def install_dependencies(dependencies, force, install_dir)
  return if @options[:ignore_dependencies]
  installed_gems = []
  dependencies.each do |dep|
    if @options[:include_dependencies] ||
       ask_yes_no("Install required dependency #{dep.name}?", true)
      remote_installer = RemoteInstaller.new @options
      installed_gems << remote_installer.install(dep.name,
                                                 dep.version_requirements,
                                                 force, install_dir)
    elsif force then
      # ignore
    else
      raise DependencyError, "Required dependency #{dep.name} not installed"
    end
  end
  installed_gems
end

#new_installer(gem) ⇒ Object



197
198
199
# File 'lib/rubygems/remote_installer.rb', line 197

def new_installer(gem)
  return Installer.new(gem, @options)
end

#source_index_hashObject

Return a hash mapping the available source names to the source index of that source.



77
78
79
80
81
82
83
84
# File 'lib/rubygems/remote_installer.rb', line 77

def source_index_hash
  return @source_index_hash if @source_index_hash
  @source_index_hash = {}
  Gem::SourceInfoCache.cache_data.each do |source_uri, sic_entry|
    @source_index_hash[source_uri] = sic_entry.source_index
  end
  @source_index_hash
end

#specs_n_sources_matching(gem_name, version_requirement) ⇒ Object

Finds the Gem::Specification objects and the corresponding source URI for gems matching gem_name and version_requirement



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/rubygems/remote_installer.rb', line 88

def specs_n_sources_matching(gem_name, version_requirement)
  specs_n_sources = []

  source_index_hash.each do |source_uri, source_index|
    specs = source_index.search(/^#{Regexp.escape gem_name}$/i,
                                version_requirement)
    # TODO move to SourceIndex#search?
    ruby_version = Gem::Version.new RUBY_VERSION
    specs = specs.select do |spec|
      spec.required_ruby_version.nil? or
        spec.required_ruby_version.satisfied_by? ruby_version
    end
    specs.each { |spec| specs_n_sources << [spec, source_uri] }
  end

  if specs_n_sources.empty? then
    raise GemNotFoundException, "Could not find #{gem_name} (#{version_requirement}) in any repository"
  end

  specs_n_sources = specs_n_sources.sort_by { |gs,| gs.version }.reverse

  specs_n_sources
end

#write_gem_to_file(body, destination_file) ⇒ Object



190
191
192
193
194
195
# File 'lib/rubygems/remote_installer.rb', line 190

def write_gem_to_file(body, destination_file)
  FileUtils.mkdir_p(File.dirname(destination_file)) unless File.exist?(destination_file)
  File.open(destination_file, 'wb') do |out|
    out.write(body)
  end
end