class Gem::Installer
The installer installs the files contained in the .gem into the Gem.home.
Gem::Installer does the work of putting files in all the right places on the filesystem including unpacking the gem into its gem dir, installing the gemspec in the specifications dir, storing the cached gem in the cache dir, and installing either wrappers or symlinks for executables.
The installer invokes pre and post install hooks. Hooks can be added either through a rubygems_plugin.rb file in an installed gem or via a rubygems/defaults/#{RUBY_ENGINE}.rb or rubygems/defaults/operating_system.rb file. SeeGem.pre_install andGem.post_install for details.
Constants
- ENV_PATHS
Paths where env(1) might live. Some systems are broken and have it in /bin
Attributes
Overrides the executable format.
This is a sprintf format with a “%s” which will be replaced with the executable name. It is based off the ruby executable name’s difference from “ruby”.
The directory a gem’s executables will be installed into
The gem repository the gem will be installed into
The options passed when theGem::Installer was instantiated.
The gem package instance.
Public Class Methods
Source
# File lib/rubygems/installer.rb, line 88defself.at(path,options = {})security_policy =options[:security_policy]package =Gem::Package.newpath,security_policynewpackage,optionsend
Construct an installer object for the gem file located atpath
Source
# File lib/rubygems/installer.rb, line 80defexec_format@exec_format||=Gem.default_exec_formatend
Defaults to use Ruby’s program prefix and suffix.
Source
# File lib/rubygems/installer.rb, line 126defself.for_spec(spec,options = {})# FIXME: we should have a real Package class for thisnewFakePackage.new(spec),optionsend
Construct an installer object for an ephemeral gem (one where we don’t actually have a .gem file, just a spec)
Source
# File lib/rubygems/installer.rb, line 156definitialize(package,options = {})require"fileutils"@options =options@package =packageprocess_options@package.dir_mode =options[:dir_mode]@package.prog_mode =options[:prog_mode]@package.data_mode =options[:data_mode]end
Constructs anInstaller instance that will install the gem atpackage which can either be a path or an instance ofGem::Package.options is aHash with the following keys:
- :bin_dir
Where to put a bin wrapper if needed.
- :development
Whether or not development dependencies should be installed.
- :env_shebang
Use /usr/bin/env in bin wrappers.
- :force
Overrides all version checks and security policy checks, except for a signed-gems-only policy.
- :format_executable
Format the executable the same as the Ruby executable. If your Ruby is ruby18, foo_exec will be installed as foo_exec18.
- :ignore_dependencies
Don’t raise if a dependency is missing.
- :install_dir
The directory to install the gem into.
- :security_policy
Use the specified security policy. See
Gem::Security- :user_install
Indicate that the gem should be unpacked into the users personal gem directory.
- :only_install_dir
Only validate dependencies against what is in the install_dir
- :wrappers
Install wrappers if true, symlinks if false.
- :build_args
An
Arrayof arguments to pass to the extension builder process. If not set, thenGem::Command.build_argsis used- :post_install_message
Print gem post install message if true
Public Instance Methods
Source
# File lib/rubygems/installer.rb, line 726defapp_script_text(bin_file_name)# NOTE: that the `load` lines cannot be indented, as old RG versions match# against the beginning of the line<<~TEXT #{shebang bin_file_name} # # This file was generated by RubyGems. # # The application '#{spec.name}' is installed as part of a gem, and # this file is here to facilitate running it. # require 'rubygems' #{gemdeps_load(spec.name)} version = "#{Gem::Requirement.default_prerelease}" str = ARGV.first if str str = str.b[/\\A_(.*)_\\z/, 1] if str and Gem::Version.correct?(str) #{explicit_version_requirement(spec.name)} ARGV.shift end end if Gem.respond_to?(:activate_and_load_bin_path) Gem.activate_and_load_bin_path('#{spec.name}', '#{bin_file_name}', version) else load Gem.activate_bin_path('#{spec.name}', '#{bin_file_name}', version) end TEXTend
Return the text for an application file.
Source
# File lib/rubygems/installer.rb, line 817defbuild_extensionsbuilder =Gem::Ext::Builder.newspec,build_args,Gem.target_rbconfigbuilder.build_extensionsend
Builds extensions. Valid types of extensions are extconf.rb files, configure scripts and rakefiles or mkrf_conf files.
Source
# File lib/rubygems/installer.rb, line 401defdefault_spec_dirdir =File.join(gem_home,"specifications","default")FileUtils.mkdir_pdirdirend
Source
# File lib/rubygems/installer.rb, line 411defdefault_spec_fileFile.joindefault_spec_dir,"#{spec.full_name}.gemspec"end
The location of the default spec file for default gems.
Source
# File lib/rubygems/installer.rb, line 858defdirgem_dir.to_send
Return the target directory where the gem is to be installed. This directory is not guaranteed to be populated.
Source
# File lib/rubygems/installer.rb, line 367defensure_dependency(spec,dependency)unlessinstallation_satisfies_dependency?dependencyraiseGem::InstallError,"#{spec.name} requires #{dependency}"endtrueend
Ensure that the dependency is satisfied by the current installation of gem. If it is not an exception is raised.
- spec
- dependency
Source
# File lib/rubygems/installer.rb, line 607defensure_loadable_specruby =spec.to_ruby_for_cachebeginevalrubyrescueStandardError,SyntaxError=>eraiseGem::InstallError,"The specification for #{spec.full_name} is corrupt (#{e.class})"endend
Ensures theGem::Specification written out for this gem is loadable upon installation.
Source
# File lib/rubygems/installer.rb, line 768defexplicit_version_requirement(name)code ="version = str"returncodeunlessname=="bundler"code+=<<~TEXT ENV['BUNDLER_VERSION'] = str TEXTend
Source
# File lib/rubygems/installer.rb, line 837defextract_bin@package.extract_filesgem_dir,"#{spec.bindir}/*"end
Extracts only the bin/ files from the gem into the gem directory. This is used by default gems to allow a gem-aware stub to function without the full gem installed.
Source
# File lib/rubygems/installer.rb, line 828defextract_files@package.extract_filesgem_dirend
Reads the file index and extracts each file into the gem directory.
Ensures that files can’t be installed outside the gem directory.
Source
# File lib/rubygems/installer.rb, line 844defformatted_program_filename(filename)if@format_executableself.class.exec_format%File.basename(filename)elsefilenameendend
Prefix and suffix the program filename the same as ruby.
Source
# File lib/rubygems/installer.rb, line 865defgem@package.gem.pathend
Filename of the gem being installed.
Source
# File lib/rubygems/installer.rb, line 249defgem_dir@gem_dir||=File.join(gem_home,"gems",spec.full_name)end
Lazy accessor for the spec’s gem directory.
Source
# File lib/rubygems/installer.rb, line 759defgemdeps_load(name)return""ifname=="bundler"<<~TEXT Gem.use_gemdeps TEXTend
Source
# File lib/rubygems/installer.rb, line 509defgenerate_bin_script(filename,bindir)bin_script_path =File.joinbindir,formatted_program_filename(filename)Gem.open_file_with_lock(bin_script_path)dorequire"fileutils"FileUtils.rm_fbin_script_path# prior install may have been --no-wrappersFile.open(bin_script_path,"wb",0o755)do|file|file.writeapp_script_text(filename)file.chmod(options[:prog_mode]||0o755)endendverbosebin_script_pathgenerate_windows_scriptfilename,bindirend
Creates the scripts to run the applications in the gem.
Source
# File lib/rubygems/installer.rb, line 531defgenerate_bin_symlink(filename,bindir)src =File.joingem_dir,spec.bindir,filenamedst =File.joinbindir,formatted_program_filename(filename)ifFile.exist?dstifFile.symlink?dstlink =File.readlink(dst).splitFile::SEPARATORcur_version =Gem::Version.create(link[-3].sub(/^.*-/,""))returnifspec.version<cur_versionendFile.unlinkdstendFileUtils.symlinksrc,dst,verbose:Gem.configuration.really_verboserescueNotImplementedError,SystemCallErroralert_warning"Unable to use symlinks, installing wrapper"generate_bin_scriptfilename,bindirend
Creates the symlinks to run the applications in the gem. Moves the symlink if the gem being installed has a newer version.
Source
# File lib/rubygems/installer.rb, line 439defgenerate_windows_script(filename,bindir)ifGem.win_platform?script_name =formatted_program_filename(filename)+".bat"script_path =File.joinbindir,File.basename(script_name)File.openscript_path,"w"do|file|file.putswindows_stub_script(bindir,filename)endverbosescript_pathendend
Creates windows .bat files for easy running of commands
Source
# File lib/rubygems/installer.rb, line 271definstallpre_install_checksrun_pre_install_hooks# Set loaded_from to ensure extension_dir is correctspec.loaded_from =spec_file# Completely remove any previous gem filesFileUtils.rm_rfgem_dirFileUtils.rm_rfspec.extension_dirdir_mode =options[:dir_mode]FileUtils.mkdir_pgem_dir,mode:dir_mode&&0o755extract_filesbuild_extensionswrite_build_info_filerun_post_build_hooksgenerate_bingenerate_pluginswrite_specwrite_cache_fileFile.chmod(dir_mode,gem_dir)ifdir_modesayspec.post_install_messageifoptions[:post_install_message]&&!spec.post_install_message.nil?Gem::Specification.add_spec(spec)unless@install_dirload_pluginrun_post_install_hooksspecrescueErrno::EACCES=>e# Permission denied - /path/to/fooraiseGem::FilePermissionError,e.message.split(" - ").lastend
Installs the gem and returns a loadedGem::Specification for the installed gem.
The gem will be installed with the following structure:
@gem_home/ cache/<gem-version>.gem #=> a cached copy of the installed gem gems/<gem-version>/... #=> extracted files specifications/<gem-version>.gemspec #=> the Gem::Specification
Source
# File lib/rubygems/installer.rb, line 377definstallation_satisfies_dependency?(dependency)returntrueif@options[:development]&&dependency.type==:developmentreturntrueifinstalled_specs.detect {|s|dependency.matches_spec?s }returnfalseif@only_install_dir!dependency.matching_specs.empty?end
True if the gems in the system satisfydependency.
Source
# File lib/rubygems/installer.rb, line 347definstalled_specs@installed_specs||=beginspecs = []Gem::Util.glob_files_in_dir("*.gemspec",File.join(gem_home,"specifications")).eachdo|path|spec =Gem::Specification.loadpathspecs<<specifspecendspecsendend
Return anArray of Specifications contained within thegem_home we’ll be installing into.
Source
# File lib/rubygems/installer.rb, line 878defpre_install_checksverify_gem_home# The name and require_paths must be verified first, since it could contain# ruby code that would be eval'ed in #ensure_loadable_specverify_specensure_loadable_specGem.ensure_gem_subdirectoriesgem_homereturntrueif@forceensure_dependencies_metunless@ignore_dependenciestrueend
Performs various checks before installing the gem such as the install repository is writable and its directories exist, required Ruby and rubygems versions are met and that dependencies are installed.
Version and dependency checks are skipped if this install is forced.
The dependent check will be skipped if the install is ignoring dependencies.
Source
# File lib/rubygems/installer.rb, line 565defshebang(bin_file_name)path =File.joingem_dir,spec.bindir,bin_file_namefirst_line =File.open(path,"rb",&:gets)||""iffirst_line.start_with?("#!")# Preserve extra words on shebang line, like "-w". Thanks RPA.shebang =first_line.sub(/\A\#!.*?ruby\S*((\s+\S+)+)/,"#!#{Gem.ruby}")opts =$1shebang.strip!# Avoid nasty ^M issues.endifwhich =Gem.configuration[:custom_shebang]# replace bin_file_name with "ruby" to avoid endless loopswhich =which.gsub(/ #{bin_file_name}$/," #{ruby_install_name}")which =which.gsub(/\$(\w+)/)docase$1when"env"@env_path||=ENV_PATHS.find {|env_path|File.executable?env_path }when"ruby""#{Gem.ruby}#{opts}"when"exec"bin_file_namewhen"name"spec.nameendend"#!#{which}"elsif@env_shebang# Create a plain shebang line.@env_path||=ENV_PATHS.find {|env_path|File.executable?env_path }"#!#{@env_path} #{ruby_install_name}"else"#{bash_prolog_script}#!#{Gem.ruby}#{opts}"endend
Generates a! line forbin_file_name‘s wrapper copying arguments if necessary.
If the :custom_shebang config is set, then it is used as a template for how to create the shebang used for to run a gem’s executables.
The template supports 4 expansions:
$env the path to the unix env utility$ruby the path to the currently running ruby interpreter$exec the path to the gem's executable$name the name of the gem the executable is for
Source
# File lib/rubygems/installer.rb, line 256defspec@package.specend
Lazy accessor for the installer’s spec.
Source
# File lib/rubygems/installer.rb, line 397defspec_fileFile.joingem_home,"specifications","#{spec.full_name}.gemspec"end
The location of the spec file that is installed.
Source
# File lib/rubygems/installer.rb, line 387defunpack(directory)@gem_dir =directoryextract_filesend
Unpacks the gem into the given directory.
Source
# File lib/rubygems/installer.rb, line 693defverify_specunlessGem::Specification::VALID_NAME_PATTERN.match?(spec.name)raiseGem::InstallError,"#{spec} has an invalid name"endifspec.raw_require_paths.any? {|path|path=~/\R/ }raiseGem::InstallError,"#{spec} has an invalid require_paths"endifspec.extensions.any? {|ext|ext=~/\R/ }raiseGem::InstallError,"#{spec} has an invalid extensions"endif/\R/.match?(spec.platform.to_s)raiseGem::InstallError,"#{spec.platform} is an invalid platform"endunless/\A\d+\z/.match?(spec.specification_version.to_s)raiseGem::InstallError,"#{spec} has an invalid specification_version"endifspec.dependencies.any? {|dep|dep.type!=:runtime&&dep.type!=:development }raiseGem::InstallError,"#{spec} has an invalid dependencies"endifspec.dependencies.any? {|dep|dep.name=~/(?:\R|[<>])/ }raiseGem::InstallError,"#{spec} has an invalid dependencies"endend
Source
# File lib/rubygems/installer.rb, line 781defwindows_stub_script(bindir,bin_file_name)rb_topdir =RbConfig::TOPDIR||File.dirname(rb_config["bindir"])# get ruby executable file name from RbConfigruby_exe ="#{rb_config["RUBY_INSTALL_NAME"]}#{rb_config["EXEEXT"]}"ruby_exe ="ruby.exe"ifruby_exe.empty?ifFile.exist?(File.join(bindir,ruby_exe))# stub & ruby.exe within same folder. Portable<<~TEXT @ECHO OFF @"%~dp0#{ruby_exe}" "%~dpn0" %* TEXTelsifbindir.downcase.start_with?rb_topdir.downcase# stub within ruby folder, but not standard bin. Portablerequire"pathname"from =Pathname.newbindirto =Pathname.new"#{rb_topdir}/bin"rel =to.relative_path_fromfrom<<~TEXT @ECHO OFF @"%~dp0#{rel}/#{ruby_exe}" "%~dpn0" %* TEXTelse# outside ruby folder, maybe -user-install or bundler. Portable, but ruby# is dependent on PATH<<~TEXT @ECHO OFF @#{ruby_exe} "%~dpn0" %* TEXTendend
return the stub script text used to launch the true Ruby script
Source
# File lib/rubygems/installer.rb, line 900defwrite_build_info_filereturnifbuild_args.empty?build_info_dir =File.joingem_home,"build_info"dir_mode =options[:dir_mode]FileUtils.mkdir_pbuild_info_dir,mode:dir_mode&&0o755build_info_file =File.joinbuild_info_dir,"#{spec.full_name}.info"File.openbuild_info_file,"w"do|io|build_args.eachdo|arg|io.putsargendendFile.chmod(dir_mode,build_info_dir)ifdir_modeend
Writes the file containing the arguments for building this gem’s extensions.
Source
# File lib/rubygems/installer.rb, line 922defwrite_cache_filecache_file =File.joingem_home,"cache",spec.file_name@package.copy_tocache_fileend
Writes the .gem file to the cache directory
Source
# File lib/rubygems/installer.rb, line 432defwrite_default_specGem.write_binary(default_spec_file,spec.to_ruby)end
Writes the full .gemspec specification (in Ruby) to the gem home’s specifications/default directory.
In contrast towrite_spec, this keeps file lists, so the ‘gem contents` command works.
Source
# File lib/rubygems/installer.rb, line 419defwrite_specspec.installed_by_version =Gem.rubygems_versionGem.write_binary(spec_file,spec.to_ruby_for_cache)end
Writes the .gemspec specification (in Ruby) to the gem home’s specifications directory.
Private Instance Methods
Source
# File lib/rubygems/installer.rb, line 968defbash_prolog_scriptifload_relative_enabled?<<~EOS #!/bin/sh # -*- ruby -*- _=_\\ =begin bindir="${0%/*}" ruby="$bindir/#{ruby_install_name}" if [ ! -f "$ruby" ]; then ruby="#{ruby_install_name}" fi exec "$ruby" "-x" "$0" "$@" =end EOSelse""endend
Source
# File lib/rubygems/installer.rb, line 949defbuild_args@build_args||=beginrequire_relative"command"Gem::Command.build_argsendend
Source
# File lib/rubygems/installer.rb, line 988defload_pluginspecs =Gem::Specification.find_all_by_name(spec.name)# If old version already exists, this plugin isn't loaded# immediately. It's for avoiding a case that multiple versions# are loaded at the same time.returnunlessspecs.size==1plugin_files =spec.plugins.mapdo|plugin|File.join(@plugins_dir,"#{spec.name}_plugin#{File.extname(plugin)}")endGem.load_plugin_files(plugin_files)end
Source
# File lib/rubygems/installer.rb, line 964defload_relative_enabled?rb_config["LIBRUBY_RELATIVE"]=="yes"end
Source
# File lib/rubygems/installer.rb, line 960defruby_install_namerb_config["ruby_install_name"]end
Source
# File lib/rubygems/installer.rb, line 936defuser_install_dir# never install to user home in --build-root modereturnunless@build_root.nil?# Please note that @user_install might have three states:# * `true`: `--user-install`# * `false`: `--no-user-install` and# * `nil`: option was not specifiedif@user_install|| (@user_install.nil?&&Gem.default_user_install)Gem.user_direndend