summaryrefslogtreecommitdiff
path: root/lib/rubygems/commands/install_command.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rubygems/commands/install_command.rb')
-rw-r--r--lib/rubygems/commands/install_command.rb268
1 files changed, 268 insertions, 0 deletions
diff --git a/lib/rubygems/commands/install_command.rb b/lib/rubygems/commands/install_command.rb
new file mode 100644
index 0000000000..6d3beec0b4
--- /dev/null
+++ b/lib/rubygems/commands/install_command.rb
@@ -0,0 +1,268 @@
+# frozen_string_literal: true
+
+require_relative "../command"
+require_relative "../install_update_options"
+require_relative "../dependency_installer"
+require_relative "../local_remote_options"
+require_relative "../validator"
+require_relative "../version_option"
+require_relative "../update_suggestion"
+
+##
+# Gem installer command line tool
+#
+# See `gem help install`
+
+class Gem::Commands::InstallCommand < Gem::Command
+ attr_reader :installed_specs # :nodoc:
+
+ include Gem::VersionOption
+ include Gem::LocalRemoteOptions
+ include Gem::InstallUpdateOptions
+ include Gem::UpdateSuggestion
+
+ def initialize
+ defaults = Gem::DependencyInstaller::DEFAULT_OPTIONS.merge({
+ format_executable: false,
+ lock: true,
+ suggest_alternate: true,
+ version: Gem::Requirement.default,
+ without_groups: [],
+ })
+
+ defaults.merge!(install_update_options)
+
+ super "install", "Install a gem into the local repository", defaults
+
+ add_install_update_options
+ add_local_remote_options
+ add_platform_option
+ add_version_option
+ add_prerelease_option "to be installed. (Only for listed gems)"
+
+ @installed_specs = []
+ end
+
+ def arguments # :nodoc:
+ "GEMNAME name of gem to install"
+ end
+
+ def defaults_str # :nodoc:
+ "--both --version '#{Gem::Requirement.default}' --no-force\n" \
+ "--install-dir #{Gem.dir} --lock\n" +
+ install_update_defaults_str
+ end
+
+ def description # :nodoc:
+ <<-EOF
+The install command installs local or remote gem into a gem repository.
+
+For gems with executables ruby installs a wrapper file into the executable
+directory by default. This can be overridden with the --no-wrappers option.
+The wrapper allows you to choose among alternate gem versions using _version_.
+
+For example `rake _0.7.3_ --version` will run rake version 0.7.3 if a newer
+version is also installed.
+
+Gem Dependency Files
+====================
+
+RubyGems can install a consistent set of gems across multiple environments
+using `gem install -g` when a gem dependencies file (gem.deps.rb, Gemfile or
+Isolate) is present. If no explicit file is given RubyGems attempts to find
+one in the current directory.
+
+When the RUBYGEMS_GEMDEPS environment variable is set to a gem dependencies
+file the gems from that file will be activated at startup time. Set it to a
+specific filename or to "-" to have RubyGems automatically discover the gem
+dependencies file by walking up from the current directory.
+
+NOTE: Enabling automatic discovery on multiuser systems can lead to
+execution of arbitrary code when used from directories outside your control.
+
+Extension Install Failures
+==========================
+
+If an extension fails to compile during gem installation the gem
+specification is not written out, but the gem remains unpacked in the
+repository. You may need to specify the path to the library's headers and
+libraries to continue. You can do this by adding a -- between RubyGems'
+options and the extension's build options:
+
+ $ gem install some_extension_gem
+ [build fails]
+ Gem files will remain installed in \\
+ /path/to/gems/some_extension_gem-1.0 for inspection.
+ Results logged to /path/to/gems/some_extension_gem-1.0/gem_make.out
+ $ gem install some_extension_gem -- --with-extension-lib=/path/to/lib
+ [build succeeds]
+ $ gem list some_extension_gem
+
+ *** LOCAL GEMS ***
+
+ some_extension_gem (1.0)
+ $
+
+If you correct the compilation errors by editing the gem files you will need
+to write the specification by hand. For example:
+
+ $ gem install some_extension_gem
+ [build fails]
+ Gem files will remain installed in \\
+ /path/to/gems/some_extension_gem-1.0 for inspection.
+ Results logged to /path/to/gems/some_extension_gem-1.0/gem_make.out
+ $ [cd /path/to/gems/some_extension_gem-1.0]
+ $ [edit files or what-have-you and run make]
+ $ gem spec ../../cache/some_extension_gem-1.0.gem --ruby > \\
+ ../../specifications/some_extension_gem-1.0.gemspec
+ $ gem list some_extension_gem
+
+ *** LOCAL GEMS ***
+
+ some_extension_gem (1.0)
+ $
+
+Command Alias
+==========================
+
+You can use `i` command instead of `install`.
+
+ $ gem i GEMNAME
+
+ EOF
+ end
+
+ def usage # :nodoc:
+ "#{program_name} [options] GEMNAME [GEMNAME ...] -- --build-flags"
+ end
+
+ def check_version # :nodoc:
+ if options[:version] != Gem::Requirement.default &&
+ get_all_gem_names.size > 1
+ alert_error "Can't use --version with multiple gems. You can specify multiple gems with" \
+ " version requirements using `gem install 'my_gem:1.0.0' 'my_other_gem:>=2'`"
+ terminate_interaction 1
+ end
+ end
+
+ def execute
+ if options.include? :gemdeps
+ install_from_gemdeps
+ return # not reached
+ end
+
+ @installed_specs = []
+
+ ENV.delete "GEM_PATH" if options[:install_dir].nil?
+
+ check_version
+
+ load_hooks
+
+ exit_code = install_gems
+
+ show_installed
+
+ say update_suggestion if eligible_for_update?
+
+ terminate_interaction exit_code
+ end
+
+ def install_from_gemdeps # :nodoc:
+ require_relative "../request_set"
+ rs = Gem::RequestSet.new
+
+ specs = rs.install_from_gemdeps options do |req, inst|
+ s = req.full_spec
+
+ if inst
+ say "Installing #{s.name} (#{s.version})"
+ else
+ say "Using #{s.name} (#{s.version})"
+ end
+ end
+
+ @installed_specs = specs
+
+ terminate_interaction
+ end
+
+ def install_gem(name, version) # :nodoc:
+ return if options[:conservative] &&
+ !Gem::Dependency.new(name, version).matching_specs.empty?
+
+ req = Gem::Requirement.create(version)
+
+ dinst = Gem::DependencyInstaller.new options
+
+ request_set = dinst.resolve_dependencies name, req
+
+ if options[:explain]
+ say "Gems to install:"
+
+ request_set.sorted_requests.each do |activation_request|
+ say " #{activation_request.full_name}"
+ end
+ else
+ @installed_specs.concat request_set.install options
+ end
+
+ show_install_errors dinst.errors
+ end
+
+ def install_gems # :nodoc:
+ exit_code = 0
+
+ get_all_gem_names_and_versions.each do |gem_name, gem_version|
+ gem_version ||= options[:version]
+ domain = options[:domain]
+ domain = :local unless options[:suggest_alternate]
+ suppress_suggestions = (domain == :local)
+
+ begin
+ install_gem gem_name, gem_version
+ rescue Gem::InstallError => e
+ alert_error "Error installing #{gem_name}:\n\t#{e.message}"
+ exit_code |= 1
+ rescue Gem::DependencyResolutionError => e
+ alert_error "Error installing #{gem_name}:\n\t#{e.message}"
+ exit_code |= 2
+ rescue Gem::UnsatisfiableDependencyError => e
+ show_lookup_failure e.name, e.version, e.errors, suppress_suggestions,
+ "'#{gem_name}' (#{gem_version})"
+
+ exit_code |= 2
+ end
+ end
+
+ exit_code
+ end
+
+ ##
+ # Loads post-install hooks
+
+ def load_hooks # :nodoc:
+ require_relative "../install_message"
+ require_relative "../rdoc"
+ end
+
+ def show_install_errors(errors) # :nodoc:
+ return unless errors
+
+ errors.each do |x|
+ next unless Gem::SourceFetchProblem === x
+
+ require_relative "../uri"
+ msg = "Unable to pull data from '#{Gem::Uri.redact(x.source.uri)}': #{x.error.message}"
+
+ alert_warning msg
+ end
+ end
+
+ def show_installed # :nodoc:
+ return if @installed_specs.empty?
+
+ gems = @installed_specs.length == 1 ? "gem" : "gems"
+ say "#{@installed_specs.length} #{gems} installed"
+ end
+end