# frozen_string_literal: truerequire'rubygems/command'require'rubygems/package'require'rubygems/installer'require'rubygems/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]=valueendadd_option('--[no-]extensions','Restore gems with extensions','in addition to regular gems')do|value,options|options[:extensions_set]=trueoptions[:extensions]=valueendadd_option('--only-executables','Only restore executables')do|value,options|options[:only_executables]=valueendadd_option('-E','--[no-]env-shebang','Rewrite executables with a shebang','of /usr/bin/env')do|value,options|options[:env_shebang]=valueendadd_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 ...]"enddefexecutespecs=ifoptions[:all]thenGem::Specification.map# `--extensions` must be explicitly given to pristine only gems# with extensions.elsifoptions[:extensions_set]andoptions[:extensions]andoptions[:args].empty?thenGem::Specification.selectdo|spec|spec.extensionsandnotspec.extensions.empty?endelseget_all_gem_names.sort.mapdo|gem_name|Gem::Specification.find_all_by_name(gem_name,options[:version]).reverseend.flattenendifspecs.to_a.empty?thenraiseGem::Exception,"Failed to find gems #{options[:args]}#{options[:version]}"endinstall_dir=Gem.dir# TODO use installer optionraiseGem::FilePermissionError.new(install_dir)unlessFile.writable?(install_dir)say"Restoring gems to pristine condition..."specs.eachdo|spec|ifspec.default_gem?say"Skipped #{spec.full_name}, it is a default gem"nextendifspec.name==options[:skip]say"Skipped #{spec.full_name}, it was given through options"nextendifspec.bundled_gem_in_old_ruby?say"Skipped #{spec.full_name}, it is bundled with old Ruby"nextendunlessspec.extensions.empty?oroptions[:extensions]thensay"Skipped #{spec.full_name}, it needs to compile an extension"nextendgem=spec.cache_fileunlessFile.exist?gemthenrequire'rubygems/remote_fetcher'say"Cached gem for #{spec.full_name} 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_shebangthenoptions[:env_shebang]elseinstall_defaults=Gem::ConfigFile::PLATFORM_DEFAULTS['install']install_defaults.to_s['--env-shebang']endinstaller=Gem::Installer.at(gem,:wrappers=>true,:force=>true,:install_dir=>spec.base_dir,:env_shebang=>env_shebang,:build_args=>spec.build_args)ifoptions[:only_executables]theninstaller.generate_binelseinstaller.installendsay"Restored #{spec.full_name}"endendend