summaryrefslogtreecommitdiff
path: root/trunk/lib/rubygems/indexer.rb
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/lib/rubygems/indexer.rb')
-rw-r--r--trunk/lib/rubygems/indexer.rb370
1 files changed, 0 insertions, 370 deletions
diff --git a/trunk/lib/rubygems/indexer.rb b/trunk/lib/rubygems/indexer.rb
deleted file mode 100644
index e2dd57d3fe..0000000000
--- a/trunk/lib/rubygems/indexer.rb
+++ /dev/null
@@ -1,370 +0,0 @@
-require 'fileutils'
-require 'tmpdir'
-require 'zlib'
-
-require 'rubygems'
-require 'rubygems/format'
-
-begin
- require 'builder/xchar'
-rescue LoadError
-end
-
-##
-# Top level class for building the gem repository index.
-
-class Gem::Indexer
-
- include Gem::UserInteraction
-
- ##
- # Index install location
-
- attr_reader :dest_directory
-
- ##
- # Index build directory
-
- attr_reader :directory
-
- ##
- # Create an indexer that will index the gems in +directory+.
-
- def initialize(directory)
- unless ''.respond_to? :to_xs then
- fail "Gem::Indexer requires that the XML Builder library be installed:" \
- "\n\tgem install builder"
- end
-
- @dest_directory = directory
- @directory = File.join Dir.tmpdir, "gem_generate_index_#{$$}"
-
- marshal_name = "Marshal.#{Gem.marshal_version}"
-
- @master_index = File.join @directory, 'yaml'
- @marshal_index = File.join @directory, marshal_name
-
- @quick_dir = File.join @directory, 'quick'
-
- @quick_marshal_dir = File.join @quick_dir, marshal_name
-
- @quick_index = File.join @quick_dir, 'index'
- @latest_index = File.join @quick_dir, 'latest_index'
-
- @specs_index = File.join @directory, "specs.#{Gem.marshal_version}"
- @latest_specs_index = File.join @directory,
- "latest_specs.#{Gem.marshal_version}"
-
- files = [
- @specs_index,
- "#{@specs_index}.gz",
- @latest_specs_index,
- "#{@latest_specs_index}.gz",
- @quick_dir,
- @master_index,
- "#{@master_index}.Z",
- @marshal_index,
- "#{@marshal_index}.Z",
- ]
-
- @files = files.map do |path|
- path.sub @directory, ''
- end
- end
-
- ##
- # Abbreviate the spec for downloading. Abbreviated specs are only used for
- # searching, downloading and related activities and do not need deployment
- # specific information (e.g. list of files). So we abbreviate the spec,
- # making it much smaller for quicker downloads.
-
- def abbreviate(spec)
- spec.files = []
- spec.test_files = []
- spec.rdoc_options = []
- spec.extra_rdoc_files = []
- spec.cert_chain = []
- spec
- end
-
- ##
- # Build various indicies
-
- def build_indicies(index)
- progress = ui.progress_reporter index.size,
- "Generating quick index gemspecs for #{index.size} gems",
- "Complete"
-
- index.each do |original_name, spec|
- spec_file_name = "#{original_name}.gemspec.rz"
- yaml_name = File.join @quick_dir, spec_file_name
- marshal_name = File.join @quick_marshal_dir, spec_file_name
-
- yaml_zipped = Gem.deflate spec.to_yaml
- open yaml_name, 'wb' do |io| io.write yaml_zipped end
-
- marshal_zipped = Gem.deflate Marshal.dump(spec)
- open marshal_name, 'wb' do |io| io.write marshal_zipped end
-
- progress.updated original_name
- end
-
- progress.done
-
- say "Generating specs index"
-
- open @specs_index, 'wb' do |io|
- specs = index.sort.map do |_, spec|
- platform = spec.original_platform
- platform = Gem::Platform::RUBY if platform.nil? or platform.empty?
- [spec.name, spec.version, platform]
- end
-
- specs = compact_specs specs
-
- Marshal.dump specs, io
- end
-
- say "Generating latest specs index"
-
- open @latest_specs_index, 'wb' do |io|
- specs = index.latest_specs.sort.map do |spec|
- platform = spec.original_platform
- platform = Gem::Platform::RUBY if platform.nil? or platform.empty?
- [spec.name, spec.version, platform]
- end
-
- specs = compact_specs specs
-
- Marshal.dump specs, io
- end
-
- say "Generating quick index"
-
- quick_index = File.join @quick_dir, 'index'
- open quick_index, 'wb' do |io|
- io.puts index.sort.map { |_, spec| spec.original_name }
- end
-
- say "Generating latest index"
-
- latest_index = File.join @quick_dir, 'latest_index'
- open latest_index, 'wb' do |io|
- io.puts index.latest_specs.sort.map { |spec| spec.original_name }
- end
-
- say "Generating Marshal master index"
-
- open @marshal_index, 'wb' do |io|
- io.write index.dump
- end
-
- progress = ui.progress_reporter index.size,
- "Generating YAML master index for #{index.size} gems (this may take a while)",
- "Complete"
-
- open @master_index, 'wb' do |io|
- io.puts "--- !ruby/object:#{index.class}"
- io.puts "gems:"
-
- gems = index.sort_by { |name, gemspec| gemspec.sort_obj }
- gems.each do |original_name, gemspec|
- yaml = gemspec.to_yaml.gsub(/^/, ' ')
- yaml = yaml.sub(/\A ---/, '') # there's a needed extra ' ' here
- io.print " #{original_name}:"
- io.puts yaml
-
- progress.updated original_name
- end
- end
-
- progress.done
-
- say "Compressing indicies"
- # use gzip for future files.
-
- compress quick_index, 'rz'
- paranoid quick_index, 'rz'
-
- compress latest_index, 'rz'
- paranoid latest_index, 'rz'
-
- compress @marshal_index, 'Z'
- paranoid @marshal_index, 'Z'
-
- compress @master_index, 'Z'
- paranoid @master_index, 'Z'
-
- gzip @specs_index
- gzip @latest_specs_index
- end
-
- ##
- # Collect specifications from .gem files from the gem directory.
-
- def collect_specs
- index = Gem::SourceIndex.new
-
- progress = ui.progress_reporter gem_file_list.size,
- "Loading #{gem_file_list.size} gems from #{@dest_directory}",
- "Loaded all gems"
-
- gem_file_list.each do |gemfile|
- if File.size(gemfile.to_s) == 0 then
- alert_warning "Skipping zero-length gem: #{gemfile}"
- next
- end
-
- begin
- spec = Gem::Format.from_file_by_path(gemfile).spec
-
- unless gemfile =~ /\/#{Regexp.escape spec.original_name}.*\.gem\z/i then
- alert_warning "Skipping misnamed gem: #{gemfile} => #{spec.full_name} (#{spec.original_name})"
- next
- end
-
- abbreviate spec
- sanitize spec
-
- index.gems[spec.original_name] = spec
-
- progress.updated spec.original_name
-
- rescue SignalException => e
- alert_error "Received signal, exiting"
- raise
- rescue Exception => e
- alert_error "Unable to process #{gemfile}\n#{e.message} (#{e.class})\n\t#{e.backtrace.join "\n\t"}"
- end
- end
-
- progress.done
-
- index
- end
-
- ##
- # Compacts Marshal output for the specs index data source by using identical
- # objects as much as possible.
-
- def compact_specs(specs)
- names = {}
- versions = {}
- platforms = {}
-
- specs.map do |(name, version, platform)|
- names[name] = name unless names.include? name
- versions[version] = version unless versions.include? version
- platforms[platform] = platform unless platforms.include? platform
-
- [names[name], versions[version], platforms[platform]]
- end
- end
-
- ##
- # Compress +filename+ with +extension+.
-
- def compress(filename, extension)
- data = Gem.read_binary filename
-
- zipped = Gem.deflate data
-
- open "#{filename}.#{extension}", 'wb' do |io|
- io.write zipped
- end
- end
-
- ##
- # List of gem file names to index.
-
- def gem_file_list
- Dir.glob(File.join(@dest_directory, "gems", "*.gem"))
- end
-
- ##
- # Builds and installs indexicies.
-
- def generate_index
- make_temp_directories
- index = collect_specs
- build_indicies index
- install_indicies
- rescue SignalException
- ensure
- FileUtils.rm_rf @directory
- end
-
- ##
- # Zlib::GzipWriter wrapper that gzips +filename+ on disk.
-
- def gzip(filename)
- Zlib::GzipWriter.open "#{filename}.gz" do |io|
- io.write Gem.read_binary(filename)
- end
- end
-
- ##
- # Install generated indicies into the destination directory.
-
- def install_indicies
- verbose = Gem.configuration.really_verbose
-
- say "Moving index into production dir #{@dest_directory}" if verbose
-
- @files.each do |file|
- src_name = File.join @directory, file
- dst_name = File.join @dest_directory, file
-
- FileUtils.rm_rf dst_name, :verbose => verbose
- FileUtils.mv src_name, @dest_directory, :verbose => verbose,
- :force => true
- end
- end
-
- ##
- # Make directories for index generation
-
- def make_temp_directories
- FileUtils.rm_rf @directory
- FileUtils.mkdir_p @directory, :mode => 0700
- FileUtils.mkdir_p @quick_marshal_dir
- end
-
- ##
- # Ensure +path+ and path with +extension+ are identical.
-
- def paranoid(path, extension)
- data = Gem.read_binary path
- compressed_data = Gem.read_binary "#{path}.#{extension}"
-
- unless data == Gem.inflate(compressed_data) then
- raise "Compressed file #{compressed_path} does not match uncompressed file #{path}"
- end
- end
-
- ##
- # Sanitize the descriptive fields in the spec. Sometimes non-ASCII
- # characters will garble the site index. Non-ASCII characters will
- # be replaced by their XML entity equivalent.
-
- def sanitize(spec)
- spec.summary = sanitize_string(spec.summary)
- spec.description = sanitize_string(spec.description)
- spec.post_install_message = sanitize_string(spec.post_install_message)
- spec.authors = spec.authors.collect { |a| sanitize_string(a) }
-
- spec
- end
-
- ##
- # Sanitize a single string.
-
- def sanitize_string(string)
- # HACK the #to_s is in here because RSpec has an Array of Arrays of
- # Strings for authors. Need a way to disallow bad values on gempsec
- # generation. (Probably won't happen.)
- string ? string.to_s.to_xs : string
- end
-
-end
-