# frozen_string_literal: truerequire_relative"../command"require_relative"../package"require_relative"../installer"require_relative"../version_option"classGem::Commands::PristineCommand<Gem::CommandincludeGem::VersionOptiondefinitializesuper"pristine","Restores installed gems to pristine condition from files located in the gem cache",version: Gem::Requirement.default,extensions: true,extensions_set: false,all: falseadd_option("--all","Restore all installed gems to pristine","condition")do|value,options|options[:all]=valueendadd_option("--skip=gem_name","used on --all, skip if name == gem_name")do|value,options|options[:skip]||=[]options[:skip]<<valueendadd_option("--[no-]extensions","Restore gems with extensions","in addition to regular gems")do|value,options|options[:extensions_set]=trueoptions[:extensions]=valueendadd_option("--only-missing-extensions","Only restore gems with missing extensions")do|value,options|options[:only_missing_extensions]=valueendadd_option("--only-executables","Only restore executables")do|value,options|options[:only_executables]=valueendadd_option("--only-plugins","Only restore plugins")do|value,options|options[:only_plugins]=valueendadd_option("-E","--[no-]env-shebang","Rewrite executables with a shebang","of /usr/bin/env")do|value,options|options[:env_shebang]=valueendadd_option("-i","--install-dir DIR","Gem repository to get gems restored")do|value,options|options[:install_dir]=File.expand_path(value)endadd_option("-n","--bindir DIR","Directory where executables are","located")do|value,options|options[:bin_dir]=File.expand_path(value)endadd_version_option("restore to","pristine condition")enddefarguments# :nodoc:"GEMNAME gem to restore to pristine condition (unless --all)"enddefdefaults_str# :nodoc:"--extensions"enddefdescription# :nodoc:<<-EOF
The pristine command compares an installed gem with the contents of its
cached .gem file and restores any files that don't match the cached .gem's
copy.
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.
If the cached gem cannot be found it will be downloaded.
If --no-extensions is provided pristine will not attempt to restore a gem
with an extension.
If --extensions is given (but not --all or gem names) only gems with
extensions will be restored.
EOFenddefusage# :nodoc:"#{program_name} [GEMNAME ...]"enddefexecuteinstall_dir=options[:install_dir]specification_record=install_dir?Gem::SpecificationRecord.from_path(install_dir):Gem::Specification.specification_recordspecs=ifoptions[:all]specification_record.map# `--extensions` must be explicitly given to pristine only gems# with extensions.elsifoptions[:extensions_set]&&options[:extensions]&&options[:args].empty?specification_record.selectdo|spec|spec.extensions&&!spec.extensions.empty?endelsifoptions[:only_missing_extensions]specification_record.select(&:missing_extensions?)elseget_all_gem_names.sort.flat_mapdo|gem_name|specification_record.find_all_by_name(gem_name,options[:version]).reverseendendspecs=specs.select{|spec|spec.platform==RUBY_ENGINE||Gem::Platform.local===spec.platform||spec.platform==Gem::Platform::RUBY}ifspecs.to_a.empty?raiseGem::Exception,"Failed to find gems #{options[:args]}#{options[:version]}"endsay"Restoring gems to pristine condition..."specs.group_by(&:full_name_with_location).values.eachdo|grouped_specs|spec=grouped_specs.find{|s|!s.default_gem?}||grouped_specs.firstunlessonly_executables_or_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.options[:only_executables]=trueifspec.default_gem?endifoptions.key?:skipifoptions[:skip].include?spec.namesay"Skipped #{spec.full_name}, it was given through options"nextendendunlessspec.extensions.empty?||options[:extensions]||only_executables_or_plugins?say"Skipped #{spec.full_name_with_location}, it needs to compile an extension"nextendgem=spec.cache_fileunlessFile.exist?(gem)||only_executables_or_plugins?require_relative"../remote_fetcher"say"Cached gem for #{spec.full_name_with_location} not found, attempting to fetch..."dep=Gem::Dependency.newspec.name,spec.versionfound,_=Gem::SpecFetcher.fetcher.spec_for_dependencydepiffound.empty?say"Skipped #{spec.full_name}, it was not found from cache and remote sources"nextendspec_candidate,source=found.firstGem::RemoteFetcher.fetcher.downloadspec_candidate,source.uri.to_s,spec.base_direndenv_shebang=ifoptions.include?:env_shebangoptions[:env_shebang]elseinstall_defaults=Gem::ConfigFile::PLATFORM_DEFAULTS["install"]install_defaults.to_s["--env-shebang"]endbin_dir=options[:bin_dir]ifoptions[:bin_dir]installer_options={wrappers: true,force: true,install_dir: install_dir||spec.base_dir,env_shebang: env_shebang,build_args: spec.build_args,bin_dir: bin_dir,}ifoptions[:only_executables]installer=Gem::Installer.for_spec(spec,installer_options)installer.generate_binelsifoptions[:only_plugins]installer=Gem::Installer.for_spec(spec,installer_options)installer.generate_pluginselseinstaller=Gem::Installer.at(gem,installer_options)installer.installendsay"Restored #{spec.full_name_with_location}"endendprivatedefonly_executables_or_plugins?options[:only_executables]||options[:only_plugins]endend