diff options
author | Jari Vetoniemi <jari.vetoniemi@indooratlas.com> | 2020-03-16 18:49:26 +0900 |
---|---|---|
committer | Jari Vetoniemi <jari.vetoniemi@indooratlas.com> | 2020-03-30 00:39:06 +0900 |
commit | fcbf63e62c627deae76c1b8cb8c0876c536ed811 (patch) | |
tree | 64cb17de3f41a2b6fef2368028fbd00349946994 /jni/ruby/lib/rubygems/commands |
Fresh start
Diffstat (limited to 'jni/ruby/lib/rubygems/commands')
32 files changed, 4945 insertions, 0 deletions
diff --git a/jni/ruby/lib/rubygems/commands/build_command.rb b/jni/ruby/lib/rubygems/commands/build_command.rb new file mode 100644 index 0000000..d975429 --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/build_command.rb @@ -0,0 +1,60 @@ +require 'rubygems/command' +require 'rubygems/package' + +class Gem::Commands::BuildCommand < Gem::Command + + def initialize + super 'build', 'Build a gem from a gemspec' + + add_option '--force', 'skip validation of the spec' do |value, options| + options[:force] = true + end + end + + def arguments # :nodoc: + "GEMSPEC_FILE gemspec file name to build a gem for" + end + + def description # :nodoc: + <<-EOF +The build command allows you to create a gem from a ruby gemspec. + +The best way to build a gem is to use a Rakefile and the Gem::PackageTask +which ships with RubyGems. + +The gemspec can either be created by hand or extracted from an existing gem +with gem spec: + + $ gem unpack my_gem-1.0.gem + Unpacked gem: '.../my_gem-1.0' + $ gem spec my_gem-1.0.gem --ruby > my_gem-1.0/my_gem-1.0.gemspec + $ cd my_gem-1.0 + [edit gem contents] + $ gem build my_gem-1.0.gemspec + EOF + end + + def usage # :nodoc: + "#{program_name} GEMSPEC_FILE" + end + + def execute + gemspec = get_one_gem_name + + if File.exist? gemspec then + spec = Gem::Specification.load gemspec + + if spec then + Gem::Package.build spec, options[:force] + else + alert_error "Error loading gemspec. Aborting." + terminate_interaction 1 + end + else + alert_error "Gemspec file not found: #{gemspec}" + terminate_interaction 1 + end + end + +end + diff --git a/jni/ruby/lib/rubygems/commands/cert_command.rb b/jni/ruby/lib/rubygems/commands/cert_command.rb new file mode 100644 index 0000000..a920e7f --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/cert_command.rb @@ -0,0 +1,276 @@ +require 'rubygems/command' +require 'rubygems/security' +begin + require 'openssl' +rescue LoadError => e + raise unless (e.respond_to?(:path) && e.path == 'openssl') || + e.message =~ / -- openssl$/ +end + +class Gem::Commands::CertCommand < Gem::Command + + def initialize + super 'cert', 'Manage RubyGems certificates and signing settings', + :add => [], :remove => [], :list => [], :build => [], :sign => [] + + OptionParser.accept OpenSSL::X509::Certificate do |certificate| + begin + OpenSSL::X509::Certificate.new File.read certificate + rescue Errno::ENOENT + raise OptionParser::InvalidArgument, "#{certificate}: does not exist" + rescue OpenSSL::X509::CertificateError + raise OptionParser::InvalidArgument, + "#{certificate}: invalid X509 certificate" + end + end + + OptionParser.accept OpenSSL::PKey::RSA do |key_file| + begin + passphrase = ENV['GEM_PRIVATE_KEY_PASSPHRASE'] + key = OpenSSL::PKey::RSA.new File.read(key_file), passphrase + rescue Errno::ENOENT + raise OptionParser::InvalidArgument, "#{key_file}: does not exist" + rescue OpenSSL::PKey::RSAError + raise OptionParser::InvalidArgument, "#{key_file}: invalid RSA key" + end + + raise OptionParser::InvalidArgument, + "#{key_file}: private key not found" unless key.private? + + key + end + + add_option('-a', '--add CERT', OpenSSL::X509::Certificate, + 'Add a trusted certificate.') do |cert, options| + options[:add] << cert + end + + add_option('-l', '--list [FILTER]', + 'List trusted certificates where the', + 'subject contains FILTER') do |filter, options| + filter ||= '' + + options[:list] << filter + end + + add_option('-r', '--remove FILTER', + 'Remove trusted certificates where the', + 'subject contains FILTER') do |filter, options| + options[:remove] << filter + end + + add_option('-b', '--build EMAIL_ADDR', + 'Build private key and self-signed', + 'certificate for EMAIL_ADDR') do |email_address, options| + options[:build] << email_address + end + + add_option('-C', '--certificate CERT', OpenSSL::X509::Certificate, + 'Signing certificate for --sign') do |cert, options| + options[:issuer_cert] = cert + end + + add_option('-K', '--private-key KEY', OpenSSL::PKey::RSA, + 'Key for --sign or --build') do |key, options| + options[:key] = key + end + + add_option('-s', '--sign CERT', + 'Signs CERT with the key from -K', + 'and the certificate from -C') do |cert_file, options| + raise OptionParser::InvalidArgument, "#{cert_file}: does not exist" unless + File.file? cert_file + + options[:sign] << cert_file + end + end + + def add_certificate certificate # :nodoc: + Gem::Security.trust_dir.trust_cert certificate + + say "Added '#{certificate.subject}'" + end + + def execute + options[:add].each do |certificate| + add_certificate certificate + end + + options[:remove].each do |filter| + remove_certificates_matching filter + end + + options[:list].each do |filter| + list_certificates_matching filter + end + + options[:build].each do |name| + build name + end + + sign_certificates unless options[:sign].empty? + end + + def build name + key, key_path = build_key + cert_path = build_cert name, key + + say "Certificate: #{cert_path}" + + if key_path + say "Private Key: #{key_path}" + say "Don't forget to move the key file to somewhere private!" + end + end + + def build_cert name, key # :nodoc: + cert = Gem::Security.create_cert_email name, key + Gem::Security.write cert, "gem-public_cert.pem" + end + + def build_key # :nodoc: + return options[:key] if options[:key] + + passphrase = ask_for_password 'Passphrase for your Private Key:' + say "\n" + + passphrase_confirmation = ask_for_password 'Please repeat the passphrase for your Private Key:' + say "\n" + + raise Gem::CommandLineError, + "Passphrase and passphrase confirmation don't match" unless passphrase == passphrase_confirmation + + key = Gem::Security.create_key + key_path = Gem::Security.write key, "gem-private_key.pem", 0600, passphrase + + return key, key_path + end + + def certificates_matching filter + return enum_for __method__, filter unless block_given? + + Gem::Security.trusted_certificates.select do |certificate, _| + subject = certificate.subject.to_s + subject.downcase.index filter + end.sort_by do |certificate, _| + certificate.subject.to_a.map { |name, data,| [name, data] } + end.each do |certificate, path| + yield certificate, path + end + end + + def description # :nodoc: + <<-EOF +The cert command manages signing keys and certificates for creating signed +gems. Your signing certificate and private key are typically stored in +~/.gem/gem-public_cert.pem and ~/.gem/gem-private_key.pem respectively. + +To build a certificate for signing gems: + + gem cert --build you@example + +If you already have an RSA key, or are creating a new certificate for an +existing key: + + gem cert --build you@example --private-key /path/to/key.pem + +If you wish to trust a certificate you can add it to the trust list with: + + gem cert --add /path/to/cert.pem + +You can list trusted certificates with: + + gem cert --list + +or: + + gem cert --list cert_subject_substring + +If you wish to remove a previously trusted certificate: + + gem cert --remove cert_subject_substring + +To sign another gem author's certificate: + + gem cert --sign /path/to/other_cert.pem + +For further reading on signing gems see `ri Gem::Security`. + EOF + end + + def list_certificates_matching filter # :nodoc: + certificates_matching filter do |certificate, _| + # this could probably be formatted more gracefully + say certificate.subject.to_s + end + end + + def load_default_cert + cert_file = File.join Gem.default_cert_path + cert = File.read cert_file + options[:issuer_cert] = OpenSSL::X509::Certificate.new cert + rescue Errno::ENOENT + alert_error \ + "--certificate not specified and ~/.gem/gem-public_cert.pem does not exist" + + terminate_interaction 1 + rescue OpenSSL::X509::CertificateError + alert_error \ + "--certificate not specified and ~/.gem/gem-public_cert.pem is not valid" + + terminate_interaction 1 + end + + def load_default_key + key_file = File.join Gem.default_key_path + key = File.read key_file + passphrase = ENV['GEM_PRIVATE_KEY_PASSPHRASE'] + options[:key] = OpenSSL::PKey::RSA.new key, passphrase + rescue Errno::ENOENT + alert_error \ + "--private-key not specified and ~/.gem/gem-private_key.pem does not exist" + + terminate_interaction 1 + rescue OpenSSL::PKey::RSAError + alert_error \ + "--private-key not specified and ~/.gem/gem-private_key.pem is not valid" + + terminate_interaction 1 + end + + def load_defaults # :nodoc: + load_default_cert unless options[:issuer_cert] + load_default_key unless options[:key] + end + + def remove_certificates_matching filter # :nodoc: + certificates_matching filter do |certificate, path| + FileUtils.rm path + say "Removed '#{certificate.subject}'" + end + end + + def sign cert_file + cert = File.read cert_file + cert = OpenSSL::X509::Certificate.new cert + + permissions = File.stat(cert_file).mode & 0777 + + issuer_cert = options[:issuer_cert] + issuer_key = options[:key] + + cert = Gem::Security.sign cert, issuer_key, issuer_cert + + Gem::Security.write cert, cert_file, permissions + end + + def sign_certificates # :nodoc: + load_defaults unless options[:sign].empty? + + options[:sign].each do |cert_file| + sign cert_file + end + end + +end if defined?(OpenSSL::SSL) + diff --git a/jni/ruby/lib/rubygems/commands/check_command.rb b/jni/ruby/lib/rubygems/commands/check_command.rb new file mode 100644 index 0000000..8893b9c --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/check_command.rb @@ -0,0 +1,93 @@ +require 'rubygems/command' +require 'rubygems/version_option' +require 'rubygems/validator' +require 'rubygems/doctor' + +class Gem::Commands::CheckCommand < Gem::Command + + include Gem::VersionOption + + def initialize + super 'check', 'Check a gem repository for added or missing files', + :alien => true, :doctor => false, :dry_run => false, :gems => true + + add_option('-a', '--[no-]alien', + 'Report "unmanaged" or rogue files in the', + 'gem repository') do |value, options| + options[:alien] = value + end + + add_option('--[no-]doctor', + 'Clean up uninstalled gems and broken', + 'specifications') do |value, options| + options[:doctor] = value + end + + add_option('--[no-]dry-run', + 'Do not remove files, only report what', + 'would be removed') do |value, options| + options[:dry_run] = value + end + + add_option('--[no-]gems', + 'Check installed gems for problems') do |value, options| + options[:gems] = value + end + + add_version_option 'check' + end + + def check_gems + say 'Checking gems...' + say + gems = get_all_gem_names rescue [] + + Gem::Validator.new.alien(gems).sort.each do |key, val| + unless val.empty? then + say "#{key} has #{val.size} problems" + val.each do |error_entry| + say " #{error_entry.path}:" + say " #{error_entry.problem}" + end + else + say "#{key} is error-free" if Gem.configuration.verbose + end + say + end + end + + def doctor + say 'Checking for files from uninstalled gems...' + say + + Gem.path.each do |gem_repo| + doctor = Gem::Doctor.new gem_repo, options[:dry_run] + doctor.doctor + end + end + + def execute + check_gems if options[:gems] + doctor if options[:doctor] + end + + def arguments # :nodoc: + 'GEMNAME name of gem to check' + end + + def defaults_str # :nodoc: + '--gems --alien' + end + + def description # :nodoc: + <<-EOF +The check command can list and repair problems with installed gems and +specifications and will clean up gems that have been partially uninstalled. + EOF + end + + def usage # :nodoc: + "#{program_name} [OPTIONS] [GEMNAME ...]" + end + +end diff --git a/jni/ruby/lib/rubygems/commands/cleanup_command.rb b/jni/ruby/lib/rubygems/commands/cleanup_command.rb new file mode 100644 index 0000000..6997564 --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/cleanup_command.rb @@ -0,0 +1,165 @@ +require 'rubygems/command' +require 'rubygems/dependency_list' +require 'rubygems/uninstaller' + +class Gem::Commands::CleanupCommand < Gem::Command + + def initialize + super 'cleanup', + 'Clean up old versions of installed gems', + :force => false, :install_dir => Gem.dir + + add_option('-n', '-d', '--dryrun', + 'Do not uninstall gems') do |value, options| + options[:dryrun] = true + end + + @candidate_gems = nil + @default_gems = [] + @full = nil + @gems_to_cleanup = nil + @original_home = nil + @original_path = nil + @primary_gems = nil + end + + def arguments # :nodoc: + "GEMNAME name of gem to cleanup" + end + + def defaults_str # :nodoc: + "--no-dryrun" + end + + def description # :nodoc: + <<-EOF +The cleanup command removes old versions of gems from GEM_HOME that are not +required to meet a dependency. If a gem is installed elsewhere in GEM_PATH +the cleanup command won't delete it. + +If no gems are named all gems in GEM_HOME are cleaned. + EOF + end + + def usage # :nodoc: + "#{program_name} [GEMNAME ...]" + end + + def execute + say "Cleaning up installed gems..." + + if options[:args].empty? then + done = false + last_set = nil + + until done do + clean_gems + + this_set = @gems_to_cleanup.map { |spec| spec.full_name }.sort + + done = this_set.empty? || last_set == this_set + + last_set = this_set + end + else + clean_gems + end + + say "Clean Up Complete" + + verbose do + skipped = @default_gems.map { |spec| spec.full_name } + + "Skipped default gems: #{skipped.join ', '}" + end + end + + def clean_gems + get_primary_gems + get_candidate_gems + get_gems_to_cleanup + + @full = Gem::DependencyList.from_specs + + deplist = Gem::DependencyList.new + @gems_to_cleanup.each do |spec| deplist.add spec end + + deps = deplist.strongly_connected_components.flatten + + @original_home = Gem.dir + @original_path = Gem.path + + deps.reverse_each do |spec| + uninstall_dep spec + end + + Gem::Specification.reset + end + + def get_candidate_gems + @candidate_gems = unless options[:args].empty? then + options[:args].map do |gem_name| + Gem::Specification.find_all_by_name gem_name + end.flatten + else + Gem::Specification.to_a + end + end + + def get_gems_to_cleanup + gems_to_cleanup = @candidate_gems.select { |spec| + @primary_gems[spec.name].version != spec.version + } + + default_gems, gems_to_cleanup = gems_to_cleanup.partition { |spec| + spec.default_gem? + } + + @default_gems += default_gems + @default_gems.uniq! + @gems_to_cleanup = gems_to_cleanup.uniq + end + + def get_primary_gems + @primary_gems = {} + + Gem::Specification.each do |spec| + if @primary_gems[spec.name].nil? or + @primary_gems[spec.name].version < spec.version then + @primary_gems[spec.name] = spec + end + end + end + + def uninstall_dep spec + return unless @full.ok_to_remove?(spec.full_name) + + if options[:dryrun] then + say "Dry Run Mode: Would uninstall #{spec.full_name}" + return + end + + say "Attempting to uninstall #{spec.full_name}" + + uninstall_options = { + :executables => false, + :version => "= #{spec.version}", + } + + uninstall_options[:user_install] = Gem.user_dir == spec.base_dir + + uninstaller = Gem::Uninstaller.new spec.name, uninstall_options + + begin + uninstaller.uninstall + rescue Gem::DependencyRemovalException, Gem::InstallError, + Gem::GemNotInHomeException, Gem::FilePermissionError => e + say "Unable to uninstall #{spec.full_name}:" + say "\t#{e.class}: #{e.message}" + end + ensure + # Restore path Gem::Uninstaller may have changed + Gem.use_paths @original_home, *@original_path + end + +end diff --git a/jni/ruby/lib/rubygems/commands/contents_command.rb b/jni/ruby/lib/rubygems/commands/contents_command.rb new file mode 100644 index 0000000..4b944f1 --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/contents_command.rb @@ -0,0 +1,190 @@ +require 'English' +require 'rubygems/command' +require 'rubygems/version_option' + +class Gem::Commands::ContentsCommand < Gem::Command + + include Gem::VersionOption + + def initialize + super 'contents', 'Display the contents of the installed gems', + :specdirs => [], :lib_only => false, :prefix => true, + :show_install_dir => false + + add_version_option + + add_option( '--all', + "Contents for all gems") do |all, options| + options[:all] = all + end + + add_option('-s', '--spec-dir a,b,c', Array, + "Search for gems under specific paths") do |spec_dirs, options| + options[:specdirs] = spec_dirs + end + + add_option('-l', '--[no-]lib-only', + "Only return files in the Gem's lib_dirs") do |lib_only, options| + options[:lib_only] = lib_only + end + + add_option( '--[no-]prefix', + "Don't include installed path prefix") do |prefix, options| + options[:prefix] = prefix + end + + add_option( '--[no-]show-install-dir', + 'Show only the gem install dir') do |show, options| + options[:show_install_dir] = show + end + + @path_kind = nil + @spec_dirs = nil + @version = nil + end + + def arguments # :nodoc: + "GEMNAME name of gem to list contents for" + end + + def defaults_str # :nodoc: + "--no-lib-only --prefix" + end + + def description # :nodoc: + <<-EOF +The contents command lists the files in an installed gem. The listing can +be given as full file names, file names without the installed directory +prefix or only the files that are requireable. + EOF + end + + def usage # :nodoc: + "#{program_name} GEMNAME [GEMNAME ...]" + end + + def execute + @version = options[:version] || Gem::Requirement.default + @spec_dirs = specification_directories + @path_kind = path_description @spec_dirs + + names = gem_names + + names.each do |name| + found = + if options[:show_install_dir] then + gem_install_dir name + else + gem_contents name + end + + terminate_interaction 1 unless found or names.length > 1 + end + end + + def files_in spec + if spec.default_gem? then + files_in_default_gem spec + else + files_in_gem spec + end + end + + def files_in_gem spec + gem_path = spec.full_gem_path + extra = "/{#{spec.require_paths.join ','}}" if options[:lib_only] + glob = "#{gem_path}#{extra}/**/*" + prefix_re = /#{Regexp.escape(gem_path)}\// + + Dir[glob].map do |file| + [gem_path, file.sub(prefix_re, "")] + end + end + + def files_in_default_gem spec + spec.files.map do |file| + case file + when /\A#{spec.bindir}\// + [RbConfig::CONFIG['bindir'], $POSTMATCH] + when /\.so\z/ + [RbConfig::CONFIG['archdir'], file] + else + [RbConfig::CONFIG['rubylibdir'], file] + end + end + end + + def gem_contents name + spec = spec_for name + + return false unless spec + + files = files_in spec + + show_files files + + true + end + + def gem_install_dir name + spec = spec_for name + + return false unless spec + + say spec.gem_dir + + true + end + + def gem_names # :nodoc: + if options[:all] then + Gem::Specification.map(&:name) + else + get_all_gem_names + end + end + + def path_description spec_dirs # :nodoc: + if spec_dirs.empty? then + "default gem paths" + else + "specified path" + end + end + + def show_files files + files.sort.each do |prefix, basename| + absolute_path = File.join(prefix, basename) + next if File.directory? absolute_path + + if options[:prefix] then + say absolute_path + else + say basename + end + end + end + + def spec_for name + spec = Gem::Specification.find_all_by_name(name, @version).last + + return spec if spec + + say "Unable to find gem '#{name}' in #{@path_kind}" + + if Gem.configuration.verbose then + say "\nDirectories searched:" + @spec_dirs.sort.each { |dir| say dir } + end + + return nil + end + + def specification_directories # :nodoc: + options[:specdirs].map do |i| + [i, File.join(i, "specifications")] + end.flatten + end + +end + diff --git a/jni/ruby/lib/rubygems/commands/dependency_command.rb b/jni/ruby/lib/rubygems/commands/dependency_command.rb new file mode 100644 index 0000000..4a54a3e --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/dependency_command.rb @@ -0,0 +1,207 @@ +require 'rubygems/command' +require 'rubygems/local_remote_options' +require 'rubygems/version_option' + +class Gem::Commands::DependencyCommand < Gem::Command + + include Gem::LocalRemoteOptions + include Gem::VersionOption + + def initialize + super 'dependency', + 'Show the dependencies of an installed gem', + :version => Gem::Requirement.default, :domain => :local + + add_version_option + add_platform_option + add_prerelease_option + + add_option('-R', '--[no-]reverse-dependencies', + 'Include reverse dependencies in the output') do + |value, options| + options[:reverse_dependencies] = value + end + + add_option('-p', '--pipe', + "Pipe Format (name --version ver)") do |value, options| + options[:pipe_format] = value + end + + add_local_remote_options + end + + def arguments # :nodoc: + "REGEXP show dependencies for gems whose names start with REGEXP" + end + + def defaults_str # :nodoc: + "--local --version '#{Gem::Requirement.default}' --no-reverse-dependencies" + end + + def description # :nodoc: + <<-EOF +The dependency commands lists which other gems a given gem depends on. For +local gems only the reverse dependencies can be shown (which gems depend on +the named gem). + +The dependency list can be displayed in a format suitable for piping for +use with other commands. + EOF + end + + def usage # :nodoc: + "#{program_name} REGEXP" + end + + def fetch_remote_specs dependency # :nodoc: + fetcher = Gem::SpecFetcher.fetcher + + ss, = fetcher.spec_for_dependency dependency + + ss.map { |spec, _| spec } + end + + def fetch_specs dependency # :nodoc: + specs = [] + + specs.concat dependency.matching_specs if local? + specs.concat fetch_remote_specs dependency if remote? + + ensure_specs specs + + specs.uniq.sort + end + + def gem_dependency args, version, prerelease # :nodoc: + args << '' if args.empty? + + pattern = if args.length == 1 and args.first =~ /\A\/(.*)\/(i)?\z/m then + flags = $2 ? Regexp::IGNORECASE : nil + Regexp.new $1, flags + else + /\A#{Regexp.union(*args)}/ + end + + dependency = Gem::Deprecate.skip_during { + Gem::Dependency.new pattern, version + } + + dependency.prerelease = prerelease + + dependency + end + + def display_pipe specs # :nodoc: + specs.each do |spec| + unless spec.dependencies.empty? then + spec.dependencies.sort_by { |dep| dep.name }.each do |dep| + say "#{dep.name} --version '#{dep.requirement}'" + end + end + end + end + + def display_readable specs, reverse # :nodoc: + response = '' + + specs.each do |spec| + response << print_dependencies(spec) + unless reverse[spec.full_name].empty? then + response << " Used by\n" + reverse[spec.full_name].each do |sp, dep| + response << " #{sp} (#{dep})\n" + end + end + response << "\n" + end + + say response + end + + def execute + ensure_local_only_reverse_dependencies + + dependency = + gem_dependency options[:args], options[:version], options[:prerelease] + + specs = fetch_specs dependency + + reverse = reverse_dependencies specs + + if options[:pipe_format] then + display_pipe specs + else + display_readable specs, reverse + end + end + + def ensure_local_only_reverse_dependencies # :nodoc: + if options[:reverse_dependencies] and remote? and not local? then + alert_error 'Only reverse dependencies for local gems are supported.' + terminate_interaction 1 + end + end + + def ensure_specs specs # :nodoc: + return unless specs.empty? + + patterns = options[:args].join ',' + say "No gems found matching #{patterns} (#{options[:version]})" if + Gem.configuration.verbose + + terminate_interaction 1 + end + + def print_dependencies(spec, level = 0) # :nodoc: + response = '' + response << ' ' * level + "Gem #{spec.full_name}\n" + unless spec.dependencies.empty? then + spec.dependencies.sort_by { |dep| dep.name }.each do |dep| + response << ' ' * level + " #{dep}\n" + end + end + response + end + + def remote_specs dependency # :nodoc: + fetcher = Gem::SpecFetcher.fetcher + + ss, _ = fetcher.spec_for_dependency dependency + + ss.map { |s,o| s } + end + + def reverse_dependencies specs # :nodoc: + reverse = Hash.new { |h, k| h[k] = [] } + + return reverse unless options[:reverse_dependencies] + + specs.each do |spec| + reverse[spec.full_name] = find_reverse_dependencies spec + end + + reverse + end + + ## + # Returns an Array of [specification, dep] that are satisfied by +spec+. + + def find_reverse_dependencies spec # :nodoc: + result = [] + + Gem::Specification.each do |sp| + sp.dependencies.each do |dep| + dep = Gem::Dependency.new(*dep) unless Gem::Dependency === dep + + if spec.name == dep.name and + dep.requirement.satisfied_by?(spec.version) then + result << [sp.full_name, dep] + end + end + end + + result + end + +end + diff --git a/jni/ruby/lib/rubygems/commands/environment_command.rb b/jni/ruby/lib/rubygems/commands/environment_command.rb new file mode 100644 index 0000000..067d0b1 --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/environment_command.rb @@ -0,0 +1,158 @@ +require 'rubygems/command' + +class Gem::Commands::EnvironmentCommand < Gem::Command + + def initialize + super 'environment', 'Display information about the RubyGems environment' + end + + def arguments # :nodoc: + args = <<-EOF + packageversion display the package version + gemdir display the path where gems are installed + gempath display path used to search for gems + version display the gem format version + remotesources display the remote gem servers + platform display the supported gem platforms + <omitted> display everything + EOF + return args.gsub(/^\s+/, '') + end + + def description # :nodoc: + <<-EOF +The environment command lets you query rubygems for its configuration for +use in shell scripts or as a debugging aid. + +The RubyGems environment can be controlled through command line arguments, +gemrc files, environment variables and built-in defaults. + +Command line argument defaults and some RubyGems defaults can be set in a +~/.gemrc file for individual users and a gemrc in the SYSTEM CONFIGURATION +DIRECTORY for all users. These files are YAML files with the following YAML +keys: + + :sources: A YAML array of remote gem repositories to install gems from + :verbose: Verbosity of the gem command. false, true, and :really are the + levels + :update_sources: Enable/disable automatic updating of repository metadata + :backtrace: Print backtrace when RubyGems encounters an error + :gempath: The paths in which to look for gems + :disable_default_gem_server: Force specification of gem server host on push + <gem_command>: A string containing arguments for the specified gem command + +Example: + + :verbose: false + install: --no-wrappers + update: --no-wrappers + :disable_default_gem_server: true + +RubyGems' default local repository can be overridden with the GEM_PATH and +GEM_HOME environment variables. GEM_HOME sets the default repository to +install into. GEM_PATH allows multiple local repositories to be searched for +gems. + +If you are behind a proxy server, RubyGems uses the HTTP_PROXY, +HTTP_PROXY_USER and HTTP_PROXY_PASS environment variables to discover the +proxy server. + +If you would like to push gems to a private gem server the RUBYGEMS_HOST +environment variable can be set to the URI for that server. + +If you are packaging RubyGems all of RubyGems' defaults are in +lib/rubygems/defaults.rb. You may override these in +lib/rubygems/defaults/operating_system.rb + EOF + end + + def usage # :nodoc: + "#{program_name} [arg]" + end + + def execute + out = '' + arg = options[:args][0] + out << + case arg + when /^packageversion/ then + Gem::RubyGemsPackageVersion + when /^version/ then + Gem::VERSION + when /^gemdir/, /^gemhome/, /^home/, /^GEM_HOME/ then + Gem.dir + when /^gempath/, /^path/, /^GEM_PATH/ then + Gem.path.join(File::PATH_SEPARATOR) + when /^remotesources/ then + Gem.sources.to_a.join("\n") + when /^platform/ then + Gem.platforms.join(File::PATH_SEPARATOR) + when nil then + show_environment + else + raise Gem::CommandLineError, "Unknown environment option [#{arg}]" + end + say out + true + end + + def add_path out, path + path.each do |component| + out << " - #{component}\n" + end + end + + def show_environment # :nodoc: + out = "RubyGems Environment:\n" + + out << " - RUBYGEMS VERSION: #{Gem::VERSION}\n" + + out << " - RUBY VERSION: #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}" + out << " patchlevel #{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL + out << ") [#{RUBY_PLATFORM}]\n" + + out << " - INSTALLATION DIRECTORY: #{Gem.dir}\n" + + out << " - RUBYGEMS PREFIX: #{Gem.prefix}\n" unless Gem.prefix.nil? + + out << " - RUBY EXECUTABLE: #{Gem.ruby}\n" + + out << " - EXECUTABLE DIRECTORY: #{Gem.bindir}\n" + + out << " - SPEC CACHE DIRECTORY: #{Gem.spec_cache_dir}\n" + + out << " - SYSTEM CONFIGURATION DIRECTORY: #{Gem::ConfigFile::SYSTEM_CONFIG_PATH}\n" + + out << " - RUBYGEMS PLATFORMS:\n" + Gem.platforms.each do |platform| + out << " - #{platform}\n" + end + + out << " - GEM PATHS:\n" + out << " - #{Gem.dir}\n" + + gem_path = Gem.path.dup + gem_path.delete Gem.dir + add_path out, gem_path + + out << " - GEM CONFIGURATION:\n" + Gem.configuration.each do |name, value| + value = value.gsub(/./, '*') if name == 'gemcutter_key' + out << " - #{name.inspect} => #{value.inspect}\n" + end + + out << " - REMOTE SOURCES:\n" + Gem.sources.each do |s| + out << " - #{s}\n" + end + + out << " - SHELL PATH:\n" + + shell_path = ENV['PATH'].split(File::PATH_SEPARATOR) + add_path out, shell_path + + out + end + +end + diff --git a/jni/ruby/lib/rubygems/commands/fetch_command.rb b/jni/ruby/lib/rubygems/commands/fetch_command.rb new file mode 100644 index 0000000..c57ab00 --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/fetch_command.rb @@ -0,0 +1,77 @@ +require 'rubygems/command' +require 'rubygems/local_remote_options' +require 'rubygems/version_option' + +class Gem::Commands::FetchCommand < Gem::Command + + include Gem::LocalRemoteOptions + include Gem::VersionOption + + def initialize + super 'fetch', 'Download a gem and place it in the current directory' + + add_bulk_threshold_option + add_proxy_option + add_source_option + add_clear_sources_option + + add_version_option + add_platform_option + add_prerelease_option + end + + def arguments # :nodoc: + 'GEMNAME name of gem to download' + end + + def defaults_str # :nodoc: + "--version '#{Gem::Requirement.default}'" + end + + def description # :nodoc: + <<-EOF +The fetch command fetches gem files that can be stored for later use or +unpacked to examine their contents. + +See the build command help for an example of unpacking a gem, modifying it, +then repackaging it. + EOF + end + + def usage # :nodoc: + "#{program_name} GEMNAME [GEMNAME ...]" + end + + def execute + version = options[:version] || Gem::Requirement.default + + platform = Gem.platforms.last + gem_names = get_all_gem_names + + gem_names.each do |gem_name| + dep = Gem::Dependency.new gem_name, version + dep.prerelease = options[:prerelease] + + specs_and_sources, errors = + Gem::SpecFetcher.fetcher.spec_for_dependency dep + + if platform then + filtered = specs_and_sources.select { |s,| s.platform == platform } + specs_and_sources = filtered unless filtered.empty? + end + + spec, source = specs_and_sources.max_by { |s,| s.version } + + if spec.nil? then + show_lookup_failure gem_name, version, errors, options[:domain] + next + end + + source.download spec + + say "Downloaded #{spec.full_name}" + end + end + +end + diff --git a/jni/ruby/lib/rubygems/commands/generate_index_command.rb b/jni/ruby/lib/rubygems/commands/generate_index_command.rb new file mode 100644 index 0000000..ca6f694 --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/generate_index_command.rb @@ -0,0 +1,84 @@ +require 'rubygems/command' +require 'rubygems/indexer' + +## +# Generates a index files for use as a gem server. +# +# See `gem help generate_index` + +class Gem::Commands::GenerateIndexCommand < Gem::Command + + def initialize + super 'generate_index', + 'Generates the index files for a gem server directory', + :directory => '.', :build_modern => true + + add_option '-d', '--directory=DIRNAME', + 'repository base dir containing gems subdir' do |dir, options| + options[:directory] = File.expand_path dir + end + + add_option '--[no-]modern', + 'Generate indexes for RubyGems', + '(always true)' do |value, options| + options[:build_modern] = value + end + + add_option '--update', + 'Update modern indexes with gems added', + 'since the last update' do |value, options| + options[:update] = value + end + end + + def defaults_str # :nodoc: + "--directory . --modern" + end + + def description # :nodoc: + <<-EOF +The generate_index command creates a set of indexes for serving gems +statically. The command expects a 'gems' directory under the path given to +the --directory option. The given directory will be the directory you serve +as the gem repository. + +For `gem generate_index --directory /path/to/repo`, expose /path/to/repo via +your HTTP server configuration (not /path/to/repo/gems). + +When done, it will generate a set of files like this: + + gems/*.gem # .gem files you want to + # index + + specs.<version>.gz # specs index + latest_specs.<version>.gz # latest specs index + prerelease_specs.<version>.gz # prerelease specs index + quick/Marshal.<version>/<gemname>.gemspec.rz # Marshal quick index file + +The .rz extension files are compressed with the inflate algorithm. +The Marshal version number comes from ruby's Marshal::MAJOR_VERSION and +Marshal::MINOR_VERSION constants. It is used to ensure compatibility. + EOF + end + + def execute + # This is always true because it's the only way now. + options[:build_modern] = true + + if not File.exist?(options[:directory]) or + not File.directory?(options[:directory]) then + alert_error "unknown directory name #{directory}." + terminate_interaction 1 + else + indexer = Gem::Indexer.new options.delete(:directory), options + + if options[:update] then + indexer.update_index + else + indexer.generate_index + end + end + end + +end + diff --git a/jni/ruby/lib/rubygems/commands/help_command.rb b/jni/ruby/lib/rubygems/commands/help_command.rb new file mode 100644 index 0000000..ed81ad6 --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/help_command.rb @@ -0,0 +1,384 @@ +require 'rubygems/command' + +class Gem::Commands::HelpCommand < Gem::Command + + # :stopdoc: + EXAMPLES = <<-EOF +Some examples of 'gem' usage. + +* Install 'rake', either from local directory or remote server: + + gem install rake + +* Install 'rake', only from remote server: + + gem install rake --remote + +* Install 'rake', but only version 0.3.1, even if dependencies + are not met, and into a user-specific directory: + + gem install rake --version 0.3.1 --force --user-install + +* List local gems whose name begins with 'D': + + gem list D + +* List local and remote gems whose name contains 'log': + + gem search log --both + +* List only remote gems whose name contains 'log': + + gem search log --remote + +* Uninstall 'rake': + + gem uninstall rake + +* Create a gem: + + See http://guides.rubygems.org/make-your-own-gem/ + +* See information about RubyGems: + + gem environment + +* Update all gems on your system: + + gem update + +* Update your local version of RubyGems + + gem update --system + EOF + + GEM_DEPENDENCIES = <<-EOF +A gem dependencies file allows installation of a consistent set of gems across +multiple environments. The RubyGems implementation is designed to be +compatible with Bundler's Gemfile format. You can see additional +documentation on the format at: + + http://bundler.io + +RubyGems automatically looks for these gem dependencies files: + +* gem.deps.rb +* Gemfile +* Isolate + +These files are looked up automatically using `gem install -g`, or you can +specify a custom file. + +When the RUBYGEMS_GEMDEPS environment variable is set to a gem dependencies +file the gems from that file will be activated at startup time. Set it to a +specific filename or to "-" to have RubyGems automatically discover the gem +dependencies file by walking up from the current directory. + +You can also activate gem dependencies at program startup using +Gem.use_gemdeps. + +NOTE: Enabling automatic discovery on multiuser systems can lead to execution +of arbitrary code when used from directories outside your control. + +Gem Dependencies +================ + +Use #gem to declare which gems you directly depend upon: + + gem 'rake' + +To depend on a specific set of versions: + + gem 'rake', '~> 10.3', '>= 10.3.2' + +RubyGems will require the gem name when activating the gem using +the RUBYGEMS_GEMDEPS environment variable or Gem::use_gemdeps. Use the +require: option to override this behavior if the gem does not have a file of +that name or you don't want to require those files: + + gem 'my_gem', require: 'other_file' + +To prevent RubyGems from requiring any files use: + + gem 'my_gem', require: false + +To load dependencies from a .gemspec file: + + gemspec + +RubyGems looks for the first .gemspec file in the current directory. To +override this use the name: option: + + gemspec name: 'specific_gem' + +To look in a different directory use the path: option: + + gemspec name: 'specific_gem', path: 'gemspecs' + +To depend on a gem unpacked into a local directory: + + gem 'modified_gem', path: 'vendor/modified_gem' + +To depend on a gem from git: + + gem 'private_gem', git: 'git@my.company.example:private_gem.git' + +To depend on a gem from github: + + gem 'private_gem', github: 'my_company/private_gem' + +To depend on a gem from a github gist: + + gem 'bang', gist: '1232884' + +Git, github and gist support the ref:, branch: and tag: options to specify a +commit reference or hash, branch or tag respectively to use for the gem. + +Setting the submodules: option to true for git, github and gist dependencies +causes fetching of submodules when fetching the repository. + +You can depend on multiple gems from a single repository with the git method: + + git 'https://github.com/rails/rails.git' do + gem 'activesupport' + gem 'activerecord' + end + +Gem Sources +=========== + +RubyGems uses the default sources for regular `gem install` for gem +dependencies files. Unlike bundler, you do need to specify a source. + +You can override the sources used for downloading gems with: + + source 'https://gem_server.example' + +You may specify multiple sources. Unlike bundler the prepend: option is not +supported. Sources are used in-order, to prepend a source place it at the +front of the list. + +Gem Platform +============ + +You can restrict gem dependencies to specific platforms with the #platform +and #platforms methods: + + platform :ruby_21 do + gem 'debugger' + end + +See the bundler Gemfile manual page for a list of platforms supported in a gem +dependencies file.: + + http://bundler.io/v1.6/man/gemfile.5.html + +Ruby Version and Engine Dependency +================================== + +You can specifiy the version, engine and engine version of ruby to use with +your gem dependencies file. If you are not running the specified version +RubyGems will raise an exception. + +To depend on a specific version of ruby: + + ruby '2.1.2' + +To depend on a specific ruby engine: + + ruby '1.9.3', engine: 'jruby' + +To depend on a specific ruby engine version: + + ruby '1.9.3', engine: 'jruby', engine_version: '1.7.11' + +Grouping Dependencies +===================== + +Gem dependencies may be placed in groups that can be excluded from install. +Dependencies required for development or testing of your code may be excluded +when installed in a production environment. + +A #gem dependency may be placed in a group using the group: option: + + gem 'minitest', group: :test + +To install dependencies from a gemfile without specific groups use the +`--without` option for `gem install -g`: + + $ gem install -g --without test + +The group: option also accepts multiple groups if the gem fits in multiple +categories. + +Multiple groups may be excluded during install by comma-separating the groups for `--without` or by specifying `--without` multiple times. + +The #group method can also be used to place gems in groups: + + group :test do + gem 'minitest' + gem 'minitest-emoji' + end + +The #group method allows multiple groups. + +The #gemspec development dependencies are placed in the :development group by +default. This may be overriden with the :development_group option: + + gemspec development_group: :other + + EOF + + PLATFORMS = <<-'EOF' +RubyGems platforms are composed of three parts, a CPU, an OS, and a +version. These values are taken from values in rbconfig.rb. You can view +your current platform by running `gem environment`. + +RubyGems matches platforms as follows: + + * The CPU must match exactly unless one of the platforms has + "universal" as the CPU or the local CPU starts with "arm" and the gem's + CPU is exactly "arm" (for gems that support generic ARM architecture). + * The OS must match exactly. + * The versions must match exactly unless one of the versions is nil. + +For commands that install, uninstall and list gems, you can override what +RubyGems thinks your platform is with the --platform option. The platform +you pass must match "#{cpu}-#{os}" or "#{cpu}-#{os}-#{version}". On mswin +platforms, the version is the compiler version, not the OS version. (Ruby +compiled with VC6 uses "60" as the compiler version, VC8 uses "80".) + +For the ARM architecture, gems with a platform of "arm-linux" should run on a +reasonable set of ARM CPUs and not depend on instructions present on a limited +subset of the architecture. For example, the binary should run on platforms +armv5, armv6hf, armv6l, armv7, etc. If you use the "arm-linux" platform +please test your gem on a variety of ARM hardware before release to ensure it +functions correctly. + +Example platforms: + + x86-freebsd # Any FreeBSD version on an x86 CPU + universal-darwin-8 # Darwin 8 only gems that run on any CPU + x86-mswin32-80 # Windows gems compiled with VC8 + armv7-linux # Gem complied for an ARMv7 CPU running linux + arm-linux # Gem compiled for any ARM CPU running linux + +When building platform gems, set the platform in the gem specification to +Gem::Platform::CURRENT. This will correctly mark the gem with your ruby's +platform. + EOF + + # NOTE when updating also update Gem::Command::HELP + + SUBCOMMANDS = [ + ["commands", :show_commands], + ["options", Gem::Command::HELP], + ["examples", EXAMPLES], + ["gem_dependencies", GEM_DEPENDENCIES], + ["platforms", PLATFORMS], + ] + # :startdoc: + + def initialize + super 'help', "Provide help on the 'gem' command" + + @command_manager = Gem::CommandManager.instance + end + + def usage # :nodoc: + "#{program_name} ARGUMENT" + end + + def execute + arg = options[:args][0] + + _, help = SUBCOMMANDS.find do |command,| + begins? command, arg + end + + if help then + if Symbol === help then + send help + else + say help + end + return + end + + if options[:help] then + show_help + + elsif arg then + show_command_help arg + + else + say Gem::Command::HELP + end + end + + def show_commands # :nodoc: + out = [] + out << "GEM commands are:" + out << nil + + margin_width = 4 + + desc_width = @command_manager.command_names.map { |n| n.size }.max + 4 + + summary_width = 80 - margin_width - desc_width + wrap_indent = ' ' * (margin_width + desc_width) + format = "#{' ' * margin_width}%-#{desc_width}s%s" + + @command_manager.command_names.each do |cmd_name| + command = @command_manager[cmd_name] + + summary = + if command then + command.summary + else + "[No command found for #{cmd_name}]" + end + + summary = wrap(summary, summary_width).split "\n" + out << sprintf(format, cmd_name, summary.shift) + until summary.empty? do + out << "#{wrap_indent}#{summary.shift}" + end + end + + out << nil + out << "For help on a particular command, use 'gem help COMMAND'." + out << nil + out << "Commands may be abbreviated, so long as they are unambiguous." + out << "e.g. 'gem i rake' is short for 'gem install rake'." + + say out.join("\n") + end + + def show_command_help command_name # :nodoc: + command_name = command_name.downcase + + possibilities = @command_manager.find_command_possibilities command_name + + if possibilities.size == 1 then + command = @command_manager[possibilities.first] + command.invoke("--help") + elsif possibilities.size > 1 then + alert_warning "Ambiguous command #{command_name} (#{possibilities.join(', ')})" + else + alert_warning "Unknown command #{command_name}. Try: gem help commands" + end + end + + def show_help # :nodoc: + command = @command_manager[options[:help]] + if command then + # help with provided command + command.invoke("--help") + else + alert_error "Unknown command #{options[:help]}. Try 'gem help commands'" + end + end + +end + diff --git a/jni/ruby/lib/rubygems/commands/install_command.rb b/jni/ruby/lib/rubygems/commands/install_command.rb new file mode 100644 index 0000000..1bf5928 --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/install_command.rb @@ -0,0 +1,347 @@ +require 'rubygems/command' +require 'rubygems/install_update_options' +require 'rubygems/dependency_installer' +require 'rubygems/local_remote_options' +require 'rubygems/validator' +require 'rubygems/version_option' + +## +# Gem installer command line tool +# +# See `gem help install` + +class Gem::Commands::InstallCommand < Gem::Command + + attr_reader :installed_specs # :nodoc: + + include Gem::VersionOption + include Gem::LocalRemoteOptions + include Gem::InstallUpdateOptions + + def initialize + defaults = Gem::DependencyInstaller::DEFAULT_OPTIONS.merge({ + :format_executable => false, + :lock => true, + :suggest_alternate => true, + :version => Gem::Requirement.default, + :without_groups => [], + }) + + super 'install', 'Install a gem into the local repository', defaults + + add_install_update_options + add_local_remote_options + add_platform_option + add_version_option + add_prerelease_option "to be installed. (Only for listed gems)" + + add_option(:"Install/Update", '-g', '--file [FILE]', + 'Read from a gem dependencies API file and', + 'install the listed gems') do |v,o| + v = Gem::GEM_DEP_FILES.find do |file| + File.exist? file + end unless v + + unless v then + message = v ? v : "(tried #{Gem::GEM_DEP_FILES.join ', '})" + + raise OptionParser::InvalidArgument, + "cannot find gem dependencies file #{message}" + end + + o[:gemdeps] = v + end + + add_option(:"Install/Update", '--without GROUPS', Array, + 'Omit the named groups (comma separated)', + 'when installing from a gem dependencies', + 'file') do |v,o| + o[:without_groups].concat v.map { |without| without.intern } + end + + add_option(:"Install/Update", '--default', + 'Add the gem\'s full specification to', + 'specifications/default and extract only its bin') do |v,o| + o[:install_as_default] = v + end + + add_option(:"Install/Update", '--explain', + 'Rather than install the gems, indicate which would', + 'be installed') do |v,o| + o[:explain] = v + end + + add_option(:"Install/Update", '--[no-]lock', + 'Create a lock file (when used with -g/--file)') do |v,o| + o[:lock] = v + end + + add_option(:"Install/Update", '--[no-]suggestions', + 'Suggest alternates when gems are not found') do |v,o| + o[:suggest_alternate] = v + end + + @installed_specs = [] + end + + def arguments # :nodoc: + "GEMNAME name of gem to install" + end + + def defaults_str # :nodoc: + "--both --version '#{Gem::Requirement.default}' --document --no-force\n" + + "--install-dir #{Gem.dir} --lock" + end + + def description # :nodoc: + <<-EOF +The install command installs local or remote gem into a gem repository. + +For gems with executables ruby installs a wrapper file into the executable +directory by default. This can be overridden with the --no-wrappers option. +The wrapper allows you to choose among alternate gem versions using _version_. + +For example `rake _0.7.3_ --version` will run rake version 0.7.3 if a newer +version is also installed. + +Gem Dependency Files +==================== + +RubyGems can install a consistent set of gems across multiple environments +using `gem install -g` when a gem dependencies file (gem.deps.rb, Gemfile or +Isolate) is present. If no explicit file is given RubyGems attempts to find +one in the current directory. + +When the RUBYGEMS_GEMDEPS environment variable is set to a gem dependencies +file the gems from that file will be activated at startup time. Set it to a +specific filename or to "-" to have RubyGems automatically discover the gem +dependencies file by walking up from the current directory. + +NOTE: Enabling automatic discovery on multiuser systems can lead to +execution of arbitrary code when used from directories outside your control. + +Extension Install Failures +========================== + +If an extension fails to compile during gem installation the gem +specification is not written out, but the gem remains unpacked in the +repository. You may need to specify the path to the library's headers and +libraries to continue. You can do this by adding a -- between RubyGems' +options and the extension's build options: + + $ gem install some_extension_gem + [build fails] + Gem files will remain installed in \\ + /path/to/gems/some_extension_gem-1.0 for inspection. + Results logged to /path/to/gems/some_extension_gem-1.0/gem_make.out + $ gem install some_extension_gem -- --with-extension-lib=/path/to/lib + [build succeeds] + $ gem list some_extension_gem + + *** LOCAL GEMS *** + + some_extension_gem (1.0) + $ + +If you correct the compilation errors by editing the gem files you will need +to write the specification by hand. For example: + + $ gem install some_extension_gem + [build fails] + Gem files will remain installed in \\ + /path/to/gems/some_extension_gem-1.0 for inspection. + Results logged to /path/to/gems/some_extension_gem-1.0/gem_make.out + $ [cd /path/to/gems/some_extension_gem-1.0] + $ [edit files or what-have-you and run make] + $ gem spec ../../cache/some_extension_gem-1.0.gem --ruby > \\ + ../../specifications/some_extension_gem-1.0.gemspec + $ gem list some_extension_gem + + *** LOCAL GEMS *** + + some_extension_gem (1.0) + $ + + EOF + end + + def usage # :nodoc: + "#{program_name} GEMNAME [GEMNAME ...] [options] -- --build-flags" + end + + def check_install_dir # :nodoc: + if options[:install_dir] and options[:user_install] then + alert_error "Use --install-dir or --user-install but not both" + terminate_interaction 1 + end + end + + def check_version # :nodoc: + if options[:version] != Gem::Requirement.default and + get_all_gem_names.size > 1 then + alert_error "Can't use --version w/ multiple gems. Use name:ver instead." + terminate_interaction 1 + end + end + + def execute + if options.include? :gemdeps then + install_from_gemdeps + return # not reached + end + + @installed_specs = [] + + ENV.delete 'GEM_PATH' if options[:install_dir].nil? and RUBY_VERSION > '1.9' + + check_install_dir + check_version + + load_hooks + + exit_code = install_gems + + show_installed + + terminate_interaction exit_code + end + + def install_from_gemdeps # :nodoc: + require 'rubygems/request_set' + rs = Gem::RequestSet.new + + specs = rs.install_from_gemdeps options do |req, inst| + s = req.full_spec + + if inst + say "Installing #{s.name} (#{s.version})" + else + say "Using #{s.name} (#{s.version})" + end + end + + @installed_specs = specs + + terminate_interaction + end + + def install_gem name, version # :nodoc: + return if options[:conservative] and + not Gem::Dependency.new(name, version).matching_specs.empty? + + req = Gem::Requirement.create(version) + + if options[:ignore_dependencies] then + install_gem_without_dependencies name, req + else + inst = Gem::DependencyInstaller.new options + request_set = inst.resolve_dependencies name, req + + if options[:explain] + puts "Gems to install:" + + request_set.sorted_requests.each do |s| + puts " #{s.full_name}" + end + + return + else + @installed_specs.concat request_set.install options + end + + show_install_errors inst.errors + end + end + + def install_gem_without_dependencies name, req # :nodoc: + gem = nil + + if local? then + if name =~ /\.gem$/ and File.file? name then + source = Gem::Source::SpecificFile.new name + spec = source.spec + else + source = Gem::Source::Local.new + spec = source.find_gem name, req + end + gem = source.download spec if spec + end + + if remote? and not gem then + dependency = Gem::Dependency.new name, req + dependency.prerelease = options[:prerelease] + + fetcher = Gem::RemoteFetcher.fetcher + gem = fetcher.download_to_cache dependency + end + + inst = Gem::Installer.new gem, options + inst.install + + require 'rubygems/dependency_installer' + dinst = Gem::DependencyInstaller.new options + dinst.installed_gems.replace [inst.spec] + + Gem.done_installing_hooks.each do |hook| + hook.call dinst, [inst.spec] + end unless Gem.done_installing_hooks.empty? + + @installed_specs.push(inst.spec) + end + + def install_gems # :nodoc: + exit_code = 0 + + get_all_gem_names_and_versions.each do |gem_name, gem_version| + gem_version ||= options[:version] + + begin + install_gem gem_name, gem_version + rescue Gem::InstallError => e + alert_error "Error installing #{gem_name}:\n\t#{e.message}" + exit_code |= 1 + rescue Gem::GemNotFoundException, Gem::UnsatisfiableDependencyError => e + domain = options[:domain] + domain = :local unless options[:suggest_alternate] + show_lookup_failure e.name, e.version, e.errors, domain + + exit_code |= 2 + end + end + + exit_code + end + + ## + # Loads post-install hooks + + def load_hooks # :nodoc: + if options[:install_as_default] + require 'rubygems/install_default_message' + else + require 'rubygems/install_message' + end + require 'rubygems/rdoc' + end + + def show_install_errors errors # :nodoc: + return unless errors + + errors.each do |x| + return unless Gem::SourceFetchProblem === x + + msg = "Unable to pull data from '#{x.source.uri}': #{x.error.message}" + + alert_warning msg + end + end + + def show_installed # :nodoc: + return if @installed_specs.empty? + + gems = @installed_specs.length == 1 ? 'gem' : 'gems' + say "#{@installed_specs.length} #{gems} installed" + end + +end + diff --git a/jni/ruby/lib/rubygems/commands/list_command.rb b/jni/ruby/lib/rubygems/commands/list_command.rb new file mode 100644 index 0000000..c6ff237 --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/list_command.rb @@ -0,0 +1,40 @@ +require 'rubygems/command' +require 'rubygems/commands/query_command' + +## +# An alternate to Gem::Commands::QueryCommand that searches for gems starting +# with the the supplied argument. + +class Gem::Commands::ListCommand < Gem::Commands::QueryCommand + + def initialize + super 'list', 'Display local gems whose name matches REGEXP' + + remove_option('--name-matches') + end + + def arguments # :nodoc: + "REGEXP regexp to look for in gem name" + end + + def defaults_str # :nodoc: + "--local --no-details" + end + + def description # :nodoc: + <<-EOF +The list command is used to view the gems you have installed locally. + +The --details option displays additional details including the summary, the +homepage, the author, the locations of different versions of the gem. + +To search for remote gems use the search command. + EOF + end + + def usage # :nodoc: + "#{program_name} [STRING ...]" + end + +end + diff --git a/jni/ruby/lib/rubygems/commands/lock_command.rb b/jni/ruby/lib/rubygems/commands/lock_command.rb new file mode 100644 index 0000000..6b4b25a --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/lock_command.rb @@ -0,0 +1,110 @@ +require 'rubygems/command' + +class Gem::Commands::LockCommand < Gem::Command + + def initialize + super 'lock', 'Generate a lockdown list of gems', + :strict => false + + add_option '-s', '--[no-]strict', + 'fail if unable to satisfy a dependency' do |strict, options| + options[:strict] = strict + end + end + + def arguments # :nodoc: + "GEMNAME name of gem to lock\nVERSION version of gem to lock" + end + + def defaults_str # :nodoc: + "--no-strict" + end + + def description # :nodoc: + <<-EOF +The lock command will generate a list of +gem+ statements that will lock down +the versions for the gem given in the command line. It will specify exact +versions in the requirements list to ensure that the gems loaded will always +be consistent. A full recursive search of all effected gems will be +generated. + +Example: + + gem lock rails-1.0.0 > lockdown.rb + +will produce in lockdown.rb: + + require "rubygems" + gem 'rails', '= 1.0.0' + gem 'rake', '= 0.7.0.1' + gem 'activesupport', '= 1.2.5' + gem 'activerecord', '= 1.13.2' + gem 'actionpack', '= 1.11.2' + gem 'actionmailer', '= 1.1.5' + gem 'actionwebservice', '= 1.0.0' + +Just load lockdown.rb from your application to ensure that the current +versions are loaded. Make sure that lockdown.rb is loaded *before* any +other require statements. + +Notice that rails 1.0.0 only requires that rake 0.6.2 or better be used. +Rake-0.7.0.1 is the most recent version installed that satisfies that, so we +lock it down to the exact version. + EOF + end + + def usage # :nodoc: + "#{program_name} GEMNAME-VERSION [GEMNAME-VERSION ...]" + end + + def complain(message) + if options[:strict] then + raise Gem::Exception, message + else + say "# #{message}" + end + end + + def execute + say "require 'rubygems'" + + locked = {} + + pending = options[:args] + + until pending.empty? do + full_name = pending.shift + + spec = Gem::Specification.load spec_path(full_name) + + if spec.nil? then + complain "Could not find gem #{full_name}, try using the full name" + next + end + + say "gem '#{spec.name}', '= #{spec.version}'" unless locked[spec.name] + locked[spec.name] = true + + spec.runtime_dependencies.each do |dep| + next if locked[dep.name] + candidates = dep.matching_specs + + if candidates.empty? then + complain "Unable to satisfy '#{dep}' from currently installed gems" + else + pending << candidates.last.full_name + end + end + end + end + + def spec_path(gem_full_name) + gemspecs = Gem.path.map { |path| + File.join path, "specifications", "#{gem_full_name}.gemspec" + } + + gemspecs.find { |path| File.exist? path } + end + +end + diff --git a/jni/ruby/lib/rubygems/commands/mirror_command.rb b/jni/ruby/lib/rubygems/commands/mirror_command.rb new file mode 100644 index 0000000..24fb668 --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/mirror_command.rb @@ -0,0 +1,25 @@ +require 'rubygems/command' + +unless defined? Gem::Commands::MirrorCommand + class Gem::Commands::MirrorCommand < Gem::Command + def initialize + super('mirror', 'Mirror all gem files (requires rubygems-mirror)') + begin + Gem::Specification.find_by_name('rubygems-mirror').activate + rescue Gem::LoadError + # no-op + end + end + + def description # :nodoc: + <<-EOF +The mirror command has been moved to the rubygems-mirror gem. + EOF + end + + def execute + alert_error "Install the rubygems-mirror gem for the mirror command" + end + + end +end diff --git a/jni/ruby/lib/rubygems/commands/open_command.rb b/jni/ruby/lib/rubygems/commands/open_command.rb new file mode 100644 index 0000000..91963bb --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/open_command.rb @@ -0,0 +1,74 @@ +require 'English' +require 'rubygems/command' +require 'rubygems/version_option' +require 'rubygems/util' + +class Gem::Commands::OpenCommand < Gem::Command + + include Gem::VersionOption + + def initialize + super 'open', 'Open gem sources in editor' + + add_option('-e', '--editor EDITOR', String, + "Opens gem sources in EDITOR") do |editor, options| + options[:editor] = editor || get_env_editor + end + end + + def arguments # :nodoc: + "GEMNAME name of gem to open in editor" + end + + def defaults_str # :nodoc: + "-e #{get_env_editor}" + end + + def description # :nodoc: + <<-EOF + The open command opens gem in editor and changes current path + to gem's source directory. Editor can be specified with -e option, + otherwise rubygems will look for editor in $EDITOR, $VISUAL and + $GEM_EDITOR variables. + EOF + end + + def usage # :nodoc: + "#{program_name} GEMNAME [-e EDITOR]" + end + + def get_env_editor + ENV['GEM_EDITOR'] || + ENV['VISUAL'] || + ENV['EDITOR'] || + 'vi' + end + + def execute + @version = options[:version] || Gem::Requirement.default + @editor = options[:editor] || get_env_editor + + found = open_gem(get_one_gem_name) + + terminate_interaction 1 unless found + end + + def open_gem name + spec = spec_for name + return false unless spec + + open_editor(spec.full_gem_path) + end + + def open_editor path + system(*@editor.split(/\s+/) + [path]) + end + + def spec_for name + spec = Gem::Specification.find_all_by_name(name, @version).last + + return spec if spec + + say "Unable to find gem '#{name}'" + end +end diff --git a/jni/ruby/lib/rubygems/commands/outdated_command.rb b/jni/ruby/lib/rubygems/commands/outdated_command.rb new file mode 100644 index 0000000..7159dbb --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/outdated_command.rb @@ -0,0 +1,32 @@ +require 'rubygems/command' +require 'rubygems/local_remote_options' +require 'rubygems/spec_fetcher' +require 'rubygems/version_option' + +class Gem::Commands::OutdatedCommand < Gem::Command + + include Gem::LocalRemoteOptions + include Gem::VersionOption + + def initialize + super 'outdated', 'Display all gems that need updates' + + add_local_remote_options + add_platform_option + end + + def description # :nodoc: + <<-EOF +The outdated command lists gems you may wish to upgrade to a newer version. + +You can check for dependency mismatches using the dependency command and +update the gems with the update or install commands. + EOF + end + + def execute + Gem::Specification.outdated_and_latest_version.each do |spec, remote_version| + say "#{spec.name} (#{spec.version} < #{remote_version})" + end + end +end diff --git a/jni/ruby/lib/rubygems/commands/owner_command.rb b/jni/ruby/lib/rubygems/commands/owner_command.rb new file mode 100644 index 0000000..322bf65 --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/owner_command.rb @@ -0,0 +1,99 @@ +require 'rubygems/command' +require 'rubygems/local_remote_options' +require 'rubygems/gemcutter_utilities' + +class Gem::Commands::OwnerCommand < Gem::Command + include Gem::LocalRemoteOptions + include Gem::GemcutterUtilities + + def description # :nodoc: + <<-EOF +The owner command lets you add and remove owners of a gem on a push +server (the default is https://rubygems.org). + +The owner of a gem has the permission to push new versions, yank existing +versions or edit the HTML page of the gem. Be careful of who you give push +permission to. + EOF + end + + def arguments # :nodoc: + "GEM gem to manage owners for" + end + + def usage # :nodoc: + "#{program_name} GEM" + end + + def initialize + super 'owner', 'Manage gem owners of a gem on the push server' + add_proxy_option + add_key_option + defaults.merge! :add => [], :remove => [] + + add_option '-a', '--add EMAIL', 'Add an owner' do |value, options| + options[:add] << value + end + + add_option '-r', '--remove EMAIL', 'Remove an owner' do |value, options| + options[:remove] << value + end + + add_option '-h', '--host HOST', 'Use another gemcutter-compatible host' do |value, options| + options[:host] = value + end + end + + def execute + @host = options[:host] + + sign_in + name = get_one_gem_name + + add_owners name, options[:add] + remove_owners name, options[:remove] + show_owners name + end + + def show_owners name + response = rubygems_api_request :get, "api/v1/gems/#{name}/owners.yaml" do |request| + request.add_field "Authorization", api_key + end + + with_response response do |resp| + owners = YAML.load resp.body + + say "Owners for gem: #{name}" + owners.each do |owner| + say "- #{owner['email']}" + end + end + end + + def add_owners name, owners + manage_owners :post, name, owners + end + + def remove_owners name, owners + manage_owners :delete, name, owners + end + + def manage_owners method, name, owners + owners.each do |owner| + begin + response = rubygems_api_request method, "api/v1/gems/#{name}/owners" do |request| + request.set_form_data 'email' => owner + request.add_field "Authorization", api_key + end + + action = method == :delete ? "Removing" : "Adding" + + with_response response, "#{action} #{owner}" + rescue + # ignore + end + end + end + +end + diff --git a/jni/ruby/lib/rubygems/commands/pristine_command.rb b/jni/ruby/lib/rubygems/commands/pristine_command.rb new file mode 100644 index 0000000..dcd5bb7 --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/pristine_command.rb @@ -0,0 +1,165 @@ +require 'rubygems/command' +require 'rubygems/package' +require 'rubygems/installer' +require 'rubygems/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| + options[:all] = value + end + + 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| + options[:only_executables] = 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') + end + + def arguments # :nodoc: + "GEMNAME gem to restore to pristine condition (unless --all)" + end + + def defaults_str # :nodoc: + '--extensions' + end + + def description # :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. + EOF + end + + def usage # :nodoc: + "#{program_name} [GEMNAME ...]" + 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.map do |gem_name| + Gem::Specification.find_all_by_name gem_name, options[:version] + end.flatten + end + + if specs.to_a.empty? then + raise Gem::Exception, + "Failed to find gems #{options[:args]} #{options[:version]}" + end + + install_dir = Gem.dir # TODO use installer option + + raise Gem::FilePermissionError.new(install_dir) unless + File.writable?(install_dir) + + 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 + + if spec.bundled_gem_in_old_ruby? + say "Skipped #{spec.full_name}, it is bundled with old Ruby" + next + end + + unless spec.extensions.empty? or options[:extensions] then + say "Skipped #{spec.full_name}, it needs to compile an extension" + next + end + + gem = spec.cache_file + + unless File.exist? gem then + require 'rubygems/remote_fetcher' + + say "Cached gem for #{spec.full_name} not found, attempting to fetch..." + + dep = Gem::Dependency.new spec.name, spec.version + found, _ = Gem::SpecFetcher.fetcher.spec_for_dependency dep + + if found.empty? + say "Skipped #{spec.full_name}, it was not found from cache and remote sources" + next + end + + spec_candidate, source = found.first + Gem::RemoteFetcher.fetcher.download spec_candidate, source.uri.to_s, spec.base_dir + end + + env_shebang = + if options.include? :env_shebang then + options[:env_shebang] + else + install_defaults = Gem::ConfigFile::PLATFORM_DEFAULTS['install'] + install_defaults.to_s['--env-shebang'] + end + + installer = Gem::Installer.new(gem, + :wrappers => true, + :force => true, + :install_dir => spec.base_dir, + :env_shebang => env_shebang, + :build_args => spec.build_args) + + if options[:only_executables] then + installer.generate_bin + else + installer.install + end + + say "Restored #{spec.full_name}" + end + end +end diff --git a/jni/ruby/lib/rubygems/commands/push_command.rb b/jni/ruby/lib/rubygems/commands/push_command.rb new file mode 100644 index 0000000..6899b48 --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/push_command.rb @@ -0,0 +1,98 @@ +require 'rubygems/command' +require 'rubygems/local_remote_options' +require 'rubygems/gemcutter_utilities' +require 'rubygems/package' + +class Gem::Commands::PushCommand < Gem::Command + include Gem::LocalRemoteOptions + include Gem::GemcutterUtilities + + def description # :nodoc: + <<-EOF +The push command uploads a gem to the push server (the default is +https://rubygems.org) and adds it to the index. + +The gem can be removed from the index (but only the index) using the yank +command. For further discussion see the help for the yank command. + EOF + end + + def arguments # :nodoc: + "GEM built gem to push up" + end + + def usage # :nodoc: + "#{program_name} GEM" + end + + def initialize + super 'push', 'Push a gem up to the gem server', :host => self.host + + add_proxy_option + add_key_option + + add_option('--host HOST', + 'Push to another gemcutter-compatible host') do |value, options| + options[:host] = value + end + + @host = nil + end + + def execute + @host = options[:host] + + sign_in @host + + send_gem get_one_gem_name + end + + def send_gem name + args = [:post, "api/v1/gems"] + + latest_rubygems_version = Gem.latest_rubygems_version + + if latest_rubygems_version < Gem.rubygems_version and + Gem.rubygems_version.prerelease? and + Gem::Version.new('2.0.0.rc.2') != Gem.rubygems_version then + alert_error <<-ERROR +You are using a beta release of RubyGems (#{Gem::VERSION}) which is not +allowed to push gems. Please downgrade or upgrade to a release version. + +The latest released RubyGems version is #{latest_rubygems_version} + +You can upgrade or downgrade to the latest release version with: + + gem update --system=#{latest_rubygems_version} + + ERROR + terminate_interaction 1 + end + + gem_data = Gem::Package.new(name) + + unless @host then + @host = gem_data.spec.metadata['default_gem_server'] + end + + # Always include this, even if it's nil + args << @host + + if gem_data.spec.metadata.has_key?('allowed_push_host') + args << gem_data.spec.metadata['allowed_push_host'] + end + + say "Pushing gem to #{@host || Gem.host}..." + + response = rubygems_api_request(*args) do |request| + request.body = Gem.read_binary name + request.add_field "Content-Length", request.body.size + request.add_field "Content-Type", "application/octet-stream" + request.add_field "Authorization", api_key + end + + with_response response + end + +end + diff --git a/jni/ruby/lib/rubygems/commands/query_command.rb b/jni/ruby/lib/rubygems/commands/query_command.rb new file mode 100644 index 0000000..432250e --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/query_command.rb @@ -0,0 +1,343 @@ +require 'rubygems/command' +require 'rubygems/local_remote_options' +require 'rubygems/spec_fetcher' +require 'rubygems/version_option' +require 'rubygems/text' + +class Gem::Commands::QueryCommand < Gem::Command + + include Gem::Text + include Gem::LocalRemoteOptions + include Gem::VersionOption + + def initialize(name = 'query', + summary = 'Query gem information in local or remote repositories') + super name, summary, + :name => //, :domain => :local, :details => false, :versions => true, + :installed => nil, :version => Gem::Requirement.default + + add_option('-i', '--[no-]installed', + 'Check for installed gem') do |value, options| + options[:installed] = value + end + + add_option('-I', 'Equivalent to --no-installed') do |value, options| + options[:installed] = false + end + + add_version_option command, "for use with --installed" + + add_option('-n', '--name-matches REGEXP', + 'Name of gem(s) to query on matches the', + 'provided REGEXP') do |value, options| + options[:name] = /#{value}/i + end + + add_option('-d', '--[no-]details', + 'Display detailed information of gem(s)') do |value, options| + options[:details] = value + end + + add_option( '--[no-]versions', + 'Display only gem names') do |value, options| + options[:versions] = value + options[:details] = false unless value + end + + add_option('-a', '--all', + 'Display all gem versions') do |value, options| + options[:all] = value + end + + add_option( '--[no-]prerelease', + 'Display prerelease versions') do |value, options| + options[:prerelease] = value + end + + add_local_remote_options + end + + def defaults_str # :nodoc: + "--local --name-matches // --no-details --versions --no-installed" + end + + def description # :nodoc: + <<-EOF +The query command is the basis for the list and search commands. + +You should really use the list and search commands instead. This command +is too hard to use. + EOF + end + + def execute + exit_code = 0 + if options[:args].to_a.empty? and options[:name].source.empty? + name = options[:name] + no_name = true + elsif !options[:name].source.empty? + name = Array(options[:name]) + else + name = options[:args].to_a.map{|arg| /#{arg}/i } + end + + prerelease = options[:prerelease] + + unless options[:installed].nil? then + if no_name then + alert_error "You must specify a gem name" + exit_code |= 4 + elsif name.count > 1 + alert_error "You must specify only ONE gem!" + exit_code |= 4 + else + installed = installed? name.first, options[:version] + installed = !installed unless options[:installed] + + if installed then + say "true" + else + say "false" + exit_code |= 1 + end + end + + terminate_interaction exit_code + end + + names = Array(name) + names.each { |n| show_gems n, prerelease } + end + + private + + def display_header type + if (ui.outs.tty? and Gem.configuration.verbose) or both? then + say + say "*** #{type} GEMS ***" + say + end + end + + #Guts of original execute + def show_gems name, prerelease + req = Gem::Requirement.default + # TODO: deprecate for real + dep = Gem::Deprecate.skip_during { Gem::Dependency.new name, req } + dep.prerelease = prerelease + + if local? then + if prerelease and not both? then + alert_warning "prereleases are always shown locally" + end + + display_header 'LOCAL' + + specs = Gem::Specification.find_all { |s| + s.name =~ name and req =~ s.version + } + + spec_tuples = specs.map do |spec| + [spec.name_tuple, spec] + end + + output_query_results spec_tuples + end + + if remote? then + display_header 'REMOTE' + + fetcher = Gem::SpecFetcher.fetcher + + type = if options[:all] + if options[:prerelease] + :complete + else + :released + end + elsif options[:prerelease] + :prerelease + else + :latest + end + + if name.source.empty? + spec_tuples = fetcher.detect(type) { true } + else + spec_tuples = fetcher.detect(type) do |name_tuple| + name === name_tuple.name + end + end + + output_query_results spec_tuples + end + end + + ## + # Check if gem +name+ version +version+ is installed. + + def installed?(name, req = Gem::Requirement.default) + Gem::Specification.any? { |s| s.name =~ name and req =~ s.version } + end + + def output_query_results(spec_tuples) + output = [] + versions = Hash.new { |h,name| h[name] = [] } + + spec_tuples.each do |spec_tuple, source| + versions[spec_tuple.name] << [spec_tuple, source] + end + + versions = versions.sort_by do |(n,_),_| + n.downcase + end + + output_versions output, versions + + say output.join(options[:details] ? "\n\n" : "\n") + end + + def output_versions output, versions + versions.each do |gem_name, matching_tuples| + matching_tuples = matching_tuples.sort_by { |n,_| n.version }.reverse + + platforms = Hash.new { |h,version| h[version] = [] } + + matching_tuples.each do |n, _| + platforms[n.version] << n.platform if n.platform + end + + seen = {} + + matching_tuples.delete_if do |n,_| + if seen[n.version] then + true + else + seen[n.version] = true + false + end + end + + output << make_entry(matching_tuples, platforms) + end + end + + def entry_details entry, detail_tuple, specs, platforms + return unless options[:details] + + name_tuple, spec = detail_tuple + + spec = spec.fetch_spec name_tuple unless Gem::Specification === spec + + entry << "\n" + + spec_platforms entry, platforms + spec_authors entry, spec + spec_homepage entry, spec + spec_license entry, spec + spec_loaded_from entry, spec, specs + spec_summary entry, spec + end + + def entry_versions entry, name_tuples, platforms + return unless options[:versions] + + list = + if platforms.empty? or options[:details] then + name_tuples.map { |n| n.version }.uniq + else + platforms.sort.reverse.map do |version, pls| + if pls == [Gem::Platform::RUBY] then + version + else + ruby = pls.delete Gem::Platform::RUBY + platform_list = [ruby, *pls.sort].compact + "#{version} #{platform_list.join ' '}" + end + end + end + + entry << " (#{list.join ', '})" + end + + def make_entry entry_tuples, platforms + detail_tuple = entry_tuples.first + + name_tuples, specs = entry_tuples.flatten.partition do |item| + Gem::NameTuple === item + end + + entry = [name_tuples.first.name] + + entry_versions entry, name_tuples, platforms + entry_details entry, detail_tuple, specs, platforms + + entry.join + end + + def spec_authors entry, spec + authors = "Author#{spec.authors.length > 1 ? 's' : ''}: " + authors << spec.authors.join(', ') + entry << format_text(authors, 68, 4) + end + + def spec_homepage entry, spec + return if spec.homepage.nil? or spec.homepage.empty? + + entry << "\n" << format_text("Homepage: #{spec.homepage}", 68, 4) + end + + def spec_license entry, spec + return if spec.license.nil? or spec.license.empty? + + licenses = "License#{spec.licenses.length > 1 ? 's' : ''}: " + licenses << spec.licenses.join(', ') + entry << "\n" << format_text(licenses, 68, 4) + end + + def spec_loaded_from entry, spec, specs + return unless spec.loaded_from + + if specs.length == 1 then + default = spec.default_gem? ? ' (default)' : nil + entry << "\n" << " Installed at#{default}: #{spec.base_dir}" + else + label = 'Installed at' + specs.each do |s| + version = s.version.to_s + version << ', default' if s.default_gem? + entry << "\n" << " #{label} (#{version}): #{s.base_dir}" + label = ' ' * label.length + end + end + end + + def spec_platforms entry, platforms + non_ruby = platforms.any? do |_, pls| + pls.any? { |pl| pl != Gem::Platform::RUBY } + end + + return unless non_ruby + + if platforms.length == 1 then + title = platforms.values.length == 1 ? 'Platform' : 'Platforms' + entry << " #{title}: #{platforms.values.sort.join ', '}\n" + else + entry << " Platforms:\n" + platforms.sort_by do |version,| + version + end.each do |version, pls| + label = " #{version}: " + data = format_text pls.sort.join(', '), 68, label.length + data[0, label.length] = label + entry << data << "\n" + end + end + end + + def spec_summary entry, spec + entry << "\n\n" << format_text(spec.summary, 68, 4) + end + +end + diff --git a/jni/ruby/lib/rubygems/commands/rdoc_command.rb b/jni/ruby/lib/rubygems/commands/rdoc_command.rb new file mode 100644 index 0000000..86597f9 --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/rdoc_command.rb @@ -0,0 +1,96 @@ +require 'rubygems/command' +require 'rubygems/version_option' +require 'rubygems/rdoc' +require 'fileutils' + +class Gem::Commands::RdocCommand < Gem::Command + include Gem::VersionOption + + def initialize + super 'rdoc', 'Generates RDoc for pre-installed gems', + :version => Gem::Requirement.default, + :include_rdoc => false, :include_ri => true, :overwrite => false + + add_option('--all', + 'Generate RDoc/RI documentation for all', + 'installed gems') do |value, options| + options[:all] = value + end + + add_option('--[no-]rdoc', + 'Generate RDoc HTML') do |value, options| + options[:include_rdoc] = value + end + + add_option('--[no-]ri', + 'Generate RI data') do |value, options| + options[:include_ri] = value + end + + add_option('--[no-]overwrite', + 'Overwrite installed documents') do |value, options| + options[:overwrite] = value + end + + add_version_option + end + + def arguments # :nodoc: + "GEMNAME gem to generate documentation for (unless --all)" + end + + def defaults_str # :nodoc: + "--version '#{Gem::Requirement.default}' --ri --no-overwrite" + end + + def description # :nodoc: + <<-DESC +The rdoc command builds documentation for installed gems. By default +only documentation is built using rdoc, but additional types of +documentation may be built through rubygems plugins and the +Gem.post_installs hook. + +Use --overwrite to force rebuilding of documentation. + DESC + end + + def usage # :nodoc: + "#{program_name} [args]" + end + + def execute + specs = if options[:all] then + Gem::Specification.to_a + else + get_all_gem_names.map do |name| + Gem::Specification.find_by_name name, options[:version] + end.flatten.uniq + end + + if specs.empty? then + alert_error 'No matching gems found' + terminate_interaction 1 + end + + specs.each do |spec| + doc = Gem::RDoc.new spec, options[:include_rdoc], options[:include_ri] + + doc.force = options[:overwrite] + + if options[:overwrite] then + FileUtils.rm_rf File.join(spec.doc_dir, 'ri') + FileUtils.rm_rf File.join(spec.doc_dir, 'rdoc') + end + + begin + doc.generate + rescue Errno::ENOENT => e + e.message =~ / - / + alert_error "Unable to document #{spec.full_name}, #{$'} is missing, skipping" + terminate_interaction 1 if specs.length == 1 + end + end + end + +end + diff --git a/jni/ruby/lib/rubygems/commands/search_command.rb b/jni/ruby/lib/rubygems/commands/search_command.rb new file mode 100644 index 0000000..a1e2c1a --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/search_command.rb @@ -0,0 +1,40 @@ +require 'rubygems/command' +require 'rubygems/commands/query_command' + +class Gem::Commands::SearchCommand < Gem::Commands::QueryCommand + + def initialize + super 'search', 'Display remote gems whose name matches REGEXP' + + remove_option '--name-matches' + + defaults[:domain] = :remote + end + + def arguments # :nodoc: + "REGEXP regexp to search for in gem name" + end + + def defaults_str # :nodoc: + "--remote --no-details" + end + + def description # :nodoc: + <<-EOF +The search command displays remote gems whose name matches the given +regexp. + +The --details option displays additional details from the gem but will +take a little longer to complete as it must download the information +individually from the index. + +To list local gems use the list command. + EOF + end + + def usage # :nodoc: + "#{program_name} [REGEXP]" + end + +end + diff --git a/jni/ruby/lib/rubygems/commands/server_command.rb b/jni/ruby/lib/rubygems/commands/server_command.rb new file mode 100644 index 0000000..4796ce2 --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/server_command.rb @@ -0,0 +1,86 @@ +require 'rubygems/command' +require 'rubygems/server' + +class Gem::Commands::ServerCommand < Gem::Command + + def initialize + super 'server', 'Documentation and gem repository HTTP server', + :port => 8808, :gemdir => [], :daemon => false + + OptionParser.accept :Port do |port| + if port =~ /\A\d+\z/ then + port = Integer port + raise OptionParser::InvalidArgument, "#{port}: not a port number" if + port > 65535 + + port + else + begin + Socket.getservbyname port + rescue SocketError + raise OptionParser::InvalidArgument, "#{port}: no such named service" + end + end + end + + add_option '-p', '--port=PORT', :Port, + 'port to listen on' do |port, options| + options[:port] = port + end + + add_option '-d', '--dir=GEMDIR', + 'directories from which to serve gems', + 'multiple directories may be provided' do |gemdir, options| + options[:gemdir] << File.expand_path(gemdir) + end + + add_option '--[no-]daemon', 'run as a daemon' do |daemon, options| + options[:daemon] = daemon + end + + add_option '-b', '--bind=HOST,HOST', + 'addresses to bind', Array do |address, options| + options[:addresses] ||= [] + options[:addresses].push(*address) + end + + add_option '-l', '--launch[=COMMAND]', + 'launches a browser window', + "COMMAND defaults to 'start' on Windows", + "and 'open' on all other platforms" do |launch, options| + launch ||= Gem.win_platform? ? 'start' : 'open' + options[:launch] = launch + end + end + + def defaults_str # :nodoc: + "--port 8808 --dir #{Gem.dir} --no-daemon" + end + + def description # :nodoc: + <<-EOF +The server command starts up a web server that hosts the RDoc for your +installed gems and can operate as a server for installation of gems on other +machines. + +The cache files for installed gems must exist to use the server as a source +for gem installation. + +To install gems from a running server, use `gem install GEMNAME --source +http://gem_server_host:8808` + +You can set up a shortcut to gem server documentation using the URL: + + http://localhost:8808/rdoc?q=%s - Firefox + http://localhost:8808/rdoc?q=* - LaunchBar + + EOF + end + + def execute + options[:gemdir] = Gem.path if options[:gemdir].empty? + Gem::Server.run options + end + +end + diff --git a/jni/ruby/lib/rubygems/commands/setup_command.rb b/jni/ruby/lib/rubygems/commands/setup_command.rb new file mode 100644 index 0000000..6617396 --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/setup_command.rb @@ -0,0 +1,483 @@ +require 'rubygems/command' + +## +# Installs RubyGems itself. This command is ordinarily only available from a +# RubyGems checkout or tarball. + +class Gem::Commands::SetupCommand < Gem::Command + HISTORY_HEADER = /^===\s*[\d.]+\s*\/\s*\d{4}-\d{2}-\d{2}\s*$/ + VERSION_MATCHER = /^===\s*([\d.]+)\s*\/\s*\d{4}-\d{2}-\d{2}\s*$/ + + def initialize + require 'tmpdir' + + super 'setup', 'Install RubyGems', + :format_executable => true, :document => %w[ri], + :site_or_vendor => 'sitelibdir', + :destdir => '', :prefix => '', :previous_version => '' + + add_option '--previous-version=VERSION', + 'Previous version of rubygems', + 'Used for changelog processing' do |version, options| + options[:previous_version] = version + end + + add_option '--prefix=PREFIX', + 'Prefix path for installing RubyGems', + 'Will not affect gem repository location' do |prefix, options| + options[:prefix] = File.expand_path prefix + end + + add_option '--destdir=DESTDIR', + 'Root directory to install RubyGems into', + 'Mainly used for packaging RubyGems' do |destdir, options| + options[:destdir] = File.expand_path destdir + end + + add_option '--[no-]vendor', + 'Install into vendorlibdir not sitelibdir' do |vendor, options| + options[:site_or_vendor] = vendor ? 'vendorlibdir' : 'sitelibdir' + end + + add_option '--[no-]format-executable', + 'Makes `gem` match ruby', + 'If ruby is ruby18, gem will be gem18' do |value, options| + options[:format_executable] = value + end + + add_option '--[no-]document [TYPES]', Array, + 'Generate documentation for RubyGems.', + 'List the documentation types you wish to', + 'generate. For example: rdoc,ri' do |value, options| + options[:document] = case value + when nil then %w[rdoc ri] + when false then [] + else value + end + end + + add_option '--[no-]rdoc', + 'Generate RDoc documentation for RubyGems' do |value, options| + if value then + options[:document] << 'rdoc' + else + options[:document].delete 'rdoc' + end + + options[:document].uniq! + end + + add_option '--[no-]ri', + 'Generate RI documentation for RubyGems' do |value, options| + if value then + options[:document] << 'ri' + else + options[:document].delete 'ri' + end + + options[:document].uniq! + end + + @verbose = nil + end + + def check_ruby_version + required_version = Gem::Requirement.new '>= 1.8.7' + + unless required_version.satisfied_by? Gem.ruby_version then + alert_error "Expected Ruby version #{required_version}, is #{Gem.ruby_version}" + terminate_interaction 1 + end + end + + def defaults_str # :nodoc: + "--format-executable --document ri" + end + + def description # :nodoc: + <<-EOF +Installs RubyGems itself. + +RubyGems installs RDoc for itself in GEM_HOME. By default this is: + #{Gem.dir} + +If you prefer a different directory, set the GEM_HOME environment variable. + +RubyGems will install the gem command with a name matching ruby's +prefix and suffix. If ruby was installed as `ruby18`, gem will be +installed as `gem18`. + +By default, this RubyGems will install gem as: + #{Gem.default_exec_format % 'gem'} + EOF + end + + def execute + @verbose = Gem.configuration.really_verbose + + install_destdir = options[:destdir] + + unless install_destdir.empty? then + ENV['GEM_HOME'] ||= File.join(install_destdir, + Gem.default_dir.gsub(/^[a-zA-Z]:/, '')) + end + + check_ruby_version + + require 'fileutils' + if Gem.configuration.really_verbose then + extend FileUtils::Verbose + else + extend FileUtils + end + + lib_dir, bin_dir = make_destination_dirs install_destdir + + install_lib lib_dir + + install_executables bin_dir + + remove_old_bin_files bin_dir + + remove_old_lib_files lib_dir + + say "RubyGems #{Gem::VERSION} installed" + + uninstall_old_gemcutter + + documentation_success = install_rdoc + + say + if @verbose then + say "-" * 78 + say + end + + if options[:previous_version].empty? + options[:previous_version] = Gem::VERSION.sub(/[0-9]+$/, '0') + end + + options[:previous_version] = Gem::Version.new(options[:previous_version]) + + show_release_notes + + say + say "-" * 78 + say + + say "RubyGems installed the following executables:" + say @bin_file_names.map { |name| "\t#{name}\n" } + say + + unless @bin_file_names.grep(/#{File::SEPARATOR}gem$/) then + say "If `gem` was installed by a previous RubyGems installation, you may need" + say "to remove it by hand." + say + end + + if documentation_success + if options[:document].include? 'rdoc' then + say "Rdoc documentation was installed. You may now invoke:" + say " gem server" + say "and then peruse beautifully formatted documentation for your gems" + say "with your web browser." + say "If you do not wish to install this documentation in the future, use the" + say "--no-document flag, or set it as the default in your ~/.gemrc file. See" + say "'gem help env' for details." + say + end + + if options[:document].include? 'ri' then + say "Ruby Interactive (ri) documentation was installed. ri is kind of like man " + say "pages for ruby libraries. You may access it like this:" + say " ri Classname" + say " ri Classname.class_method" + say " ri Classname#instance_method" + say "If you do not wish to install this documentation in the future, use the" + say "--no-document flag, or set it as the default in your ~/.gemrc file. See" + say "'gem help env' for details." + say + end + end + end + + def install_executables(bin_dir) + say "Installing gem executable" if @verbose + + @bin_file_names = [] + + Dir.chdir 'bin' do + bin_files = Dir['*'] + + bin_files.delete 'update_rubygems' + + bin_files.each do |bin_file| + bin_file_formatted = if options[:format_executable] then + Gem.default_exec_format % bin_file + else + bin_file + end + + dest_file = File.join bin_dir, bin_file_formatted + bin_tmp_file = File.join Dir.tmpdir, "#{bin_file}.#{$$}" + + begin + bin = File.readlines bin_file + bin[0] = "#!#{Gem.ruby}\n" + + File.open bin_tmp_file, 'w' do |fp| + fp.puts bin.join + end + + install bin_tmp_file, dest_file, :mode => 0755 + @bin_file_names << dest_file + ensure + rm bin_tmp_file + end + + next unless Gem.win_platform? + + begin + bin_cmd_file = File.join Dir.tmpdir, "#{bin_file}.bat" + + File.open bin_cmd_file, 'w' do |file| + file.puts <<-TEXT +@ECHO OFF +IF NOT "%~f0" == "~f0" GOTO :WinNT +@"#{File.basename(Gem.ruby).chomp('"')}" "#{dest_file}" %1 %2 %3 %4 %5 %6 %7 %8 %9 +GOTO :EOF +:WinNT +@"#{File.basename(Gem.ruby).chomp('"')}" "%~dpn0" %* +TEXT + end + + install bin_cmd_file, "#{dest_file}.bat", :mode => 0755 + ensure + rm bin_cmd_file + end + end + end + end + + def install_file file, dest_dir + dest_file = File.join dest_dir, file + dest_dir = File.dirname dest_file + mkdir_p dest_dir unless File.directory? dest_dir + + install file, dest_file, :mode => 0644 + end + + def install_lib(lib_dir) + say "Installing RubyGems" if @verbose + + lib_files = rb_files_in 'lib' + pem_files = pem_files_in 'lib' + + Dir.chdir 'lib' do + lib_files.each do |lib_file| + install_file lib_file, lib_dir + end + + pem_files.each do |pem_file| + install_file pem_file, lib_dir + end + end + end + + def install_rdoc + gem_doc_dir = File.join Gem.dir, 'doc' + rubygems_name = "rubygems-#{Gem::VERSION}" + rubygems_doc_dir = File.join gem_doc_dir, rubygems_name + + begin + Gem.ensure_gem_subdirectories Gem.dir + rescue SystemCallError + # ignore + end + + if File.writable? gem_doc_dir and + (not File.exist? rubygems_doc_dir or + File.writable? rubygems_doc_dir) then + say "Removing old RubyGems RDoc and ri" if @verbose + Dir[File.join(Gem.dir, 'doc', 'rubygems-[0-9]*')].each do |dir| + rm_rf dir + end + + require 'rubygems/rdoc' + + fake_spec = Gem::Specification.new 'rubygems', Gem::VERSION + def fake_spec.full_gem_path + File.expand_path '../../../..', __FILE__ + end + + generate_ri = options[:document].include? 'ri' + generate_rdoc = options[:document].include? 'rdoc' + + rdoc = Gem::RDoc.new fake_spec, generate_rdoc, generate_ri + rdoc.generate + + return true + elsif @verbose then + say "Skipping RDoc generation, #{gem_doc_dir} not writable" + say "Set the GEM_HOME environment variable if you want RDoc generated" + end + + return false + end + + def make_destination_dirs(install_destdir) + lib_dir, bin_dir = Gem.default_rubygems_dirs + + unless lib_dir + lib_dir, bin_dir = generate_default_dirs(install_destdir) + end + + mkdir_p lib_dir + mkdir_p bin_dir + + return lib_dir, bin_dir + end + + def generate_default_dirs(install_destdir) + prefix = options[:prefix] + site_or_vendor = options[:site_or_vendor] + + if prefix.empty? then + lib_dir = RbConfig::CONFIG[site_or_vendor] + bin_dir = RbConfig::CONFIG['bindir'] + else + # Apple installed RubyGems into libdir, and RubyGems <= 1.1.0 gets + # confused about installation location, so switch back to + # sitelibdir/vendorlibdir. + if defined?(APPLE_GEM_HOME) and + # just in case Apple and RubyGems don't get this patched up proper. + (prefix == RbConfig::CONFIG['libdir'] or + # this one is important + prefix == File.join(RbConfig::CONFIG['libdir'], 'ruby')) then + lib_dir = RbConfig::CONFIG[site_or_vendor] + bin_dir = RbConfig::CONFIG['bindir'] + else + lib_dir = File.join prefix, 'lib' + bin_dir = File.join prefix, 'bin' + end + end + + unless install_destdir.empty? then + lib_dir = File.join install_destdir, lib_dir.gsub(/^[a-zA-Z]:/, '') + bin_dir = File.join install_destdir, bin_dir.gsub(/^[a-zA-Z]:/, '') + end + + [lib_dir, bin_dir] + end + + def pem_files_in dir + Dir.chdir dir do + Dir[File.join('**', '*pem')] + end + end + + def rb_files_in dir + Dir.chdir dir do + Dir[File.join('**', '*rb')] + end + end + + def remove_old_bin_files(bin_dir) + old_bin_files = { + 'gem_mirror' => 'gem mirror', + 'gem_server' => 'gem server', + 'gemlock' => 'gem lock', + 'gemri' => 'ri', + 'gemwhich' => 'gem which', + 'index_gem_repository.rb' => 'gem generate_index', + } + + old_bin_files.each do |old_bin_file, new_name| + old_bin_path = File.join bin_dir, old_bin_file + next unless File.exist? old_bin_path + + deprecation_message = "`#{old_bin_file}` has been deprecated. Use `#{new_name}` instead." + + File.open old_bin_path, 'w' do |fp| + fp.write <<-EOF +#!#{Gem.ruby} + +abort "#{deprecation_message}" + EOF + end + + next unless Gem.win_platform? + + File.open "#{old_bin_path}.bat", 'w' do |fp| + fp.puts %{@ECHO.#{deprecation_message}} + end + end + end + + def remove_old_lib_files lib_dir + rubygems_dir = File.join lib_dir, 'rubygems' + lib_files = rb_files_in 'lib/rubygems' + + old_lib_files = rb_files_in rubygems_dir + + to_remove = old_lib_files - lib_files + + to_remove.delete_if do |file| + file.start_with? 'defaults' + end + + Dir.chdir rubygems_dir do + to_remove.each do |file| + FileUtils.rm_f file + + warn "unable to remove old file #{file} please remove it by hand" if + File.exist? file + end + end + end + + def show_release_notes + release_notes = File.join Dir.pwd, 'History.txt' + + release_notes = + if File.exist? release_notes then + history = File.read release_notes + + history.force_encoding Encoding::UTF_8 if + Object.const_defined? :Encoding + + history = history.sub(/^# coding:.*?(?=^=)/m, '') + + text = history.split(HISTORY_HEADER) + text.shift # correct an off-by-one generated by split + version_lines = history.scan(HISTORY_HEADER) + versions = history.scan(VERSION_MATCHER).flatten.map do |x| + Gem::Version.new(x) + end + + history_string = "" + + until versions.length == 0 or + versions.shift < options[:previous_version] do + history_string += version_lines.shift + text.shift + end + + history_string + else + "Oh-no! Unable to find release notes!" + end + + say release_notes + end + + def uninstall_old_gemcutter + require 'rubygems/uninstaller' + + ui = Gem::Uninstaller.new('gemcutter', :all => true, :ignore => true, + :version => '< 0.4') + ui.uninstall + rescue Gem::InstallError + end + +end + diff --git a/jni/ruby/lib/rubygems/commands/sources_command.rb b/jni/ruby/lib/rubygems/commands/sources_command.rb new file mode 100644 index 0000000..81ff07b --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/sources_command.rb @@ -0,0 +1,210 @@ +require 'rubygems/command' +require 'rubygems/remote_fetcher' +require 'rubygems/spec_fetcher' +require 'rubygems/local_remote_options' + +class Gem::Commands::SourcesCommand < Gem::Command + + include Gem::LocalRemoteOptions + + def initialize + require 'fileutils' + + super 'sources', + 'Manage the sources and cache file RubyGems uses to search for gems' + + add_option '-a', '--add SOURCE_URI', 'Add source' do |value, options| + options[:add] = value + end + + add_option '-l', '--list', 'List sources' do |value, options| + options[:list] = value + end + + add_option '-r', '--remove SOURCE_URI', 'Remove source' do |value, options| + options[:remove] = value + end + + add_option '-c', '--clear-all', + 'Remove all sources (clear the cache)' do |value, options| + options[:clear_all] = value + end + + add_option '-u', '--update', 'Update source cache' do |value, options| + options[:update] = value + end + + add_proxy_option + end + + def add_source source_uri # :nodoc: + check_rubygems_https source_uri + + source = Gem::Source.new source_uri + + begin + if Gem.sources.include? source_uri then + say "source #{source_uri} already present in the cache" + else + source.load_specs :released + Gem.sources << source + Gem.configuration.write + + say "#{source_uri} added to sources" + end + rescue URI::Error, ArgumentError + say "#{source_uri} is not a URI" + terminate_interaction 1 + rescue Gem::RemoteFetcher::FetchError => e + say "Error fetching #{source_uri}:\n\t#{e.message}" + terminate_interaction 1 + end + end + + def check_rubygems_https source_uri # :nodoc: + uri = URI source_uri + + if uri.scheme and uri.scheme.downcase == 'http' and + uri.host.downcase == 'rubygems.org' then + question = <<-QUESTION.chomp +https://rubygems.org is recommended for security over #{uri} + +Do you want to add this insecure source? + QUESTION + + terminate_interaction 1 unless ask_yes_no question + end + end + + def clear_all # :nodoc: + path = Gem.spec_cache_dir + FileUtils.rm_rf path + + unless File.exist? path then + say "*** Removed specs cache ***" + else + unless File.writable? path then + say "*** Unable to remove source cache (write protected) ***" + else + say "*** Unable to remove source cache ***" + end + + terminate_interaction 1 + end + end + + def defaults_str # :nodoc: + '--list' + end + + def description # :nodoc: + <<-EOF +RubyGems fetches gems from the sources you have configured (stored in your +~/.gemrc). + +The default source is https://rubygems.org, but you may have older sources +configured. This guide will help you update your sources or configure +yourself to use your own gem server. + +Without any arguments the sources lists your currently configured sources: + + $ gem sources + *** CURRENT SOURCES *** + + https://rubygems.org + +This may list multiple sources or non-rubygems sources. You probably +configured them before or have an old `~/.gemrc`. If you have sources you +do not recognize you should remove them. + +RubyGems has been configured to serve gems via the following URLs through +its history: + +* http://gems.rubyforge.org (RubyGems 1.3.6 and earlier) +* http://rubygems.org (RubyGems 1.3.7 through 1.8.25) +* https://rubygems.org (RubyGems 2.0.1 and newer) + +Since all of these sources point to the same set of gems you only need one +of them in your list. https://rubygems.org is recommended as it brings the +protections of an SSL connection to gem downloads. + +To add a source use the --add argument: + + $ gem sources --add https://rubygems.org + https://rubygems.org added to sources + +RubyGems will check to see if gems can be installed from the source given +before it is added. + +To remove a source use the --remove argument: + + $ gem sources --remove http://rubygems.org + http://rubygems.org removed from sources + + EOF + end + + def list # :nodoc: + say "*** CURRENT SOURCES ***" + say + + Gem.sources.each do |src| + say src + end + end + + def list? # :nodoc: + !(options[:add] || + options[:clear_all] || + options[:remove] || + options[:update]) + end + + def execute + clear_all if options[:clear_all] + + source_uri = options[:add] + add_source source_uri if source_uri + + source_uri = options[:remove] + remove_source source_uri if source_uri + + update if options[:update] + + list if list? + end + + def remove_source source_uri # :nodoc: + unless Gem.sources.include? source_uri then + say "source #{source_uri} not present in cache" + else + Gem.sources.delete source_uri + Gem.configuration.write + + say "#{source_uri} removed from sources" + end + end + + def update # :nodoc: + Gem.sources.each_source do |src| + src.load_specs :released + src.load_specs :latest + end + + say "source cache successfully updated" + end + + def remove_cache_file desc, path # :nodoc: + FileUtils.rm_rf path + + if not File.exist?(path) then + say "*** Removed #{desc} source cache ***" + elsif not File.writable?(path) then + say "*** Unable to remove #{desc} source cache (write protected) ***" + else + say "*** Unable to remove #{desc} source cache ***" + end + end + +end + diff --git a/jni/ruby/lib/rubygems/commands/specification_command.rb b/jni/ruby/lib/rubygems/commands/specification_command.rb new file mode 100644 index 0000000..3bc02a9 --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/specification_command.rb @@ -0,0 +1,145 @@ +require 'rubygems/command' +require 'rubygems/local_remote_options' +require 'rubygems/version_option' +require 'rubygems/package' + +class Gem::Commands::SpecificationCommand < Gem::Command + + include Gem::LocalRemoteOptions + include Gem::VersionOption + + def initialize + Gem.load_yaml + + super 'specification', 'Display gem specification (in yaml)', + :domain => :local, :version => Gem::Requirement.default, + :format => :yaml + + add_version_option('examine') + add_platform_option + add_prerelease_option + + add_option('--all', 'Output specifications for all versions of', + 'the gem') do |value, options| + options[:all] = true + end + + add_option('--ruby', 'Output ruby format') do |value, options| + options[:format] = :ruby + end + + add_option('--yaml', 'Output YAML format') do |value, options| + options[:format] = :yaml + end + + add_option('--marshal', 'Output Marshal format') do |value, options| + options[:format] = :marshal + end + + add_local_remote_options + end + + def arguments # :nodoc: + <<-ARGS +GEMFILE name of gem to show the gemspec for +FIELD name of gemspec field to show + ARGS + end + + def defaults_str # :nodoc: + "--local --version '#{Gem::Requirement.default}' --yaml" + end + + def description # :nodoc: + <<-EOF +The specification command allows you to extract the specification from +a gem for examination. + +The specification can be output in YAML, ruby or Marshal formats. + +Specific fields in the specification can be extracted in YAML format: + + $ gem spec rake summary + --- Ruby based make-like utility. + ... + + EOF + end + + def usage # :nodoc: + "#{program_name} [GEMFILE] [FIELD]" + end + + def execute + specs = [] + gem = options[:args].shift + + unless gem then + raise Gem::CommandLineError, + "Please specify a gem name or file on the command line" + end + + case v = options[:version] + when String + req = Gem::Requirement.create v + when Gem::Requirement + req = v + else + raise Gem::CommandLineError, "Unsupported version type: '#{v}'" + end + + if !req.none? and options[:all] + alert_error "Specify --all or -v, not both" + terminate_interaction 1 + end + + if options[:all] + dep = Gem::Dependency.new gem + else + dep = Gem::Dependency.new gem, req + end + + field = get_one_optional_argument + + raise Gem::CommandLineError, "--ruby and FIELD are mutually exclusive" if + field and options[:format] == :ruby + + if local? then + if File.exist? gem then + specs << Gem::Package.new(gem).spec rescue nil + end + + if specs.empty? then + specs.push(*dep.matching_specs) + end + end + + if remote? then + dep.prerelease = options[:prerelease] + found, _ = Gem::SpecFetcher.fetcher.spec_for_dependency dep + + specs.push(*found.map { |spec,| spec }) + end + + if specs.empty? then + alert_error "No gem matching '#{dep}' found" + terminate_interaction 1 + end + + unless options[:all] then + specs = [specs.max_by { |s| s.version }] + end + + specs.each do |s| + s = s.send field if field + + say case options[:format] + when :ruby then s.to_ruby + when :marshal then Marshal.dump s + else s.to_yaml + end + + say "\n" + end + end +end diff --git a/jni/ruby/lib/rubygems/commands/stale_command.rb b/jni/ruby/lib/rubygems/commands/stale_command.rb new file mode 100644 index 0000000..0ef0755 --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/stale_command.rb @@ -0,0 +1,38 @@ +require 'rubygems/command' + +class Gem::Commands::StaleCommand < Gem::Command + def initialize + super('stale', 'List gems along with access times') + end + + def description # :nodoc: + <<-EOF +The stale command lists the latest access time for all the files in your +installed gems. + +You can use this command to discover gems and gem versions you are no +longer using. + EOF + end + + def usage # :nodoc: + "#{program_name}" + end + + def execute + gem_to_atime = {} + Gem::Specification.each do |spec| + name = spec.full_name + Dir["#{spec.full_gem_path}/**/*.*"].each do |file| + next if File.directory?(file) + stat = File.stat(file) + gem_to_atime[name] ||= stat.atime + gem_to_atime[name] = stat.atime if gem_to_atime[name] < stat.atime + end + end + + gem_to_atime.sort_by { |_, atime| atime }.each do |name, atime| + say "#{name} at #{atime.strftime '%c'}" + end + end +end diff --git a/jni/ruby/lib/rubygems/commands/uninstall_command.rb b/jni/ruby/lib/rubygems/commands/uninstall_command.rb new file mode 100644 index 0000000..9285e57 --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/uninstall_command.rb @@ -0,0 +1,164 @@ +require 'rubygems/command' +require 'rubygems/version_option' +require 'rubygems/uninstaller' +require 'fileutils' + +## +# Gem uninstaller command line tool +# +# See `gem help uninstall` + +class Gem::Commands::UninstallCommand < Gem::Command + + include Gem::VersionOption + + def initialize + super 'uninstall', 'Uninstall gems from the local repository', + :version => Gem::Requirement.default, :user_install => true, + :check_dev => false, :vendor => false + + add_option('-a', '--[no-]all', + 'Uninstall all matching versions' + ) do |value, options| + options[:all] = value + end + + add_option('-I', '--[no-]ignore-dependencies', + 'Ignore dependency requirements while', + 'uninstalling') do |value, options| + options[:ignore] = value + end + + add_option('-D', '--[no-]-check-development', + 'Check development dependencies while uninstalling', + '(default: false)') do |value, options| + options[:check_dev] = value + end + + add_option('-x', '--[no-]executables', + 'Uninstall applicable executables without', + 'confirmation') do |value, options| + options[:executables] = value + end + + add_option('-i', '--install-dir DIR', + 'Directory to uninstall gem from') do |value, options| + options[:install_dir] = File.expand_path(value) + end + + add_option('-n', '--bindir DIR', + 'Directory to remove binaries from') do |value, options| + options[:bin_dir] = File.expand_path(value) + end + + add_option('--[no-]user-install', + 'Uninstall from user\'s home directory', + 'in addition to GEM_HOME.') do |value, options| + options[:user_install] = value + end + + add_option('--[no-]format-executable', + 'Assume executable names match Ruby\'s prefix and suffix.') do |value, options| + options[:format_executable] = value + end + + add_option('--[no-]force', + 'Uninstall all versions of the named gems', + 'ignoring dependencies') do |value, options| + options[:force] = value + end + + add_option('--[no-]abort-on-dependent', + 'Prevent uninstalling gems that are', + 'depended on by other gems.') do |value, options| + options[:abort_on_dependent] = value + end + + add_version_option + add_platform_option + + add_option('--vendor', + 'Uninstall gem from the vendor directory.', + 'Only for use by gem repackagers.') do |value, options| + unless Gem.vendor_dir then + raise OptionParser::InvalidOption.new 'your platform is not supported' + end + + alert_warning 'Use your OS package manager to uninstall vendor gems' + options[:vendor] = true + options[:install_dir] = Gem.vendor_dir + end + end + + def arguments # :nodoc: + "GEMNAME name of gem to uninstall" + end + + def defaults_str # :nodoc: + "--version '#{Gem::Requirement.default}' --no-force " + + "--user-install" + end + + def description # :nodoc: + <<-EOF +The uninstall command removes a previously installed gem. + +RubyGems will ask for confirmation if you are attempting to uninstall a gem +that is a dependency of an existing gem. You can use the +--ignore-dependencies option to skip this check. + EOF + end + + def usage # :nodoc: + "#{program_name} GEMNAME [GEMNAME ...]" + end + + def execute + if options[:all] and not options[:args].empty? then + uninstall_specific + elsif options[:all] then + uninstall_all + else + uninstall_specific + end + end + + def uninstall_all + specs = Gem::Specification.reject { |spec| spec.default_gem? } + + specs.each do |spec| + options[:version] = spec.version + + begin + Gem::Uninstaller.new(spec.name, options).uninstall + rescue Gem::InstallError + end + end + + alert "Uninstalled all gems in #{options[:install_dir]}" + end + + def uninstall_specific + deplist = Gem::DependencyList.new + + get_all_gem_names.uniq.each do |name| + Gem::Specification.find_all_by_name(name).each do |spec| + deplist.add spec + end + end + + deps = deplist.strongly_connected_components.flatten.reverse + + deps.map(&:name).uniq.each do |gem_name| + begin + Gem::Uninstaller.new(gem_name, options).uninstall + rescue Gem::GemNotInHomeException => e + spec = e.spec + alert("In order to remove #{spec.name}, please execute:\n" + + "\tgem uninstall #{spec.name} --install-dir=#{spec.installation_path}") + end + end + end + +end + diff --git a/jni/ruby/lib/rubygems/commands/unpack_command.rb b/jni/ruby/lib/rubygems/commands/unpack_command.rb new file mode 100644 index 0000000..5a05ad0 --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/unpack_command.rb @@ -0,0 +1,182 @@ +require 'rubygems/command' +require 'rubygems/installer' +require 'rubygems/version_option' +require 'rubygems/remote_fetcher' + +class Gem::Commands::UnpackCommand < Gem::Command + + include Gem::VersionOption + + def initialize + require 'fileutils' + + super 'unpack', 'Unpack an installed gem to the current directory', + :version => Gem::Requirement.default, + :target => Dir.pwd + + add_option('--target=DIR', + 'target directory for unpacking') do |value, options| + options[:target] = value + end + + add_option('--spec', 'unpack the gem specification') do |value, options| + options[:spec] = true + end + + add_version_option + end + + def arguments # :nodoc: + "GEMNAME name of gem to unpack" + end + + def defaults_str # :nodoc: + "--version '#{Gem::Requirement.default}'" + end + + def description + <<-EOF +The unpack command allows you to examine the contents of a gem or modify +them to help diagnose a bug. + +You can add the contents of the unpacked gem to the load path using the +RUBYLIB environment variable or -I: + + $ gem unpack my_gem + Unpacked gem: '.../my_gem-1.0' + [edit my_gem-1.0/lib/my_gem.rb] + $ ruby -Imy_gem-1.0/lib -S other_program + +You can repackage an unpacked gem using the build command. See the build +command help for an example. + EOF + end + + def usage # :nodoc: + "#{program_name} GEMNAME" + end + + #-- + # TODO: allow, e.g., 'gem unpack rake-0.3.1'. Find a general solution for + # this, so that it works for uninstall as well. (And check other commands + # at the same time.) + + def execute + get_all_gem_names.each do |name| + dependency = Gem::Dependency.new name, options[:version] + path = get_path dependency + + unless path then + alert_error "Gem '#{name}' not installed nor fetchable." + next + end + + if @options[:spec] then + spec, metadata = get_metadata path + + if metadata.nil? then + alert_error "--spec is unsupported on '#{name}' (old format gem)" + next + end + + spec_file = File.basename spec.spec_file + + open spec_file, 'w' do |io| + io.write metadata + end + else + basename = File.basename path, '.gem' + target_dir = File.expand_path basename, options[:target] + + package = Gem::Package.new path + package.extract_files target_dir + + say "Unpacked gem: '#{target_dir}'" + end + end + end + + ## + # + # Find cached filename in Gem.path. Returns nil if the file cannot be found. + # + #-- + # TODO: see comments in get_path() about general service. + + def find_in_cache(filename) + Gem.path.each do |path| + this_path = File.join(path, "cache", filename) + return this_path if File.exist? this_path + end + + return nil + end + + ## + # Return the full path to the cached gem file matching the given + # name and version requirement. Returns 'nil' if no match. + # + # Example: + # + # get_path 'rake', '> 0.4' # "/usr/lib/ruby/gems/1.8/cache/rake-0.4.2.gem" + # get_path 'rake', '< 0.1' # nil + # get_path 'rak' # nil (exact name required) + #-- + # TODO: This should be refactored so that it's a general service. I don't + # think any of our existing classes are the right place though. Just maybe + # 'Cache'? + # + # TODO: It just uses Gem.dir for now. What's an easy way to get the list of + # source directories? + + def get_path dependency + return dependency.name if dependency.name =~ /\.gem$/i + + specs = dependency.matching_specs + + selected = specs.max_by { |s| s.version } + + return Gem::RemoteFetcher.fetcher.download_to_cache(dependency) unless + selected + + return unless dependency.name =~ /^#{selected.name}$/i + + # We expect to find (basename).gem in the 'cache' directory. Furthermore, + # the name match must be exact (ignoring case). + + path = find_in_cache File.basename selected.cache_file + + return Gem::RemoteFetcher.fetcher.download_to_cache(dependency) unless path + + path + end + + ## + # Extracts the Gem::Specification and raw metadata from the .gem file at + # +path+. + #-- + # TODO move to Gem::Package as #raw_spec or something + + def get_metadata path + format = Gem::Package.new path + spec = format.spec + + metadata = nil + + open path, Gem.binary_mode do |io| + tar = Gem::Package::TarReader.new io + tar.each_entry do |entry| + case entry.full_name + when 'metadata' then + metadata = entry.read + when 'metadata.gz' then + metadata = Gem.gunzip entry.read + end + end + end + + return spec, metadata + end + +end + diff --git a/jni/ruby/lib/rubygems/commands/update_command.rb b/jni/ruby/lib/rubygems/commands/update_command.rb new file mode 100644 index 0000000..001dd77 --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/update_command.rb @@ -0,0 +1,277 @@ +require 'rubygems/command' +require 'rubygems/command_manager' +require 'rubygems/dependency_installer' +require 'rubygems/install_update_options' +require 'rubygems/local_remote_options' +require 'rubygems/spec_fetcher' +require 'rubygems/version_option' +require 'rubygems/install_message' # must come before rdoc for messaging +require 'rubygems/rdoc' + +class Gem::Commands::UpdateCommand < Gem::Command + + include Gem::InstallUpdateOptions + include Gem::LocalRemoteOptions + include Gem::VersionOption + + attr_reader :installer # :nodoc: + + attr_reader :updated # :nodoc: + + def initialize + super 'update', 'Update installed gems to the latest version', + :document => %w[rdoc ri], + :force => false + + add_install_update_options + + OptionParser.accept Gem::Version do |value| + Gem::Version.new value + + value + end + + add_option('--system [VERSION]', Gem::Version, + 'Update the RubyGems system software') do |value, options| + value = true unless value + + options[:system] = value + end + + add_local_remote_options + add_platform_option + add_prerelease_option "as update targets" + + @updated = [] + @installer = nil + end + + def arguments # :nodoc: + "REGEXP regexp to search for in gem name" + end + + def defaults_str # :nodoc: + "--document --no-force --install-dir #{Gem.dir}" + end + + def description # :nodoc: + <<-EOF +The update command will update your gems to the latest version. + +The update command does not remove the previous version. Use the cleanup +command to remove old versions. + EOF + end + + def usage # :nodoc: + "#{program_name} REGEXP [REGEXP ...]" + end + + def check_latest_rubygems version # :nodoc: + if Gem.rubygems_version == version then + say "Latest version currently installed. Aborting." + terminate_interaction + end + + options[:user_install] = false + end + + def check_update_arguments # :nodoc: + unless options[:args].empty? then + alert_error "Gem names are not allowed with the --system option" + terminate_interaction 1 + end + end + + def execute + if options[:system] then + update_rubygems + return + end + + say "Updating installed gems" + + hig = highest_installed_gems + + gems_to_update = which_to_update hig, options[:args].uniq + + updated = update_gems gems_to_update + + updated_names = updated.map { |spec| spec.name } + not_updated_names = options[:args].uniq - updated_names + + if updated.empty? then + say "Nothing to update" + else + say "Gems updated: #{updated_names.join(' ')}" + say "Gems already up-to-date: #{not_updated_names.join(' ')}" unless not_updated_names.empty? + end + end + + def fetch_remote_gems spec # :nodoc: + dependency = Gem::Dependency.new spec.name, "> #{spec.version}" + dependency.prerelease = options[:prerelease] + + fetcher = Gem::SpecFetcher.fetcher + + spec_tuples, errors = fetcher.search_for_dependency dependency + + error = errors.find { |e| e.respond_to? :exception } + + raise error if error + + spec_tuples + end + + def highest_installed_gems # :nodoc: + hig = {} # highest installed gems + + Gem::Specification.each do |spec| + if hig[spec.name].nil? or hig[spec.name].version < spec.version then + hig[spec.name] = spec + end + end + + hig + end + + def highest_remote_version spec # :nodoc: + spec_tuples = fetch_remote_gems spec + + matching_gems = spec_tuples.select do |g,_| + g.name == spec.name and g.match_platform? + end + + highest_remote_gem = matching_gems.max_by { |g,_| g.version } + + highest_remote_gem ||= [Gem::NameTuple.null] + + highest_remote_gem.first.version + end + + def install_rubygems version # :nodoc: + args = update_rubygems_arguments + + update_dir = File.join Gem.dir, 'gems', "rubygems-update-#{version}" + + Dir.chdir update_dir do + say "Installing RubyGems #{version}" + + # Make sure old rubygems isn't loaded + old = ENV["RUBYOPT"] + ENV.delete("RUBYOPT") if old + installed = system Gem.ruby, 'setup.rb', *args + say "RubyGems system software updated" if installed + ENV["RUBYOPT"] = old if old + end + end + + def rubygems_target_version + version = options[:system] + update_latest = version == true + + if update_latest then + version = Gem::Version.new Gem::VERSION + requirement = Gem::Requirement.new ">= #{Gem::VERSION}" + else + version = Gem::Version.new version + requirement = Gem::Requirement.new version + end + + rubygems_update = Gem::Specification.new + rubygems_update.name = 'rubygems-update' + rubygems_update.version = version + + hig = { + 'rubygems-update' => rubygems_update + } + + gems_to_update = which_to_update hig, options[:args], :system + _, up_ver = gems_to_update.first + + target = if update_latest then + up_ver + else + version + end + + return target, requirement + end + + def update_gem name, version = Gem::Requirement.default + return if @updated.any? { |spec| spec.name == name } + + update_options = options.dup + update_options[:prerelease] = version.prerelease? + + @installer = Gem::DependencyInstaller.new update_options + + say "Updating #{name}" + begin + @installer.install name, Gem::Requirement.new(version) + rescue Gem::InstallError, Gem::DependencyError => e + alert_error "Error installing #{name}:\n\t#{e.message}" + end + + @installer.installed_gems.each do |spec| + @updated << spec + end + end + + def update_gems gems_to_update + gems_to_update.uniq.sort.each do |(name, version)| + update_gem name, version + end + + @updated + end + + ## + # Update RubyGems software to the latest version. + + def update_rubygems + check_update_arguments + + version, requirement = rubygems_target_version + + check_latest_rubygems version + + update_gem 'rubygems-update', version + + installed_gems = Gem::Specification.find_all_by_name 'rubygems-update', requirement + version = installed_gems.last.version + + install_rubygems version + end + + def update_rubygems_arguments # :nodoc: + args = [] + args << '--prefix' << Gem.prefix if Gem.prefix + # TODO use --document for >= 1.9 , --no-rdoc --no-ri < 1.9 + args << '--no-rdoc' unless options[:document].include? 'rdoc' + args << '--no-ri' unless options[:document].include? 'ri' + args << '--no-format-executable' if options[:no_format_executable] + args << '--previous-version' << Gem::VERSION if + options[:system] == true or + Gem::Version.new(options[:system]) >= Gem::Version.new(2) + args + end + + def which_to_update highest_installed_gems, gem_names, system = false + result = [] + + highest_installed_gems.each do |l_name, l_spec| + next if not gem_names.empty? and + gem_names.none? { |name| name == l_spec.name } + + highest_remote_ver = highest_remote_version l_spec + + if system or (l_spec.version < highest_remote_ver) then + result << [l_spec.name, [l_spec.version, highest_remote_ver].max] + end + end + + result + end + +end diff --git a/jni/ruby/lib/rubygems/commands/which_command.rb b/jni/ruby/lib/rubygems/commands/which_command.rb new file mode 100644 index 0000000..96eeb86 --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/which_command.rb @@ -0,0 +1,90 @@ +require 'rubygems/command' + +class Gem::Commands::WhichCommand < Gem::Command + def initialize + super 'which', 'Find the location of a library file you can require', + :search_gems_first => false, :show_all => false + + add_option '-a', '--[no-]all', 'show all matching files' do |show_all, options| + options[:show_all] = show_all + end + + add_option '-g', '--[no-]gems-first', + 'search gems before non-gems' do |gems_first, options| + options[:search_gems_first] = gems_first + end + end + + def arguments # :nodoc: + "FILE name of file to find" + end + + def defaults_str # :nodoc: + "--no-gems-first --no-all" + end + + def description # :nodoc: + <<-EOF +The which command is like the shell which command and shows you where +the file you wish to require lives. + +You can use the which command to help determine why you are requiring a +version you did not expect or to look at the content of a file you are +requiring to see why it does not behave as you expect. + EOF + end + + def execute + found = true + + options[:args].each do |arg| + arg = arg.sub(/#{Regexp.union(*Gem.suffixes)}$/, '') + dirs = $LOAD_PATH + + spec = Gem::Specification.find_by_path arg + + if spec then + if options[:search_gems_first] then + dirs = spec.full_require_paths + $LOAD_PATH + else + dirs = $LOAD_PATH + spec.full_require_paths + end + end + + # TODO: this is totally redundant and stupid + paths = find_paths arg, dirs + + if paths.empty? then + alert_error "Can't find ruby library file or shared library #{arg}" + + found &&= false + else + say paths + end + end + + terminate_interaction 1 unless found + end + + def find_paths(package_name, dirs) + result = [] + + dirs.each do |dir| + Gem.suffixes.each do |ext| + full_path = File.join dir, "#{package_name}#{ext}" + if File.exist? full_path and not File.directory? full_path then + result << full_path + return result unless options[:show_all] + end + end + end + + result + end + + def usage # :nodoc: + "#{program_name} FILE [FILE ...]" + end + +end + diff --git a/jni/ruby/lib/rubygems/commands/yank_command.rb b/jni/ruby/lib/rubygems/commands/yank_command.rb new file mode 100644 index 0000000..3c7859e --- /dev/null +++ b/jni/ruby/lib/rubygems/commands/yank_command.rb @@ -0,0 +1,107 @@ +require 'rubygems/command' +require 'rubygems/local_remote_options' +require 'rubygems/version_option' +require 'rubygems/gemcutter_utilities' + +class Gem::Commands::YankCommand < Gem::Command + include Gem::LocalRemoteOptions + include Gem::VersionOption + include Gem::GemcutterUtilities + + def description # :nodoc: + <<-EOF +The yank command removes a gem you pushed to a server from the server's +index. + +Note that if you push a gem to rubygems.org the yank command does not +prevent other people from downloading the gem via the download link. + +Once you have pushed a gem several downloads will happen automatically +via the webhooks. If you accidentally pushed passwords or other sensitive +data you will need to change them immediately and yank your gem. + +If you are yanking a gem due to intellectual property reasons contact +http://help.rubygems.org for permanant removal. Be sure to mention this +as the reason for the removal request. + EOF + end + + def arguments # :nodoc: + "GEM name of gem" + end + + def usage # :nodoc: + "#{program_name} GEM -v VERSION [-p PLATFORM] [--undo] [--key KEY_NAME]" + end + + def initialize + super 'yank', 'Remove a pushed gem from the index' + + add_version_option("remove") + add_platform_option("remove") + + add_option('--undo') do |value, options| + options[:undo] = true + end + + add_key_option + end + + def execute + sign_in + + version = get_version_from_requirements(options[:version]) + platform = get_platform_from_requirements(options) + + if version then + if options[:undo] then + unyank_gem(version, platform) + else + yank_gem(version, platform) + end + else + say "A version argument is required: #{usage}" + terminate_interaction + end + end + + def yank_gem(version, platform) + say "Yanking gem from #{self.host}..." + yank_api_request(:delete, version, platform, "api/v1/gems/yank") + end + + def unyank_gem(version, platform) + say "Unyanking gem from #{host}..." + yank_api_request(:put, version, platform, "api/v1/gems/unyank") + end + + private + + def yank_api_request(method, version, platform, api) + name = get_one_gem_name + response = rubygems_api_request(method, api) do |request| + request.add_field("Authorization", api_key) + + data = { + 'gem_name' => name, + 'version' => version, + } + data['platform'] = platform if platform + + request.set_form_data data + end + say response.body + end + + def get_version_from_requirements(requirements) + requirements.requirements.first[1].version + rescue + nil + end + + def get_platform_from_requirements(requirements) + Gem.platforms[1].to_s if requirements.key? :added_platform + end + +end + |