2 # Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
4 # See LICENSE.txt for permissions.
11 require 'rubygems/format'
12 require 'rubygems/ext'
13 require 'rubygems/require_paths_builder'
16 # The installer class processes RubyGem .gem files and installs the
17 # files contained in the .gem into the Gem.path.
19 # Gem::Installer does the work of putting files in all the right places on the
20 # filesystem including unpacking the gem into its gem dir, installing the
21 # gemspec in the specifications dir, storing the cached gem in the cache dir,
22 # and installing either wrappers or symlinks for executables.
26 # Raised when there is an error while building extensions.
28 class ExtensionBuildError < Gem::InstallError; end
30 include Gem::UserInteraction
32 include Gem::RequirePathsBuilder
36 attr_writer :exec_format
38 # Defaults to use Ruby's program prefix and suffix.
40 @exec_format ||= Gem.default_exec_format
46 # Constructs an Installer instance that will install the gem located at
47 # +gem+. +options+ is a Hash with the following keys:
49 # :env_shebang:: Use /usr/bin/env in bin wrappers.
50 # :force:: Overrides all version checks and security policy checks, except
51 # for a signed-gems-only policy.
52 # :ignore_dependencies:: Don't raise if a dependency is missing.
53 # :install_dir:: The directory to install the gem into.
54 # :format_executable:: Format the executable the same as the ruby executable.
55 # If your ruby is ruby18, foo_exec will be installed as
57 # :security_policy:: Use the specified security policy. See Gem::Security
58 # :wrappers:: Install wrappers if true, symlinks if false.
60 def initialize(gem, options={})
65 :install_dir => Gem.dir,
66 :exec_format => false,
67 :env_shebang => false,
71 @env_shebang = options[:env_shebang]
72 @force = options[:force]
73 gem_home = options[:install_dir]
74 @gem_home = Pathname.new(gem_home).expand_path
75 @ignore_dependencies = options[:ignore_dependencies]
76 @format_executable = options[:format_executable]
77 @security_policy = options[:security_policy]
78 @wrappers = options[:wrappers]
79 @bin_dir = options[:bin_dir]
80 @development = options[:development]
83 @format = Gem::Format.from_file_by_path @gem, @security_policy
84 rescue Gem::Package::FormatError
85 raise Gem::InstallError, "invalid gem format for #{@gem}"
90 @gem_dir = File.join(@gem_home, "gems", @spec.full_name).untaint
94 # Installs the gem and returns a loaded Gem::Specification for the installed
97 # The gem will be installed with the following structure:
100 # cache/<gem-version>.gem #=> a cached copy of the installed gem
101 # gems/<gem-version>/... #=> extracted files
102 # specifications/<gem-version>.gemspec #=> the Gem::Specification
105 # If we're forcing the install then disable security unless the security
106 # policy says that we only install singed gems.
107 @security_policy = nil if @force and @security_policy and
108 not @security_policy.only_signed
111 if rrv = @spec.required_ruby_version then
112 unless rrv.satisfied_by? Gem.ruby_version then
113 raise Gem::InstallError, "#{@spec.name} requires Ruby version #{rrv}"
117 if rrgv = @spec.required_rubygems_version then
118 unless rrgv.satisfied_by? Gem::Version.new(Gem::RubyGemsVersion) then
119 raise Gem::InstallError,
120 "#{@spec.name} requires RubyGems version #{rrgv}"
124 unless @ignore_dependencies then
125 deps = @spec.runtime_dependencies
126 deps |= @spec.development_dependencies if @development
128 deps.each do |dep_gem|
129 ensure_dependency @spec, dep_gem
134 FileUtils.mkdir_p @gem_home unless File.directory? @gem_home
135 raise Gem::FilePermissionError, @gem_home unless File.writable? @gem_home
137 Gem.ensure_gem_subdirectories @gem_home
139 FileUtils.mkdir_p @gem_dir
146 write_require_paths_file_if_needed
148 # HACK remove? Isn't this done in multiple places?
149 cached_gem = File.join @gem_home, "cache", @gem.split(/\//).pop
150 unless File.exist? cached_gem then
151 FileUtils.cp @gem, File.join(@gem_home, "cache")
154 say @spec.post_install_message unless @spec.post_install_message.nil?
156 @spec.loaded_from = File.join(@gem_home, 'specifications',
157 "#{@spec.full_name}.gemspec")
159 Gem.source_index.add_spec @spec
162 rescue Zlib::GzipFile::Error
163 raise Gem::InstallError, "gzip error installing #{@gem}"
167 # Ensure that the dependency is satisfied by the current installation of
168 # gem. If it is not an exception is raised.
170 # spec :: Gem::Specification
171 # dependency :: Gem::Dependency
173 def ensure_dependency(spec, dependency)
174 unless installation_satisfies_dependency? dependency then
175 raise Gem::InstallError, "#{spec.name} requires #{dependency}"
182 # True if the gems in Gem.source_index satisfy +dependency+.
184 def installation_satisfies_dependency?(dependency)
185 Gem.source_index.find_name(dependency.name, dependency.version_requirements).size > 0
189 # Unpacks the gem into the given directory.
191 def unpack(directory)
193 @format = Gem::Format.from_file_by_path @gem, @security_policy
198 # Writes the .gemspec specification (in Ruby) to the supplied
201 # spec:: [Gem::Specification] The Gem specification to output
202 # spec_path:: [String] The location (path) to write the gemspec to
205 rubycode = @spec.to_ruby
207 file_name = File.join @gem_home, 'specifications',
208 "#{@spec.full_name}.gemspec"
211 File.open(file_name, "w") do |file|
217 # Creates windows .bat files for easy running of commands
219 def generate_windows_script(bindir, filename)
220 if Gem.win_platform? then
221 script_name = filename + ".bat"
222 script_path = File.join bindir, File.basename(script_name)
223 File.open script_path, 'w' do |file|
224 file.puts windows_stub_script(bindir, filename)
227 say script_path if Gem.configuration.really_verbose
232 return if @spec.executables.nil? or @spec.executables.empty?
234 # If the user has asked for the gem to be installed in a directory that is
235 # the system gem directory, then use the system bin directory, else create
236 # (or use) a new bin dir under the gem_home.
237 bindir = @bin_dir ? @bin_dir : Gem.bindir(@gem_home)
239 Dir.mkdir bindir unless File.exist? bindir
240 raise Gem::FilePermissionError.new(bindir) unless File.writable? bindir
242 @spec.executables.each do |filename|
244 bin_path = File.expand_path File.join(@gem_dir, @spec.bindir, filename)
245 mode = File.stat(bin_path).mode | 0111
246 File.chmod mode, bin_path
249 generate_bin_script filename, bindir
251 generate_bin_symlink filename, bindir
257 # Creates the scripts to run the applications in the gem.
259 # The Windows script is generated in addition to the regular one due to a
260 # bug or misfeature in the Windows shell's pipe. See
261 # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/193379
263 def generate_bin_script(filename, bindir)
264 bin_script_path = File.join bindir, formatted_program_filename(filename)
266 exec_path = File.join @gem_dir, @spec.bindir, filename
268 # HACK some gems don't have #! in their executables, restore 2008/06
269 #if File.read(exec_path, 2) == '#!' then
270 FileUtils.rm_f bin_script_path # prior install may have been --no-wrappers
272 File.open bin_script_path, 'w', 0755 do |file|
273 file.print app_script_text(filename)
276 say bin_script_path if Gem.configuration.really_verbose
278 generate_windows_script bindir, filename
280 # FileUtils.rm_f bin_script_path
281 # FileUtils.cp exec_path, bin_script_path,
282 # :verbose => Gem.configuration.really_verbose
287 # Creates the symlinks to run the applications in the gem. Moves
288 # the symlink if the gem being installed has a newer version.
290 def generate_bin_symlink(filename, bindir)
291 if Gem.win_platform? then
292 alert_warning "Unable to use symlinks on Windows, installing wrapper"
293 generate_bin_script filename, bindir
297 src = File.join @gem_dir, 'bin', filename
298 dst = File.join bindir, formatted_program_filename(filename)
300 if File.exist? dst then
301 if File.symlink? dst then
302 link = File.readlink(dst).split File::SEPARATOR
303 cur_version = Gem::Version.create(link[-3].sub(/^.*-/, ''))
304 return if @spec.version < cur_version
309 FileUtils.symlink src, dst, :verbose => Gem.configuration.really_verbose
313 # Generates a #! line for +bin_file_name+'s wrapper copying arguments if
316 def shebang(bin_file_name)
318 "#!/usr/bin/env " + Gem::ConfigMap[:ruby_install_name]
320 path = File.join @gem_dir, @spec.bindir, bin_file_name
322 File.open(path, "rb") do |file|
323 first_line = file.gets
324 if first_line =~ /^#!/ then
325 # Preserve extra words on shebang line, like "-w". Thanks RPA.
326 shebang = first_line.sub(/\A\#!.*?ruby\S*/, "#!#{Gem.ruby}")
328 # Create a plain shebang line.
329 shebang = "#!#{Gem.ruby}"
332 shebang.strip # Avoid nasty ^M issues.
338 # Return the text for an application file.
340 def app_script_text(bin_file_name)
342 #{shebang bin_file_name}
344 # This file was generated by RubyGems.
346 # The application '#{@spec.name}' is installed as part of a gem, and
347 # this file is here to facilitate running it.
352 version = "#{Gem::Requirement.default}"
354 if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
359 gem '#{@spec.name}', version
360 load '#{bin_file_name}'
365 # return the stub script text used to launch the true ruby script
367 def windows_stub_script(bindir, bin_file_name)
370 IF NOT "%~f0" == "~f0" GOTO :WinNT
371 @"#{File.basename(Gem.ruby)}" "#{File.join(bindir, bin_file_name)}" %1 %2 %3 %4 %5 %6 %7 %8 %9
374 @"#{File.basename(Gem.ruby)}" "%~dpn0" %*
379 # Builds extensions. Valid types of extensions are extconf.rb files,
380 # configure scripts and rakefiles or mkrf_conf files.
383 return if @spec.extensions.empty?
384 say "Building native extensions. This could take a while..."
386 dest_path = File.join @gem_dir, @spec.require_paths.first
387 ran_rake = false # only run rake once
389 @spec.extensions.each do |extension|
393 builder = case extension
395 Gem::Ext::ExtConfBuilder
396 when /configure/ then
397 Gem::Ext::ConfigureBuilder
398 when /rakefile/i, /mkrf_conf/i then
400 Gem::Ext::RakeBuilder
402 results = ["No builder for extension '#{extension}'"]
407 Dir.chdir File.join(@gem_dir, File.dirname(extension))
408 results = builder.build(extension, @gem_dir, dest_path, results)
410 say results.join("\n") if Gem.configuration.really_verbose
413 results = results.join "\n"
415 File.open('gem_make.out', 'wb') { |f| f.puts results }
418 ERROR: Failed to build gem native extension.
422 Gem files will remain installed in #{@gem_dir} for inspection.
423 Results logged to #{File.join(Dir.pwd, 'gem_make.out')}
426 raise ExtensionBuildError, message
434 # Reads the file index and extracts each file into the gem directory.
436 # Ensures that files can't be installed outside the gem directory.
439 expand_and_validate_gem_dir
441 raise ArgumentError, "format required to extract from" if @format.nil?
443 @format.file_entries.each do |entry, file_data|
444 path = entry['path'].untaint
446 if path =~ /\A\// then # for extra sanity
447 raise Gem::InstallError,
448 "attempt to install file into #{entry['path'].inspect}"
451 path = File.expand_path File.join(@gem_dir, path)
453 if path !~ /\A#{Regexp.escape @gem_dir}/ then
454 msg = "attempt to install file into %p under %p" %
455 [entry['path'], @gem_dir]
456 raise Gem::InstallError, msg
459 FileUtils.mkdir_p File.dirname(path)
461 File.open(path, "wb") do |out|
465 FileUtils.chmod entry['mode'], path
467 say path if Gem.configuration.really_verbose
472 # Prefix and suffix the program filename the same as ruby.
474 def formatted_program_filename(filename)
475 if @format_executable then
476 self.class.exec_format % File.basename(filename)
485 # HACK Pathname is broken on windows.
487 def absolute_path? pathname
488 pathname.absolute? or (Gem.win_platform? and pathname.to_s =~ /\A[a-z]:/i)
491 def expand_and_validate_gem_dir
492 @gem_dir = Pathname.new(@gem_dir).expand_path
494 unless absolute_path?(@gem_dir) then # HACK is this possible after #expand_path?
495 raise ArgumentError, "install directory %p not absolute" % @gem_dir
498 @gem_dir = @gem_dir.to_s