summaryrefslogtreecommitdiff
path: root/lib/rubygems/commands/pristine_command.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rubygems/commands/pristine_command.rb')
-rw-r--r--lib/rubygems/commands/pristine_command.rb196
1 files changed, 120 insertions, 76 deletions
diff --git a/lib/rubygems/commands/pristine_command.rb b/lib/rubygems/commands/pristine_command.rb
index fafe35bec1..10978c2af7 100644
--- a/lib/rubygems/commands/pristine_command.rb
+++ b/lib/rubygems/commands/pristine_command.rb
@@ -1,51 +1,73 @@
# frozen_string_literal: true
-require 'rubygems/command'
-require 'rubygems/package'
-require 'rubygems/installer'
-require 'rubygems/version_option'
-class Gem::Commands::PristineCommand < Gem::Command
+require_relative "../command"
+require_relative "../package"
+require_relative "../installer"
+require_relative "../version_option"
+class Gem::Commands::PristineCommand < Gem::Command
include Gem::VersionOption
def initialize
- super 'pristine',
- 'Restores installed gems to pristine condition from files located in the gem cache',
- :version => Gem::Requirement.default,
- :extensions => true,
- :extensions_set => false,
- :all => false
-
- add_option('--all',
- 'Restore all installed gems to pristine',
- 'condition') do |value, options|
+ super "pristine",
+ "Restores installed gems to pristine condition from files located in the gem cache",
+ version: Gem::Requirement.default,
+ extensions: true,
+ extensions_set: false,
+ all: false
+
+ add_option("--all",
+ "Restore all installed gems to pristine",
+ "condition") do |value, options|
options[:all] = value
end
- add_option('--skip=gem_name',
- 'used on --all, skip if name == gem_name') do |value, options|
- options[:skip] = value
+ add_option("--skip=gem_name",
+ "used on --all, skip if name == gem_name") do |value, options|
+ options[:skip] ||= []
+ options[:skip] << value
end
- add_option('--[no-]extensions',
- 'Restore gems with extensions',
- 'in addition to regular gems') do |value, options|
+ add_option("--[no-]extensions",
+ "Restore gems with extensions",
+ "in addition to regular gems") do |value, options|
options[:extensions_set] = true
options[:extensions] = value
end
- add_option('--only-executables',
- 'Only restore executables') do |value, options|
+ add_option("--only-missing-extensions",
+ "Only restore gems with missing extensions") do |value, options|
+ options[:only_missing_extensions] = value
+ end
+
+ add_option("--only-executables",
+ "Only restore executables") do |value, options|
options[:only_executables] = value
end
- add_option('-E', '--[no-]env-shebang',
- 'Rewrite executables with a shebang',
- 'of /usr/bin/env') do |value, options|
+ add_option("--only-plugins",
+ "Only restore plugins") do |value, options|
+ options[:only_plugins] = value
+ end
+
+ add_option("-E", "--[no-]env-shebang",
+ "Rewrite executables with a shebang",
+ "of /usr/bin/env") do |value, options|
options[:env_shebang] = value
end
- add_version_option('restore to', 'pristine condition')
+ add_option("-i", "--install-dir DIR",
+ "Gem repository to get gems restored") do |value, options|
+ options[:install_dir] = File.expand_path(value)
+ end
+
+ add_option("-n", "--bindir DIR",
+ "Directory where executables are",
+ "located") do |value, options|
+ options[:bin_dir] = File.expand_path(value)
+ end
+
+ add_version_option("restore to", "pristine condition")
end
def arguments # :nodoc:
@@ -53,7 +75,7 @@ class Gem::Commands::PristineCommand < Gem::Command
end
def defaults_str # :nodoc:
- '--extensions'
+ "--extensions"
end
def description # :nodoc:
@@ -66,6 +88,10 @@ If you have made modifications to an installed gem, the pristine command
will revert them. All extensions are rebuilt and all bin stubs for the gem
are regenerated after checking for modifications.
+Rebuilding extensions also refreshes C-extension gems against updated system
+libraries (for example after OS or package upgrades) to avoid mismatches like
+outdated library version warnings.
+
If the cached gem cannot be found it will be downloaded.
If --no-extensions is provided pristine will not attempt to restore a gem
@@ -81,61 +107,73 @@ extensions will be restored.
end
def execute
- specs = if options[:all] then
- Gem::Specification.map
-
- # `--extensions` must be explicitly given to pristine only gems
- # with extensions.
- elsif options[:extensions_set] and
- options[:extensions] and options[:args].empty? then
- Gem::Specification.select do |spec|
- spec.extensions and not spec.extensions.empty?
- end
- else
- get_all_gem_names.sort.map do |gem_name|
- Gem::Specification.find_all_by_name(gem_name, options[:version]).reverse
- end.flatten
- end
-
- if specs.to_a.empty? then
- raise Gem::Exception,
- "Failed to find gems #{options[:args]} #{options[:version]}"
+ install_dir = options[:install_dir]
+
+ specification_record = install_dir ? Gem::SpecificationRecord.from_path(install_dir) : Gem::Specification.specification_record
+
+ specs = if options[:all]
+ specification_record.map
+
+ # `--extensions` must be explicitly given to pristine only gems
+ # with extensions.
+ elsif options[:extensions_set] &&
+ options[:extensions] && options[:args].empty?
+ specification_record.select do |spec|
+ spec.extensions && !spec.extensions.empty?
+ end
+ elsif options[:only_missing_extensions]
+ specification_record.select(&:missing_extensions?)
+ else
+ get_all_gem_names.sort.flat_map do |gem_name|
+ specification_record.find_all_by_name(gem_name, options[:version]).reverse
+ end
end
- install_dir = Gem.dir # TODO use installer option
+ specs = specs.select {|spec| spec.platform == RUBY_ENGINE || Gem::Platform.local === spec.platform || spec.platform == Gem::Platform::RUBY }
+
+ if specs.to_a.empty?
+ if options[:only_missing_extensions]
+ say "No gems with missing extensions to restore"
+ return
+ end
- raise Gem::FilePermissionError.new(install_dir) unless
- File.writable?(install_dir)
+ raise Gem::Exception,
+ "Failed to find gems #{options[:args]} #{options[:version]}"
+ end
say "Restoring gems to pristine condition..."
- specs.each do |spec|
- if spec.default_gem?
- say "Skipped #{spec.full_name}, it is a default gem"
- next
- end
+ specs.group_by(&:full_name_with_location).values.each do |grouped_specs|
+ spec = grouped_specs.find {|s| !s.default_gem? } || grouped_specs.first
- if spec.name == options[:skip]
- say "Skipped #{spec.full_name}, it was given through options"
- next
+ only_executables = options[:only_executables]
+ only_plugins = options[:only_plugins]
+
+ unless only_executables || only_plugins
+ # Default gemspecs include changes provided by ruby-core installer that
+ # can't currently be pristined (inclusion of compiled extension targets in
+ # the file list). So stick to resetting executables if it's a default gem.
+ only_executables = true if spec.default_gem?
end
- if spec.bundled_gem_in_old_ruby?
- say "Skipped #{spec.full_name}, it is bundled with old Ruby"
- next
+ if options.key? :skip
+ if options[:skip].include? spec.name
+ say "Skipped #{spec.full_name}, it was given through options"
+ next
+ end
end
- unless spec.extensions.empty? or options[:extensions] or options[:only_executables] then
- say "Skipped #{spec.full_name}, it needs to compile an extension"
+ unless spec.extensions.empty? || options[:extensions] || only_executables || only_plugins
+ say "Skipped #{spec.full_name_with_location}, it needs to compile an extension"
next
end
gem = spec.cache_file
- unless File.exist? gem or options[:only_executables] then
- require 'rubygems/remote_fetcher'
+ unless File.exist?(gem) || only_executables || only_plugins
+ require_relative "../remote_fetcher"
- say "Cached gem for #{spec.full_name} not found, attempting to fetch..."
+ say "Cached gem for #{spec.full_name_with_location} not found, attempting to fetch..."
dep = Gem::Dependency.new spec.name, spec.version
found, _ = Gem::SpecFetcher.fetcher.spec_for_dependency dep
@@ -150,30 +188,36 @@ extensions will be restored.
end
env_shebang =
- if options.include? :env_shebang then
+ if options.include? :env_shebang
options[:env_shebang]
else
- install_defaults = Gem::ConfigFile::PLATFORM_DEFAULTS['install']
- install_defaults.to_s['--env-shebang']
+ install_defaults = Gem::ConfigFile::PLATFORM_DEFAULTS["install"]
+ install_defaults.to_s["--env-shebang"]
end
+ bin_dir = options[:bin_dir] if options[:bin_dir]
+
installer_options = {
- :wrappers => true,
- :force => true,
- :install_dir => spec.base_dir,
- :env_shebang => env_shebang,
- :build_args => spec.build_args,
+ wrappers: true,
+ force: true,
+ install_dir: install_dir || spec.base_dir,
+ env_shebang: env_shebang,
+ build_args: spec.build_args,
+ bin_dir: bin_dir,
}
- if options[:only_executables] then
+ if only_executables
installer = Gem::Installer.for_spec(spec, installer_options)
installer.generate_bin
+ elsif only_plugins
+ installer = Gem::Installer.for_spec(spec, installer_options)
+ installer.generate_plugins
else
installer = Gem::Installer.at(gem, installer_options)
installer.install
end
- say "Restored #{spec.full_name}"
+ say "Restored #{spec.full_name_with_location}"
end
end
end