1require 'rubygems/command'
2require 'rubygems/install_update_options'
3require 'rubygems/dependency_installer'
4require 'rubygems/local_remote_options'
5require 'rubygems/validator'
6require 'rubygems/version_option'
7require 'rubygems/install_message' # must come before rdoc for messaging
8require 'rubygems/rdoc'
9
10##
11# Gem installer command line tool
12#
13# See `gem help install`
14
15class Gem::Commands::InstallCommand < Gem::Command
16
17  attr_reader :installed_specs # :nodoc:
18
19  include Gem::VersionOption
20  include Gem::LocalRemoteOptions
21  include Gem::InstallUpdateOptions
22
23  def initialize
24    defaults = Gem::DependencyInstaller::DEFAULT_OPTIONS.merge({
25      :format_executable => false,
26      :version           => Gem::Requirement.default,
27    })
28
29    super 'install', 'Install a gem into the local repository', defaults
30
31    add_install_update_options
32    add_local_remote_options
33    add_platform_option
34    add_version_option
35    add_prerelease_option "to be installed. (Only for listed gems)"
36
37    add_option(:"Install/Update", '-g', '--file FILE',
38               'Read from a gem dependencies API file and',
39               'install the listed gems') do |v,o|
40      o[:gemdeps] = v
41    end
42
43    @installed_specs = nil
44  end
45
46  def arguments # :nodoc:
47    "GEMNAME       name of gem to install"
48  end
49
50  def defaults_str # :nodoc:
51    "--both --version '#{Gem::Requirement.default}' --document --no-force\n" +
52    "--install-dir #{Gem.dir}"
53  end
54
55  def description # :nodoc:
56    <<-EOF
57The install command installs local or remote gem into a gem repository.
58
59For gems with executables ruby installs a wrapper file into the executable
60directory by default.  This can be overridden with the --no-wrappers option.
61The wrapper allows you to choose among alternate gem versions using _version_.
62
63For example `rake _0.7.3_ --version` will run rake version 0.7.3 if a newer
64version is also installed.
65
66If an extension fails to compile during gem installation the gem
67specification is not written out, but the gem remains unpacked in the
68repository.  You may need to specify the path to the library's headers and
69libraries to continue.  You can do this by adding a -- between RubyGems'
70options and the extension's build options:
71
72  $ gem install some_extension_gem
73  [build fails]
74  Gem files will remain installed in \\
75  /path/to/gems/some_extension_gem-1.0 for inspection.
76  Results logged to /path/to/gems/some_extension_gem-1.0/gem_make.out
77  $ gem install some_extension_gem -- --with-extension-lib=/path/to/lib
78  [build succeeds]
79  $ gem list some_extension_gem
80
81  *** LOCAL GEMS ***
82
83  some_extension_gem (1.0)
84  $
85
86If you correct the compilation errors by editing the gem files you will need
87to write the specification by hand.  For example:
88
89  $ gem install some_extension_gem
90  [build fails]
91  Gem files will remain installed in \\
92  /path/to/gems/some_extension_gem-1.0 for inspection.
93  Results logged to /path/to/gems/some_extension_gem-1.0/gem_make.out
94  $ [cd /path/to/gems/some_extension_gem-1.0]
95  $ [edit files or what-have-you and run make]
96  $ gem spec ../../cache/some_extension_gem-1.0.gem --ruby > \\
97             ../../specifications/some_extension_gem-1.0.gemspec
98  $ gem list some_extension_gem
99
100  *** LOCAL GEMS ***
101
102  some_extension_gem (1.0)
103  $
104
105    EOF
106  end
107
108  def usage # :nodoc:
109    "#{program_name} GEMNAME [GEMNAME ...] [options] -- --build-flags"
110  end
111
112  def install_from_gemdeps(gf)
113    require 'rubygems/request_set'
114    rs = Gem::RequestSet.new
115    rs.load_gemdeps gf
116
117    rs.resolve
118
119    specs = rs.install options do |req, inst|
120      s = req.full_spec
121
122      if inst
123        say "Installing #{s.name} (#{s.version})"
124      else
125        say "Using #{s.name} (#{s.version})"
126      end
127    end
128
129    @installed_specs = specs
130
131    raise Gem::SystemExitException, 0
132  end
133
134  def execute
135    if gf = options[:gemdeps] then
136      install_from_gemdeps gf
137      return
138    end
139
140    @installed_specs = []
141
142    ENV.delete 'GEM_PATH' if options[:install_dir].nil? and RUBY_VERSION > '1.9'
143
144    if options[:install_dir] and options[:user_install]
145      alert_error "Use --install-dir or --user-install but not both"
146      terminate_interaction 1
147    end
148
149    exit_code = 0
150
151    if options[:version] != Gem::Requirement.default &&
152        get_all_gem_names.size > 1 then
153      alert_error "Can't use --version w/ multiple gems. Use name:ver instead."
154      terminate_interaction 1
155    end
156
157
158    get_all_gem_names_and_versions.each do |gem_name, gem_version|
159      gem_version ||= options[:version]
160
161      begin
162        next if options[:conservative] and
163          not Gem::Dependency.new(gem_name, gem_version).matching_specs.empty?
164
165        inst = Gem::DependencyInstaller.new options
166        inst.install gem_name, Gem::Requirement.create(gem_version)
167
168        @installed_specs.push(*inst.installed_gems)
169
170        next unless errs = inst.errors
171
172        errs.each do |x|
173          next unless Gem::SourceFetchProblem === x
174
175          msg = "Unable to pull data from '#{x.source.uri}': #{x.error.message}"
176
177          alert_warning msg
178        end
179      rescue Gem::InstallError => e
180        alert_error "Error installing #{gem_name}:\n\t#{e.message}"
181        exit_code |= 1
182      rescue Gem::GemNotFoundException => e
183        show_lookup_failure e.name, e.version, e.errors, options[:domain]
184
185        exit_code |= 2
186      end
187    end
188
189    unless @installed_specs.empty? then
190      gems = @installed_specs.length == 1 ? 'gem' : 'gems'
191      say "#{@installed_specs.length} #{gems} installed"
192    end
193
194    raise Gem::SystemExitException, exit_code
195  end
196
197end
198
199