diff options
author | drbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2007-12-20 08:39:12 +0000 |
---|---|---|
committer | drbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2007-12-20 08:39:12 +0000 |
commit | dcf06bd39ea72acbc312758e2df764c4b982b40c (patch) | |
tree | f6d367888b42848fd6a660fad57fa2020e38c097 /lib/rubygems | |
parent | eb954f44e53ba18225a0e906891c47373ce0d651 (diff) | |
download | ruby-dcf06bd39ea72acbc312758e2df764c4b982b40c.tar.gz ruby-dcf06bd39ea72acbc312758e2df764c4b982b40c.tar.xz ruby-dcf06bd39ea72acbc312758e2df764c4b982b40c.zip |
Import RubyGems 1.0.0, r1575
git-svn-id: http://svn.ruby-lang.org/repos/ruby/trunk@14361 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/rubygems')
24 files changed, 415 insertions, 426 deletions
diff --git a/lib/rubygems/commands/install_command.rb b/lib/rubygems/commands/install_command.rb index 4c67c0487..aa9f480c2 100644 --- a/lib/rubygems/commands/install_command.rb +++ b/lib/rubygems/commands/install_command.rb @@ -17,6 +17,7 @@ class Gem::Commands::InstallCommand < Gem::Command :generate_rdoc => true, :generate_ri => true, :install_dir => Gem.dir, + :format_executable => false, :test => false, :version => Gem::Requirement.default, }) @@ -56,6 +57,7 @@ class Gem::Commands::InstallCommand < Gem::Command :env_shebang => options[:env_shebang], :domain => options[:domain], :force => options[:force], + :format_executable => options[:format_executable], :ignore_dependencies => options[:ignore_dependencies], :install_dir => options[:install_dir], :security_policy => options[:security_policy], diff --git a/lib/rubygems/commands/mirror_command.rb b/lib/rubygems/commands/mirror_command.rb index 74f6970e9..fc4f086ad 100644 --- a/lib/rubygems/commands/mirror_command.rb +++ b/lib/rubygems/commands/mirror_command.rb @@ -60,10 +60,16 @@ Multiple sources and destinations may be specified. if get_from.scheme.nil? then get_from = get_from.to_s elsif get_from.scheme == 'file' then - get_from = get_from.to_s[5..-1] + # check if specified URI contains a drive letter (file:/D:/Temp) + get_from = get_from.to_s + get_from = if get_from =~ /^file:.*[a-z]:/i then + get_from[6..-1] + else + get_from[5..-1] + end end - open File.join(get_from, "Marshal.#{Gem.marshal_version}.Z"), "rb" do |y| + open File.join(get_from.to_s, "Marshal.#{Gem.marshal_version}.Z"), "rb" do |y| sourceindex_data = Zlib::Inflate.inflate y.read open File.join(save_to, "Marshal.#{Gem.marshal_version}"), "wb" do |out| out.write sourceindex_data diff --git a/lib/rubygems/commands/query_command.rb b/lib/rubygems/commands/query_command.rb index 581d4bb73..4f957625e 100644 --- a/lib/rubygems/commands/query_command.rb +++ b/lib/rubygems/commands/query_command.rb @@ -82,8 +82,10 @@ class Gem::Commands::QueryCommand < Gem::Command end entry = gem_name.dup + if options[:versions] then - entry << " (#{list_of_matching.map{|gem| gem.version.to_s}.join(", ")})" + versions = list_of_matching.map { |s| s.version }.uniq + entry << " (#{versions.join ', '})" end entry << "\n" << format_text(list_of_matching[0].summary, 68, 4) if diff --git a/lib/rubygems/commands/server_command.rb b/lib/rubygems/commands/server_command.rb index 34e5e46fe..992ae1c8f 100644 --- a/lib/rubygems/commands/server_command.rb +++ b/lib/rubygems/commands/server_command.rb @@ -7,17 +7,17 @@ class Gem::Commands::ServerCommand < Gem::Command super 'server', 'Documentation and gem repository HTTP server', :port => 8808, :gemdir => Gem.dir, :daemon => false - add_option '-p', '--port=PORT', + add_option '-p', '--port=PORT', Integer, 'port to listen on' do |port, options| options[:port] = port end add_option '-d', '--dir=GEMDIR', 'directory from which to serve gems' do |gemdir, options| - options[:gemdir] = gemdir + options[:gemdir] = File.expand_path gemdir end - add_option '--[no]-daemon', 'run as a daemon' do |daemon, options| + add_option '--[no-]daemon', 'run as a daemon' do |daemon, options| options[:daemon] = daemon end end diff --git a/lib/rubygems/commands/unpack_command.rb b/lib/rubygems/commands/unpack_command.rb index ece24745a..23ebabc21 100644 --- a/lib/rubygems/commands/unpack_command.rb +++ b/lib/rubygems/commands/unpack_command.rb @@ -9,7 +9,13 @@ class Gem::Commands::UnpackCommand < Gem::Command def initialize super 'unpack', 'Unpack an installed gem to the current directory', - :version => Gem::Requirement.default + :version => Gem::Requirement.default, + :target => Dir.pwd + + add_option('--target', 'target directory for unpacking') do |value, options| + options[:target] = value + end + add_version_option end @@ -32,10 +38,11 @@ class Gem::Commands::UnpackCommand < Gem::Command def execute gemname = get_one_gem_name path = get_path(gemname, options[:version]) - if path - target_dir = File.basename(path).sub(/\.gem$/, '') + if path then + basename = File.basename(path).sub(/\.gem$/, '') + target_dir = File.expand_path File.join(options[:target], basename) FileUtils.mkdir_p target_dir - Gem::Installer.new(path).unpack(File.expand_path(target_dir)) + Gem::Installer.new(path).unpack target_dir say "Unpacked gem: '#{target_dir}'" else alert_error "Gem '#{gemname}' not installed." diff --git a/lib/rubygems/commands/update_command.rb b/lib/rubygems/commands/update_command.rb index e17ba2516..7a11ec955 100644 --- a/lib/rubygems/commands/update_command.rb +++ b/lib/rubygems/commands/update_command.rb @@ -4,146 +4,152 @@ require 'rubygems/local_remote_options' require 'rubygems/source_info_cache' require 'rubygems/version_option' -module Gem - module Commands - class UpdateCommand < Command +class Gem::Commands::UpdateCommand < Gem::Command - include Gem::InstallUpdateOptions - include Gem::LocalRemoteOptions - include Gem::VersionOption + include Gem::InstallUpdateOptions + include Gem::LocalRemoteOptions + include Gem::VersionOption - def initialize - super( - 'update', + def initialize + super 'update', 'Update the named gems (or all installed gems) in the local repository', - { - :generate_rdoc => true, - :generate_ri => true, - :force => false, - :test => false, - :install_dir => Gem.dir - }) - - add_install_update_options - - add_option('--system', - 'Update the RubyGems system software') do |value, options| - options[:system] = value - end + :generate_rdoc => true, + :generate_ri => true, + :force => false, + :test => false, + :install_dir => Gem.dir - add_local_remote_options + add_install_update_options - add_platform_option - end + add_option('--system', + 'Update the RubyGems system software') do |value, options| + options[:system] = value + end - def arguments # :nodoc: - "GEMNAME name of gem to update" - end + add_local_remote_options - def defaults_str # :nodoc: - "--rdoc --ri --no-force --no-test\n" + - "--install-dir #{Gem.dir}" - end + add_platform_option + end + + def arguments # :nodoc: + "GEMNAME name of gem to update" + end - def usage # :nodoc: - "#{program_name} GEMNAME [GEMNAME ...]" + def defaults_str # :nodoc: + "--rdoc --ri --no-force --no-test --install-dir #{Gem.dir}" + end + + def usage # :nodoc: + "#{program_name} GEMNAME [GEMNAME ...]" + end + + def execute + if options[:system] then + say "Updating RubyGems..." + + unless options[:args].empty? then + fail "No gem names are allowed with the --system option" end - def execute - if options[:system] then - say "Updating RubyGems..." + options[:args] = ["rubygems-update"] + else + say "Updating installed gems..." + end - unless options[:args].empty? then - fail "No gem names are allowed with the --system option" - end + hig = highest_installed_gems = {} - options[:args] = ["rubygems-update"] - else - say "Updating installed gems..." - end + Gem::SourceIndex.from_installed_gems.each do |name, spec| + if hig[spec.name].nil? or hig[spec.name].version < spec.version then + hig[spec.name] = spec + end + end - hig = highest_installed_gems = {} + remote_gemspecs = Gem::SourceInfoCache.search(//) - Gem::SourceIndex.from_installed_gems.each do |name, spec| - if hig[spec.name].nil? or hig[spec.name].version < spec.version - hig[spec.name] = spec - end - end + gems_to_update = if options[:args].empty? then + which_to_update(highest_installed_gems, remote_gemspecs) + else + options[:args] + end - remote_gemspecs = Gem::SourceInfoCache.search(//) + options[:domain] = :remote # install from remote source - gems_to_update = if options[:args].empty? then - which_to_update(highest_installed_gems, remote_gemspecs) - else - options[:args] - end + # HACK use the real API + install_command = Gem::CommandManager.instance['install'] - options[:domain] = :remote # install from remote source + gems_to_update.uniq.sort.each do |name| + say "Attempting remote update of #{name}" + options[:args] = [name] + options[:ignore_dependencies] = true # HACK skip seen gems instead + install_command.merge_options(options) + install_command.execute + end - # HACK use the real API - install_command = Gem::CommandManager.instance['install'] + if gems_to_update.include? "rubygems-update" then + latest_ruby_gem = remote_gemspecs.select do |s| + s.name == 'rubygems-update' + end - gems_to_update.uniq.sort.each do |name| - say "Attempting remote update of #{name}" - options[:args] = [name] - options[:ignore_dependencies] = true # HACK skip seen gems instead - install_command.merge_options(options) - install_command.execute - end + latest_ruby_gem = latest_ruby_gem.sort_by { |s| s.version }.last - if gems_to_update.include?("rubygems-update") then - latest_ruby_gem = remote_gemspecs.select { |s| - s.name == 'rubygems-update' - }.sort_by { |s| - s.version - }.last + say "Updating version of RubyGems to #{latest_ruby_gem.version}" + installed = do_rubygems_update latest_ruby_gem.version - say "Updating version of RubyGems to #{latest_ruby_gem.version}" - installed = do_rubygems_update(latest_ruby_gem.version.to_s) + say "RubyGems system software updated" if installed + else + updated = gems_to_update.uniq.sort.collect { |g| g.to_s } - say "RubyGems system software updated" if installed - else - say "Gems: [#{gems_to_update.uniq.sort.collect{|g| g.to_s}.join(', ')}] updated" - end + if updated.empty? then + say "Nothing to update" + else + say "Gems updated: #{updated.join ', '}" end + end + end - def do_rubygems_update(version_string) - args = [] - args.push '--prefix', Gem.prefix unless Gem.prefix.nil? - args << '--no-rdoc' unless options[:generate_rdoc] - args << '--no-ri' unless options[:generate_ri] + def do_rubygems_update(version) + args = [] + args.push '--prefix', Gem.prefix unless Gem.prefix.nil? + args << '--no-rdoc' unless options[:generate_rdoc] + args << '--no-ri' unless options[:generate_ri] - update_dir = File.join(Gem.dir, 'gems', - "rubygems-update-#{version_string}") + update_dir = File.join Gem.dir, 'gems', "rubygems-update-#{version}" - success = false + success = false - Dir.chdir update_dir do - say "Installing RubyGems #{version_string}" - setup_cmd = "#{Gem.ruby} setup.rb #{args.join ' '}" + Dir.chdir update_dir do + say "Installing RubyGems #{version}" + setup_cmd = "#{Gem.ruby} setup.rb #{args.join ' '}" - # Make sure old rubygems isn't loaded - if Gem.win_platform? then - system "set RUBYOPT= & #{setup_cmd}" - else - system "RUBYOPT=\"\" #{setup_cmd}" - end - end + # Make sure old rubygems isn't loaded + if Gem.win_platform? then + system "set RUBYOPT= & #{setup_cmd}" + else + system "RUBYOPT=\"\" #{setup_cmd}" end + end + end + + def which_to_update(highest_installed_gems, remote_gemspecs) + result = [] - def which_to_update(highest_installed_gems, remote_gemspecs) - result = [] - highest_installed_gems.each do |l_name, l_spec| - highest_remote_gem = - remote_gemspecs.select { |spec| spec.name == l_name }. - sort_by { |spec| spec.version }. - last - if highest_remote_gem and l_spec.version < highest_remote_gem.version - result << l_name - end + highest_installed_gems.each do |l_name, l_spec| + matching_gems = remote_gemspecs.select do |spec| + spec.name == l_name and Gem.platforms.any? do |platform| + platform == spec.platform end - result + end + + highest_remote_gem = matching_gems.sort_by { |spec| spec.version }.last + + if highest_remote_gem and + l_spec.version < highest_remote_gem.version then + result << l_name end end + + result end + end + diff --git a/lib/rubygems/defaults.rb b/lib/rubygems/defaults.rb new file mode 100644 index 000000000..3a6229511 --- /dev/null +++ b/lib/rubygems/defaults.rb @@ -0,0 +1,46 @@ +module Gem + + # An Array of the default sources that come with RubyGems. + def self.default_sources + %w[http://gems.rubyforge.org] + end + + # Default home directory path to be used if an alternate value is not + # specified in the environment. + def self.default_dir + if defined? RUBY_FRAMEWORK_VERSION then + File.join File.dirname(ConfigMap[:sitedir]), 'Gems', + ConfigMap[:ruby_version] + else + File.join ConfigMap[:libdir], 'ruby', 'gems', ConfigMap[:ruby_version] + end + end + + # Default gem path. + def self.default_path + default_dir + end + + # Deduce Ruby's --program-prefix and --program-suffix from its install name. + def self.default_exec_format + baseruby = ConfigMap[:BASERUBY] || 'ruby' + ConfigMap[:RUBY_INSTALL_NAME].sub(baseruby, '%s') rescue '%s' + end + + # The default directory for binaries + def self.default_bindir + Config::CONFIG['bindir'] + end + + # The default system-wide source info cache directory. + def self.default_system_source_cache_dir + File.join Gem.dir, 'source_cache' + end + + # The default user-specific source info cache directory. + def self.default_user_source_cache_dir + File.join Gem.user_home, '.gem', 'source_cache' + end + +end + diff --git a/lib/rubygems/dependency_installer.rb b/lib/rubygems/dependency_installer.rb index e189e800a..ec8a50d91 100644 --- a/lib/rubygems/dependency_installer.rb +++ b/lib/rubygems/dependency_installer.rb @@ -15,8 +15,9 @@ class Gem::DependencyInstaller :env_shebang => false, :domain => :both, # HACK dup :force => false, + :format_executable => false, # HACK dup :ignore_dependencies => false, - :security_policy => Gem::Security::NoSecurity, # HACK AlmostNo? Low? + :security_policy => nil, # HACK NoSecurity requires OpenSSL. AlmostNo? Low? :wrappers => true } @@ -30,6 +31,7 @@ class Gem::DependencyInstaller # current directory. :remote searches only gems in Gem::sources. # :both searches both. # :force:: See Gem::Installer#install. + # :format_executable:: See Gem::Installer#initialize. # :ignore_dependencies: Don't install any dependencies. # :install_dir: See Gem::Installer#install. # :security_policy: See Gem::Installer::new and Gem::Security. @@ -39,6 +41,7 @@ class Gem::DependencyInstaller @env_shebang = options[:env_shebang] @domain = options[:domain] @force = options[:force] + @format_executable = options[:format_executable] @ignore_dependencies = options[:ignore_dependencies] @install_dir = options[:install_dir] || Gem.dir @security_policy = options[:security_policy] @@ -48,7 +51,14 @@ class Gem::DependencyInstaller spec_and_source = nil - local_gems = Dir["#{gem_name}*"].sort.reverse + glob = if File::ALT_SEPARATOR then + gem_name.gsub File::ALT_SEPARATOR, File::SEPARATOR + else + gem_name + end + + local_gems = Dir["#{glob}*"].sort.reverse + unless local_gems.empty? then local_gems.each do |gem_file| next unless gem_file =~ /gem$/ @@ -217,6 +227,7 @@ class Gem::DependencyInstaller inst = Gem::Installer.new local_gem_path, :env_shebang => @env_shebang, :force => @force, + :format_executable => @format_executable, :ignore_dependencies => @ignore_dependencies, :install_dir => @install_dir, :security_policy => @security_policy, diff --git a/lib/rubygems/indexer.rb b/lib/rubygems/indexer.rb index dc94f51b1..272cee3fd 100644 --- a/lib/rubygems/indexer.rb +++ b/lib/rubygems/indexer.rb @@ -98,7 +98,7 @@ class Gem::Indexer files = @master_index.files + @quick_index.files + @marshal_index.files files.each do |file| - relative_name = file[/\A#{@directory}.(.*)/, 1] + relative_name = file[/\A#{Regexp.escape @directory}.(.*)/, 1] dest_name = File.join @dest_directory, relative_name FileUtils.rm_rf dest_name, :verbose => verbose diff --git a/lib/rubygems/install_update_options.rb b/lib/rubygems/install_update_options.rb index 01c3a8af2..b93e21551 100644 --- a/lib/rubygems/install_update_options.rb +++ b/lib/rubygems/install_update_options.rb @@ -76,6 +76,13 @@ module Gem::InstallUpdateOptions 'dependent gems') do |value, options| options[:include_dependencies] = value end + + add_option(:"Install/Update", '--[no-]format-executable', + 'Make installed executable names match ruby.', + 'If ruby is ruby18, foo_exec will be', + 'foo_exec18') do |value, options| + options[:format_executable] = value + end end # Default options for the gem install command. diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb index 46d0144a8..e652ac9c6 100644 --- a/lib/rubygems/installer.rb +++ b/lib/rubygems/installer.rb @@ -28,9 +28,20 @@ class Gem::Installer class ExtensionBuildError < Gem::InstallError; end include Gem::UserInteraction - + include Gem::RequirePathsBuilder + class << self + + attr_writer :exec_format + + # Defaults to use Ruby's program prefix and suffix. + def exec_format + @exec_format ||= Gem.default_exec_format + end + + end + ## # Constructs an Installer instance that will install the gem located at # +gem+. +options+ is a Hash with the following keys: @@ -40,18 +51,26 @@ class Gem::Installer # for a signed-gems-only policy. # :ignore_dependencies:: Don't raise if a dependency is missing. # :install_dir:: The directory to install the gem into. + # :format_executable:: Format the executable the same as the ruby executable. + # If your ruby is ruby18, foo_exec will be installed as + # foo_exec18. # :security_policy:: Use the specified security policy. See Gem::Security # :wrappers:: Install wrappers if true, symlinks if false. def initialize(gem, options={}) @gem = gem - options = { :force => false, :install_dir => Gem.dir }.merge options + options = { + :force => false, + :install_dir => Gem.dir, + :exec_format => false, + }.merge options @env_shebang = options[:env_shebang] @force = options[:force] gem_home = options[:install_dir] @gem_home = Pathname.new(gem_home).expand_path @ignore_dependencies = options[:ignore_dependencies] + @format_executable = options[:format_executable] @security_policy = options[:security_policy] @wrappers = options[:wrappers] @@ -114,7 +133,7 @@ class Gem::Installer generate_bin build_extensions write_spec - + write_require_paths_file_if_needed # HACK remove? Isn't this done in multiple places? @@ -190,9 +209,12 @@ class Gem::Installer def generate_windows_script(bindir, filename) if Gem.win_platform? then script_name = filename + ".bat" - File.open(File.join(bindir, File.basename(script_name)), "w") do |file| + script_path = File.join bindir, File.basename(script_name) + File.open script_path, 'w' do |file| file.puts windows_stub_script(bindir, filename) end + + say script_path if Gem.configuration.really_verbose end end @@ -209,7 +231,7 @@ class Gem::Installer @spec.executables.each do |filename| filename.untaint - bin_path = File.join @gem_dir, 'bin', filename + bin_path = File.expand_path File.join(@gem_dir, @spec.bindir, filename) mode = File.stat(bin_path).mode | 0111 File.chmod mode, bin_path @@ -229,10 +251,24 @@ class Gem::Installer # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/193379 # def generate_bin_script(filename, bindir) - File.open(File.join(bindir, File.basename(filename)), "w", 0755) do |file| - file.print app_script_text(filename) - end - generate_windows_script bindir, filename + bin_script_path = File.join bindir, formatted_program_filename(filename) + + exec_path = File.join @gem_dir, @spec.bindir, filename + + # HACK some gems don't have #! in their executables, restore 2008/06 + #if File.read(exec_path, 2) == '#!' then + File.open bin_script_path, 'w', 0755 do |file| + file.print app_script_text(filename) + end + + say bin_script_path if Gem.configuration.really_verbose + + generate_windows_script bindir, filename + #else + # FileUtils.rm_f bin_script_path + # FileUtils.cp exec_path, bin_script_path, + # :verbose => Gem.configuration.really_verbose + #end end ## @@ -247,7 +283,7 @@ class Gem::Installer end src = File.join @gem_dir, 'bin', filename - dst = File.join bindir, File.basename(filename) + dst = File.join bindir, formatted_program_filename(filename) if File.exist? dst then if File.symlink? dst then @@ -258,7 +294,7 @@ class Gem::Installer File.unlink dst end - File.symlink src, dst + FileUtils.symlink src, dst, :verbose => Gem.configuration.really_verbose end ## @@ -351,6 +387,9 @@ TEXT begin Dir.chdir File.join(@gem_dir, File.dirname(extension)) results = builder.build(extension, @gem_dir, dest_path, results) + + say results.join("\n") if Gem.configuration.really_verbose + rescue => ex results = results.join "\n" @@ -402,6 +441,17 @@ Results logged to #{File.join(Dir.pwd, 'gem_make.out')} File.open(path, "wb") do |out| out.write file_data end + + say path if Gem.configuration.really_verbose + end + end + + # Prefix and suffix the program filename the same as ruby. + def formatted_program_filename(filename) + if @format_executable then + self.class.exec_format % File.basename(filename) + else + filename end end diff --git a/lib/rubygems/package.rb b/lib/rubygems/package.rb index b613b7fa0..ee136b626 100644 --- a/lib/rubygems/package.rb +++ b/lib/rubygems/package.rb @@ -142,6 +142,7 @@ module Gem::Package end def calculate_checksum(hdr) + #hdr.split('').map { |c| c[0] }.inject { |a, b| a + b } # HACK rubinius hdr.unpack("C*").inject{|a,b| a+b} end diff --git a/lib/rubygems/platform.rb b/lib/rubygems/platform.rb index 496c4b1fb..7abc15ef9 100644 --- a/lib/rubygems/platform.rb +++ b/lib/rubygems/platform.rb @@ -12,6 +12,23 @@ class Gem::Platform attr_accessor :version + DEPRECATED_CONSTS = [ + :DARWIN, + :LINUX_586, + :MSWIN32, + :PPC_DARWIN, + :WIN32, + :X86_LINUX + ] + + def self.const_missing(name) # TODO remove six months from 2007/12 + if DEPRECATED_CONSTS.include? name then + raise NameError, "#{name} has been removed, use CURRENT instead" + else + super + end + end + def self.local arch = Gem::ConfigMap[:arch] arch = "#{arch}_60" if arch =~ /mswin32$/ @@ -160,33 +177,5 @@ class Gem::Platform CURRENT = 'current' - ## - # A One Click Installer-compatible gem, built with VC6 for 32 bit Windows. - # - # CURRENT is preferred over this constant, avoid its use at all costs. - - MSWIN32 = new ['x86', 'mswin32', '60'] - - ## - # An x86 Linux-compatible gem - # - # CURRENT is preferred over this constant, avoid its use at all costs. - - X86_LINUX = new ['x86', 'linux', nil] - - ## - # A PowerPC Darwin-compatible gem - # - # CURRENT is preferred over this constant, avoid its use at all costs. - - PPC_DARWIN = new ['ppc', 'darwin', nil] - - # :stopdoc: - # Here lie legacy constants. These are deprecated. - WIN32 = 'mswin32' - LINUX_586 = 'i586-linux' - DARWIN = 'powerpc-darwin' - # :startdoc: - end diff --git a/lib/rubygems/remote_fetcher.rb b/lib/rubygems/remote_fetcher.rb index eac4ccaf0..cb22e1f1b 100644 --- a/lib/rubygems/remote_fetcher.rb +++ b/lib/rubygems/remote_fetcher.rb @@ -16,7 +16,7 @@ class Gem::RemoteFetcher # Cached RemoteFetcher instance. def self.fetcher - @fetcher ||= new Gem.configuration[:http_proxy] + @fetcher ||= self.new Gem.configuration[:http_proxy] end # Initialize a remote fetcher using the source URI and possible proxy @@ -45,8 +45,12 @@ class Gem::RemoteFetcher end rescue Timeout::Error raise FetchError, "timed out fetching #{uri}" - rescue OpenURI::HTTPError, IOError, SocketError, SystemCallError => e + rescue IOError, SocketError, SystemCallError => e raise FetchError, "#{e.class}: #{e} reading #{uri}" + rescue OpenURI::HTTPError => e + body = e.io.readlines.join "\n\t" + message = "#{e.class}: #{e} reading #{uri}\n\t#{body}" + raise FetchError, message end # Returns the size of +uri+ in bytes. @@ -79,7 +83,7 @@ class Gem::RemoteFetcher end rescue SocketError, SystemCallError, Timeout::Error => e - raise FetchError, "#{e.message} (#{e.class})" + raise FetchError, "#{e.message} (#{e.class})\n\tgetting size of #{uri}" end private diff --git a/lib/rubygems/remote_installer.rb b/lib/rubygems/remote_installer.rb deleted file mode 100644 index e33fd548f..000000000 --- a/lib/rubygems/remote_installer.rb +++ /dev/null @@ -1,195 +0,0 @@ -#-- -# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others. -# All rights reserved. -# See LICENSE.txt for permissions. -#++ - -require 'fileutils' - -require 'rubygems' -require 'rubygems/installer' -require 'rubygems/source_info_cache' - -module Gem - - class RemoteInstaller - - include UserInteraction - - # <tt>options[:http_proxy]</tt>:: - # * [String]: explicit specification of proxy; overrides any - # environment variable setting - # * nil: respect environment variables (HTTP_PROXY, HTTP_PROXY_USER, HTTP_PROXY_PASS) - # * <tt>:no_proxy</tt>: ignore environment variables and _don't_ - # use a proxy - # - # * <tt>:cache_dir</tt>: override where downloaded gems are cached. - def initialize(options={}) - @options = options - @source_index_hash = nil - end - - # This method will install package_name onto the local system. - # - # gem_name:: - # [String] Name of the Gem to install - # - # version_requirement:: - # [default = ">= 0"] Gem version requirement to install - # - # Returns:: - # an array of Gem::Specification objects, one for each gem installed. - # - def install(gem_name, version_requirement = Gem::Requirement.default, - force = false, install_dir = Gem.dir) - unless version_requirement.respond_to?(:satisfied_by?) - version_requirement = Gem::Requirement.new [version_requirement] - end - installed_gems = [] - begin - spec, source = find_gem_to_install(gem_name, version_requirement) - dependencies = find_dependencies_not_installed(spec.dependencies) - - installed_gems << install_dependencies(dependencies, force, install_dir) - - cache_dir = @options[:cache_dir] || File.join(install_dir, "cache") - destination_file = File.join(cache_dir, spec.full_name + ".gem") - - download_gem(destination_file, source, spec) - - installer = new_installer(destination_file) - installed_gems.unshift installer.install(force, install_dir) - rescue RemoteInstallationSkipped => e - alert_error e.message - end - installed_gems.flatten - end - - # Return a hash mapping the available source names to the source - # index of that source. - def source_index_hash - return @source_index_hash if @source_index_hash - @source_index_hash = {} - Gem::SourceInfoCache.cache_data.each do |source_uri, sic_entry| - @source_index_hash[source_uri] = sic_entry.source_index - end - @source_index_hash - end - - # Finds the Gem::Specification objects and the corresponding source URI - # for gems matching +gem_name+ and +version_requirement+ - def specs_n_sources_matching(gem_name, version_requirement) - specs_n_sources = [] - - source_index_hash.each do |source_uri, source_index| - specs = source_index.search(/^#{Regexp.escape gem_name}$/i, - version_requirement) - # TODO move to SourceIndex#search? - ruby_version = Gem::Version.new RUBY_VERSION - specs = specs.select do |spec| - spec.required_ruby_version.nil? or - spec.required_ruby_version.satisfied_by? ruby_version - end - specs.each { |spec| specs_n_sources << [spec, source_uri] } - end - - if specs_n_sources.empty? then - raise GemNotFoundException, "Could not find #{gem_name} (#{version_requirement}) in any repository" - end - - specs_n_sources = specs_n_sources.sort_by { |gs,| gs.version }.reverse - - specs_n_sources - end - - # Find a gem to be installed by interacting with the user. - def find_gem_to_install(gem_name, version_requirement) - specs_n_sources = specs_n_sources_matching gem_name, version_requirement - - top_3_versions = specs_n_sources.map{|gs| gs.first.version}.uniq[0..3] - specs_n_sources.reject!{|gs| !top_3_versions.include?(gs.first.version)} - - binary_gems = specs_n_sources.reject { |item| - item[0].platform.nil? || item[0].platform==Platform::RUBY - } - - # only non-binary gems...return latest - return specs_n_sources.first if binary_gems.empty? - - list = specs_n_sources.collect { |spec, source_uri| - "#{spec.name} #{spec.version} (#{spec.platform})" - } - - list << "Skip this gem" - list << "Cancel installation" - - string, index = choose_from_list( - "Select which gem to install for your platform (#{RUBY_PLATFORM})", - list) - - if index.nil? or index == (list.size - 1) then - raise RemoteInstallationCancelled, "Installation of #{gem_name} cancelled." - end - - if index == (list.size - 2) then - raise RemoteInstallationSkipped, "Installation of #{gem_name} skipped." - end - - specs_n_sources[index] - end - - def find_dependencies_not_installed(dependencies) - to_install = [] - dependencies.each do |dependency| - srcindex = Gem::SourceIndex.from_installed_gems - matches = srcindex.find_name(dependency.name, dependency.requirement_list) - to_install.push dependency if matches.empty? - end - to_install - end - - # Install all the given dependencies. Returns an array of - # Gem::Specification objects, one for each dependency installed. - # - # TODO: For now, we recursively install, but this is not the right - # way to do things (e.g. if a package fails to download, we - # shouldn't install anything). - def install_dependencies(dependencies, force, install_dir) - return if @options[:ignore_dependencies] - installed_gems = [] - dependencies.each do |dep| - if @options[:include_dependencies] || - ask_yes_no("Install required dependency #{dep.name}?", true) - remote_installer = RemoteInstaller.new @options - installed_gems << remote_installer.install(dep.name, - dep.version_requirements, - force, install_dir) - elsif force then - # ignore - else - raise DependencyError, "Required dependency #{dep.name} not installed" - end - end - installed_gems - end - - def download_gem(destination_file, source, spec) - return if File.exist? destination_file - uri = source + "/gems/#{spec.full_name}.gem" - response = Gem::RemoteFetcher.fetcher.fetch_path uri - write_gem_to_file response, destination_file - end - - def write_gem_to_file(body, destination_file) - FileUtils.mkdir_p(File.dirname(destination_file)) unless File.exist?(destination_file) - File.open(destination_file, 'wb') do |out| - out.write(body) - end - end - - def new_installer(gem) - return Installer.new(gem, @options) - end - end - -end diff --git a/lib/rubygems/rubygems_version.rb b/lib/rubygems/rubygems_version.rb index d08789baf..85e18d48a 100644 --- a/lib/rubygems/rubygems_version.rb +++ b/lib/rubygems/rubygems_version.rb @@ -2,5 +2,5 @@ # This file is auto-generated by build scripts. # See: rake update_version module Gem - RubyGemsVersion = '0.9.5' + RubyGemsVersion = '1.0.0' end diff --git a/lib/rubygems/security.rb b/lib/rubygems/security.rb index 6f6586e9c..415e98ffc 100644 --- a/lib/rubygems/security.rb +++ b/lib/rubygems/security.rb @@ -318,7 +318,7 @@ require 'rubygems/gem_openssl' module Gem::Security - class Exception < Exception; end + class Exception < Gem::Exception; end # # default options for most of the methods below diff --git a/lib/rubygems/server.rb b/lib/rubygems/server.rb index 212ccc5f7..ed957dd38 100644 --- a/lib/rubygems/server.rb +++ b/lib/rubygems/server.rb @@ -368,19 +368,34 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; } when '/quick/index.rz' then index = @source_index.map { |name,_| name }.join("\n") res.body << Zlib::Deflate.deflate(index) - when %r|^/quick/(.*)-([0-9.]+)\.gemspec(\.marshal)?\.rz$| then - specs = @source_index.search $1, $2 + when %r|^/quick/(Marshal.#{Regexp.escape Gem.marshal_version}/)?(.*?)-([0-9.]+)(-.*?)?\.gemspec\.rz$| then + dep = Gem::Dependency.new $2, $3 + specs = @source_index.search dep + + selector = [$2, $3, $4].map { |s| s.inspect }.join ' ' + + platform = if $4 then + Gem::Platform.new $4.sub(/^-/, '') + else + Gem::Platform::RUBY + end + + specs = specs.select { |s| s.platform == platform } + if specs.empty? then res.status = 404 + res.body = "No gems found matching #{selector}" elsif specs.length > 1 then res.status = 500 - elsif $3 # marshal quickindex instead of YAML + res.body = "Multiple gems found matching #{selector}" + elsif $1 then # marshal quickindex instead of YAML res.body << Zlib::Deflate.deflate(Marshal.dump(specs.first)) else # deprecated YAML format res.body << Zlib::Deflate.deflate(specs.first.to_yaml) end else res.status = 404 + res.body = "#{req.request_uri} not found" end end diff --git a/lib/rubygems/source_index.rb b/lib/rubygems/source_index.rb index 759718d45..2df28d956 100644 --- a/lib/rubygems/source_index.rb +++ b/lib/rubygems/source_index.rb @@ -4,8 +4,6 @@ # See LICENSE.txt for permissions. #++ -require 'forwardable' - require 'rubygems' require 'rubygems/user_interaction' require 'rubygems/specification' @@ -23,7 +21,6 @@ module Gem # YAMLized source index objects to load properly. # class SourceIndex - extend Forwardable include Enumerable @@ -186,40 +183,40 @@ module Gem Gem::SHA256.new.hexdigest(@gems[gem_full_name].to_yaml).to_s end - def_delegators :@gems, :size, :length + def size + @gems.size + end + alias length size # Find a gem by an exact match on the short name. def find_name(gem_name, version_requirement = Gem::Requirement.default) search(/^#{gem_name}$/, version_requirement) end - # Search for a gem by short name pattern and optional version - # - # gem_name:: - # [String] a partial for the (short) name of the gem, or - # [Regex] a pattern to match against the short name - # version_requirement:: - # [String | default=Gem::Requirement.default] version to - # find - # return:: - # [Array] list of Gem::Specification objects in sorted (version) - # order. Empty if not found. + # Search for a gem by Gem::Dependency +gem_pattern+. If +only_platform+ + # is true, only gems matching Gem::Platform.local will be returned. An + # Array of matching Gem::Specification objects is returned. # - def search(gem_pattern, platform_only_or_version_req = false) + # For backwards compatibility, a String or Regexp pattern may be passed as + # +gem_pattern+, and a Gem::Requirement for +platform_only+. This + # behavior is deprecated and will be removed. + def search(gem_pattern, platform_only = false) version_requirement = nil only_platform = false - case gem_pattern + case gem_pattern # TODO warn after 2008/03, remove three months after when Regexp then - version_requirement = platform_only_or_version_req || - Gem::Requirement.default + version_requirement = platform_only || Gem::Requirement.default when Gem::Dependency then - only_platform = platform_only_or_version_req + only_platform = platform_only version_requirement = gem_pattern.version_requirements - gem_pattern = gem_pattern.name.empty? ? // : /^#{gem_pattern.name}$/ + gem_pattern = if gem_pattern.name.empty? then + // + else + /^#{Regexp.escape gem_pattern.name}$/ + end else - version_requirement = platform_only_or_version_req || - Gem::Requirement.default + version_requirement = platform_only || Gem::Requirement.default gem_pattern = /#{gem_pattern}/i end diff --git a/lib/rubygems/source_info_cache.rb b/lib/rubygems/source_info_cache.rb index 0498e895a..c84868a5f 100644 --- a/lib/rubygems/source_info_cache.rb +++ b/lib/rubygems/source_info_cache.rb @@ -176,7 +176,7 @@ class Gem::SourceInfoCache # The name of the system cache file. (class method) def self.system_cache_file - @system_cache_file ||= File.join(Gem.dir, "source_cache") + @system_cache_file ||= Gem.default_system_source_cache_dir end # The name of the user cache file. @@ -187,7 +187,7 @@ class Gem::SourceInfoCache # The name of the user cache file. (class method) def self.user_cache_file @user_cache_file ||= - ENV['GEMCACHE'] || File.join(Gem.user_home, ".gem", "source_cache") + ENV['GEMCACHE'] || Gem.default_user_source_cache_dir end # Write data to the proper cache. @@ -217,7 +217,7 @@ class Gem::SourceInfoCache unless File.exist? dir then begin FileUtils.mkdir_p(dir) - rescue RuntimeError + rescue RuntimeError, SystemCallError return nil end end diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb index 4a785fa60..35f2ffdff 100644 --- a/lib/rubygems/specification.rb +++ b/lib/rubygems/specification.rb @@ -4,17 +4,18 @@ # See LICENSE.txt for permissions. #++ -require 'time' require 'rubygems' require 'rubygems/version' require 'rubygems/platform' # :stopdoc: # Time::today has been deprecated in 0.9.5 and will be removed. -def Time.today - t = Time.now - t - ((t.to_i + t.gmt_offset) % 86400) -end unless defined? Time.today +if RUBY_VERSION < '1.9' then + def Time.today + t = Time.now + t - ((t.to_i + t.gmt_offset) % 86400) + end unless defined? Time.today +end # :startdoc: module Gem @@ -239,7 +240,7 @@ module Gem @specification_version, @name, @version, - (Time === @date ? @date : Time.parse(@date.to_s)), + (Time === @date ? @date : (require 'time'; Time.parse(@date.to_s))), @summary, @required_ruby_version, @required_rubygems_version, @@ -293,14 +294,9 @@ module Gem spec end - def warn_deprecated(old, new) - # How (if at all) to implement this? We only want to warn when - # a gem is being built, I should think. - end - # REQUIRED gemspec attributes ------------------------------------ - required_attribute :rubygems_version, RubyGemsVersion + required_attribute :rubygems_version, Gem::RubyGemsVersion required_attribute :specification_version, CURRENT_SPECIFICATION_VERSION required_attribute :name required_attribute :version @@ -349,12 +345,12 @@ module Gem # DEPRECATED gemspec attributes ---------------------------------- def test_suite_file - warn_deprecated(:test_suite_file, :test_files) + warn 'test_suite_file deprecated, use test_files' test_files.first end def test_suite_file=(val) - warn_deprecated(:test_suite_file, :test_files) + warn 'test_suite_file= deprecated, use test_files=' @test_files = [] unless defined? @test_files @test_files << val end @@ -386,6 +382,7 @@ module Gem case platform when Gem::Platform::CURRENT then @new_platform = Gem::Platform.local + @original_platform = @new_platform.to_s when Gem::Platform then @new_platform = platform @@ -393,14 +390,14 @@ module Gem # legacy constants when nil, Gem::Platform::RUBY then @new_platform = Gem::Platform::RUBY - when Gem::Platform::WIN32 then - @new_platform = Gem::Platform::MSWIN32 - when Gem::Platform::LINUX_586 then - @new_platform = Gem::Platform::X86_LINUX - when Gem::Platform::DARWIN then - @new_platform = Gem::Platform::PPC_DARWIN + when 'mswin32' then # was Gem::Platform::WIN32 + @new_platform = Gem::Platform.new 'x86-mswin32' + when 'i586-linux' then # was Gem::Platform::LINUX_586 + @new_platform = Gem::Platform.new 'x86-linux' + when 'powerpc-darwin' then # was Gem::Platform::DARWIN + @new_platform = Gem::Platform.new 'ppc-darwin' else - @new_platform = platform + @new_platform = Gem::Platform.new platform end @platform = @new_platform.to_s @@ -422,11 +419,16 @@ module Gem # way to do it. case date when String then - @date = Time.parse date + @date = if /\A(\d{4})-(\d{2})-(\d{2})\Z/ =~ date then + Time.local($1.to_i, $2.to_i, $3.to_i) + else + require 'time' + Time.parse date + end when Time then - @date = Time.parse date.strftime("%Y-%m-%d") + @date = Time.local(date.year, date.month, date.day) when Date then - @date = Time.parse date.to_s + @date = Time.local(date.year, date.month, date.day) else @date = TODAY end @@ -751,7 +753,10 @@ module Gem out.map taguri, to_yaml_style do |map| map.add 'name', @name map.add 'version', @version - platform = if String === @original_platform then + platform = case @original_platform + when nil, '' then + 'ruby' + when String then @original_platform else @original_platform.to_s @@ -801,13 +806,14 @@ module Gem :version, ] - attributes = @@attributes.sort_by { |name,| name.to_s } + attributes = @@attributes.sort_by { |attr_name,| attr_name.to_s } - attributes.each do |name, default| - next if handled.include? name - current_value = self.send(name) - if current_value != default or self.class.required_attribute? name then - result << " s.#{name} = #{ruby_code current_value}" + attributes.each do |attr_name, default| + next if handled.include? attr_name + current_value = self.send(attr_name) + if current_value != default or + self.class.required_attribute? attr_name then + result << " s.#{attr_name} = #{ruby_code current_value}" end end @@ -832,6 +838,8 @@ module Gem # Raises InvalidSpecificationException if the spec does not pass # the checks.. def validate + extend Gem::UserInteraction + normalize if rubygems_version != RubyGemsVersion then @@ -858,6 +866,31 @@ module Gem "invalid platform #{platform.inspect}, see Gem::Platform" end + unless Array === authors and + authors.all? { |author| String === author } then + raise Gem::InvalidSpecificationException, + 'authors must be Array of Strings' + end + + # Warnings + + %w[author email homepage rubyforge_project summary].each do |attribute| + value = self.send attribute + alert_warning "no #{attribute} specified" if value.nil? or value.empty? + end + + alert_warning "RDoc will not be generated (has_rdoc == false)" unless + has_rdoc + + alert_warning "deprecated autorequire specified" if autorequire + + executables.each do |executable| + executable_path = File.join bindir, executable + shebang = File.read(executable_path, 2) == '#!' + + alert_warning "#{executable_path} is missing #! line" unless shebang + end + true end diff --git a/lib/rubygems/uninstaller.rb b/lib/rubygems/uninstaller.rb index f26de152d..268c0b3b8 100644 --- a/lib/rubygems/uninstaller.rb +++ b/lib/rubygems/uninstaller.rb @@ -144,7 +144,7 @@ class Gem::Uninstaller cache_dir = File.join spec.installation_path, 'cache' gem = File.join cache_dir, "#{spec.full_name}.gem" - unless File.exist? gemspec then + unless File.exist? gem then gem = File.join cache_dir, "#{original_platform_name}.gem" end diff --git a/lib/rubygems/validator.rb b/lib/rubygems/validator.rb index 8130f49bc..41c457c3c 100755 --- a/lib/rubygems/validator.rb +++ b/lib/rubygems/validator.rb @@ -157,8 +157,9 @@ module Gem # XXX: why do we need this gem_spec when we've already got 'spec'? test_files = gem_spec.test_files if test_files.empty? - say "There are no unit tests to run for #{gem_spec.name}-#{gem_spec.version}" - return + say "There are no unit tests to run for #{gem_spec.full_name}" + require 'test/unit/ui/console/testrunner' + return Test::Unit::TestResult.new end gem gem_spec.name, "= #{gem_spec.version.version}" test_files.each do |f| require f end diff --git a/lib/rubygems/version.rb b/lib/rubygems/version.rb index 35dd60a74..87a1bc72e 100644 --- a/lib/rubygems/version.rb +++ b/lib/rubygems/version.rb @@ -75,7 +75,7 @@ class Gem::Version # Strip ignored trailing zeros. def normalize - @ints = @version.to_s.scan(/\d+/).map { |s| s.to_i } + @ints = build_array_from_version_string return if @ints.length == 1 @@ -127,19 +127,26 @@ class Gem::Version @ints <=> other.ints end - def hash + alias eql? == # :nodoc: + + def hash # :nodoc: to_ints.inject { |hash_code, n| hash_code + n } end # Return a new version object where the next to the last revision # number is one greater. (e.g. 5.3.1 => 5.4) def bump - ints = @ints.dup + ints = build_array_from_version_string ints.pop if ints.size > 1 ints[-1] += 1 self.class.new(ints.join(".")) end + def build_array_from_version_string + @version.to_s.scan(/\d+/).map { |s| s.to_i } + end + private :build_array_from_version_string + #:stopdoc: require 'rubygems/requirement' |