зеркало из https://github.com/github/ruby.git
[rubygems/rubygems] Extract generate_index command to rubygems-generate_index gem
So generate_index can be implemented with dependencies, such as the compact index Took this approach from feedback in https://github.com/rubygems/rubygems/pull/6853 Running `gem generate_index` by default will use an installed rubygems-generate_index, or install and then use the command from the gem Apply suggestions from code review https://github.com/rubygems/rubygems/commit/fc1cb9bc9e Co-authored-by: Hiroshi SHIBATA <hsbt@ruby-lang.org>
This commit is contained in:
Родитель
0166d56f2b
Коммит
4817166e54
|
@ -249,6 +249,7 @@ class Gem::CommandManager
|
|||
def invoke_command(args, build_args)
|
||||
cmd_name = args.shift.downcase
|
||||
cmd = find_command cmd_name
|
||||
terminate_interaction 1 unless cmd
|
||||
cmd.deprecation_warning if cmd.deprecated?
|
||||
cmd.invoke_with_build_args args, build_args
|
||||
end
|
||||
|
|
|
@ -1,86 +1,51 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative "../command"
|
||||
require_relative "../indexer"
|
||||
|
||||
##
|
||||
# Generates a index files for use as a gem server.
|
||||
#
|
||||
# See `gem help generate_index`
|
||||
unless defined? Gem::Commands::GenerateIndexCommand
|
||||
class Gem::Commands::GenerateIndexCommand < Gem::Command
|
||||
module RubygemsTrampoline
|
||||
def description # :nodoc:
|
||||
<<~EOF
|
||||
The generate_index command has been moved to the rubygems-generate_index gem.
|
||||
EOF
|
||||
end
|
||||
|
||||
class Gem::Commands::GenerateIndexCommand < Gem::Command
|
||||
def initialize
|
||||
super "generate_index",
|
||||
"Generates the index files for a gem server directory",
|
||||
directory: ".", build_modern: true
|
||||
def execute
|
||||
alert_error "Install the rubygems-generate_index gem for the generate_index command"
|
||||
end
|
||||
|
||||
add_option "-d", "--directory=DIRNAME",
|
||||
"repository base dir containing gems subdir" do |dir, options|
|
||||
options[:directory] = File.expand_path dir
|
||||
end
|
||||
def invoke_with_build_args(args, build_args)
|
||||
name = "rubygems-generate_index"
|
||||
spec = begin
|
||||
Gem::Specification.find_by_name(name)
|
||||
rescue Gem::LoadError
|
||||
require "rubygems/dependency_installer"
|
||||
Gem.install(name, Gem::Requirement.default, Gem::DependencyInstaller::DEFAULT_OPTIONS).find {|s| s.name == name }
|
||||
end
|
||||
|
||||
add_option "--[no-]modern",
|
||||
"Generate indexes for RubyGems",
|
||||
"(always true)" do |value, options|
|
||||
options[:build_modern] = value
|
||||
end
|
||||
# remove the methods defined in this file so that the methods defined in the gem are used instead,
|
||||
# and without a method redefinition warning
|
||||
%w[description execute invoke_with_build_args].each do |method|
|
||||
RubygemsTrampoline.remove_method(method)
|
||||
end
|
||||
self.class.singleton_class.remove_method(:new)
|
||||
|
||||
deprecate_option("--modern", version: "4.0", extra_msg: "Modern indexes (specs, latest_specs, and prerelease_specs) are always generated, so this option is not needed.")
|
||||
deprecate_option("--no-modern", version: "4.0", extra_msg: "The `--no-modern` option is currently ignored. Modern indexes (specs, latest_specs, and prerelease_specs) are always generated.")
|
||||
spec.activate
|
||||
Gem.load_plugin_files spec.matches_for_glob("rubygems_plugin#{Gem.suffix_pattern}")
|
||||
|
||||
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 !File.exist?(options[:directory]) ||
|
||||
!File.directory?(options[:directory])
|
||||
alert_error "unknown directory name #{options[:directory]}."
|
||||
terminate_interaction 1
|
||||
else
|
||||
indexer = Gem::Indexer.new options.delete(:directory), options
|
||||
|
||||
if options[:update]
|
||||
indexer.update_index
|
||||
else
|
||||
indexer.generate_index
|
||||
self.class.new.invoke_with_build_args(args, build_args)
|
||||
end
|
||||
end
|
||||
private_constant :RubygemsTrampoline
|
||||
|
||||
# remove_method(:initialize) warns, but removing new does not warn
|
||||
def self.new
|
||||
command = allocate
|
||||
command.send(:initialize, "generate_index", "Generates the index files for a gem server directory (requires rubygems-generate_index)")
|
||||
command
|
||||
end
|
||||
|
||||
prepend(RubygemsTrampoline)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -333,7 +333,7 @@ platform.
|
|||
@command_manager.command_names.each do |cmd_name|
|
||||
command = @command_manager[cmd_name]
|
||||
|
||||
next if command.deprecated?
|
||||
next if command&.deprecated?
|
||||
|
||||
summary =
|
||||
if command
|
||||
|
|
|
@ -1,429 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative "../rubygems"
|
||||
require_relative "package"
|
||||
require "tmpdir"
|
||||
|
||||
##
|
||||
# Top level class for building the gem repository index.
|
||||
|
||||
class Gem::Indexer
|
||||
include Gem::UserInteraction
|
||||
|
||||
##
|
||||
# Build indexes for RubyGems 1.2.0 and newer when true
|
||||
|
||||
attr_accessor :build_modern
|
||||
|
||||
##
|
||||
# Index install location
|
||||
|
||||
attr_reader :dest_directory
|
||||
|
||||
##
|
||||
# Specs index install location
|
||||
|
||||
attr_reader :dest_specs_index
|
||||
|
||||
##
|
||||
# Latest specs index install location
|
||||
|
||||
attr_reader :dest_latest_specs_index
|
||||
|
||||
##
|
||||
# Prerelease specs index install location
|
||||
|
||||
attr_reader :dest_prerelease_specs_index
|
||||
|
||||
##
|
||||
# Index build directory
|
||||
|
||||
attr_reader :directory
|
||||
|
||||
##
|
||||
# Create an indexer that will index the gems in +directory+.
|
||||
|
||||
def initialize(directory, options = {})
|
||||
require "fileutils"
|
||||
require "tmpdir"
|
||||
require "zlib"
|
||||
|
||||
options = { build_modern: true }.merge options
|
||||
|
||||
@build_modern = options[:build_modern]
|
||||
|
||||
@dest_directory = directory
|
||||
@directory = Dir.mktmpdir "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_marshal_dir_base = File.join "quick", marshal_name # FIX: UGH
|
||||
|
||||
@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}")
|
||||
@prerelease_specs_index =
|
||||
File.join(@directory, "prerelease_specs.#{Gem.marshal_version}")
|
||||
@dest_specs_index =
|
||||
File.join(@dest_directory, "specs.#{Gem.marshal_version}")
|
||||
@dest_latest_specs_index =
|
||||
File.join(@dest_directory, "latest_specs.#{Gem.marshal_version}")
|
||||
@dest_prerelease_specs_index =
|
||||
File.join(@dest_directory, "prerelease_specs.#{Gem.marshal_version}")
|
||||
|
||||
@files = []
|
||||
end
|
||||
|
||||
##
|
||||
# Build various indices
|
||||
|
||||
def build_indices
|
||||
specs = map_gems_to_specs gem_file_list
|
||||
Gem::Specification._resort! specs
|
||||
build_marshal_gemspecs specs
|
||||
build_modern_indices specs if @build_modern
|
||||
|
||||
compress_indices
|
||||
end
|
||||
|
||||
##
|
||||
# Builds Marshal quick index gemspecs.
|
||||
|
||||
def build_marshal_gemspecs(specs)
|
||||
count = specs.count
|
||||
progress = ui.progress_reporter count,
|
||||
"Generating Marshal quick index gemspecs for #{count} gems",
|
||||
"Complete"
|
||||
|
||||
files = []
|
||||
|
||||
Gem.time "Generated Marshal quick index gemspecs" do
|
||||
specs.each do |spec|
|
||||
next if spec.default_gem?
|
||||
spec_file_name = "#{spec.original_name}.gemspec.rz"
|
||||
marshal_name = File.join @quick_marshal_dir, spec_file_name
|
||||
|
||||
marshal_zipped = Gem.deflate Marshal.dump(spec)
|
||||
|
||||
File.open marshal_name, "wb" do |io|
|
||||
io.write marshal_zipped
|
||||
end
|
||||
|
||||
files << marshal_name
|
||||
|
||||
progress.updated spec.original_name
|
||||
end
|
||||
|
||||
progress.done
|
||||
end
|
||||
|
||||
@files << @quick_marshal_dir
|
||||
|
||||
files
|
||||
end
|
||||
|
||||
##
|
||||
# Build a single index for RubyGems 1.2 and newer
|
||||
|
||||
def build_modern_index(index, file, name)
|
||||
say "Generating #{name} index"
|
||||
|
||||
Gem.time "Generated #{name} index" do
|
||||
File.open(file, "wb") do |io|
|
||||
specs = index.map do |*spec|
|
||||
# We have to splat here because latest_specs is an array, while the
|
||||
# others are hashes.
|
||||
spec = spec.flatten.last
|
||||
platform = spec.original_platform
|
||||
|
||||
# win32-api-1.0.4-x86-mswin32-60
|
||||
unless String === platform
|
||||
alert_warning "Skipping invalid platform in gem: #{spec.full_name}"
|
||||
next
|
||||
end
|
||||
|
||||
platform = Gem::Platform::RUBY if platform.nil? || platform.empty?
|
||||
[spec.name, spec.version, platform]
|
||||
end
|
||||
|
||||
specs = compact_specs(specs)
|
||||
Marshal.dump(specs, io)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Builds indices for RubyGems 1.2 and newer. Handles full, latest, prerelease
|
||||
|
||||
def build_modern_indices(specs)
|
||||
prerelease, released = specs.partition do |s|
|
||||
s.version.prerelease?
|
||||
end
|
||||
latest_specs =
|
||||
Gem::Specification._latest_specs specs
|
||||
|
||||
build_modern_index(released.sort, @specs_index, "specs")
|
||||
build_modern_index(latest_specs.sort, @latest_specs_index, "latest specs")
|
||||
build_modern_index(prerelease.sort, @prerelease_specs_index,
|
||||
"prerelease specs")
|
||||
|
||||
@files += [@specs_index,
|
||||
"#{@specs_index}.gz",
|
||||
@latest_specs_index,
|
||||
"#{@latest_specs_index}.gz",
|
||||
@prerelease_specs_index,
|
||||
"#{@prerelease_specs_index}.gz"]
|
||||
end
|
||||
|
||||
def map_gems_to_specs(gems)
|
||||
gems.map do |gemfile|
|
||||
if File.size(gemfile) == 0
|
||||
alert_warning "Skipping zero-length gem: #{gemfile}"
|
||||
next
|
||||
end
|
||||
|
||||
begin
|
||||
spec = Gem::Package.new(gemfile).spec
|
||||
spec.loaded_from = gemfile
|
||||
|
||||
spec.abbreviate
|
||||
spec.sanitize
|
||||
|
||||
spec
|
||||
rescue SignalException
|
||||
alert_error "Received signal, exiting"
|
||||
raise
|
||||
rescue StandardError => e
|
||||
msg = ["Unable to process #{gemfile}",
|
||||
"#{e.message} (#{e.class})",
|
||||
"\t#{e.backtrace.join "\n\t"}"].join("\n")
|
||||
alert_error msg
|
||||
end
|
||||
end.compact
|
||||
end
|
||||
|
||||
##
|
||||
# Compresses indices on disk
|
||||
#--
|
||||
# All future files should be compressed using gzip, not deflate
|
||||
|
||||
def compress_indices
|
||||
say "Compressing indices"
|
||||
|
||||
Gem.time "Compressed indices" do
|
||||
if @build_modern
|
||||
gzip @specs_index
|
||||
gzip @latest_specs_index
|
||||
gzip @prerelease_specs_index
|
||||
end
|
||||
end
|
||||
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
|
||||
|
||||
File.open "#{filename}.#{extension}", "wb" do |io|
|
||||
io.write zipped
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# List of gem file names to index.
|
||||
|
||||
def gem_file_list
|
||||
Gem::Util.glob_files_in_dir("*.gem", File.join(@dest_directory, "gems"))
|
||||
end
|
||||
|
||||
##
|
||||
# Builds and installs indices.
|
||||
|
||||
def generate_index
|
||||
make_temp_directories
|
||||
build_indices
|
||||
install_indices
|
||||
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 indices into the destination directory.
|
||||
|
||||
def install_indices
|
||||
verbose = Gem.configuration.really_verbose
|
||||
|
||||
say "Moving index into production dir #{@dest_directory}" if verbose
|
||||
|
||||
files = @files
|
||||
files.delete @quick_marshal_dir if files.include? @quick_dir
|
||||
|
||||
if files.include?(@quick_marshal_dir) && !files.include?(@quick_dir)
|
||||
files.delete @quick_marshal_dir
|
||||
|
||||
dst_name = File.join(@dest_directory, @quick_marshal_dir_base)
|
||||
|
||||
FileUtils.mkdir_p File.dirname(dst_name), verbose: verbose
|
||||
FileUtils.rm_rf dst_name, verbose: verbose
|
||||
FileUtils.mv(@quick_marshal_dir, dst_name,
|
||||
verbose: verbose, force: true)
|
||||
end
|
||||
|
||||
files = files.map do |path|
|
||||
path.sub(%r{^#{Regexp.escape @directory}/?}, "") # HACK?
|
||||
end
|
||||
|
||||
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: 0o700
|
||||
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::Util.inflate(compressed_data)
|
||||
raise "Compressed file #{compressed_path} does not match uncompressed file #{path}"
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Perform an in-place update of the repository from newly added gems.
|
||||
|
||||
def update_index
|
||||
make_temp_directories
|
||||
|
||||
specs_mtime = File.stat(@dest_specs_index).mtime
|
||||
newest_mtime = Time.at 0
|
||||
|
||||
updated_gems = gem_file_list.select do |gem|
|
||||
gem_mtime = File.stat(gem).mtime
|
||||
newest_mtime = gem_mtime if gem_mtime > newest_mtime
|
||||
gem_mtime >= specs_mtime
|
||||
end
|
||||
|
||||
if updated_gems.empty?
|
||||
say "No new gems"
|
||||
terminate_interaction 0
|
||||
end
|
||||
|
||||
specs = map_gems_to_specs updated_gems
|
||||
prerelease, released = specs.partition {|s| s.version.prerelease? }
|
||||
|
||||
files = build_marshal_gemspecs specs
|
||||
|
||||
Gem.time "Updated indexes" do
|
||||
update_specs_index released, @dest_specs_index, @specs_index
|
||||
update_specs_index released, @dest_latest_specs_index, @latest_specs_index
|
||||
update_specs_index(prerelease,
|
||||
@dest_prerelease_specs_index,
|
||||
@prerelease_specs_index)
|
||||
end
|
||||
|
||||
compress_indices
|
||||
|
||||
verbose = Gem.configuration.really_verbose
|
||||
|
||||
say "Updating production dir #{@dest_directory}" if verbose
|
||||
|
||||
files << @specs_index
|
||||
files << "#{@specs_index}.gz"
|
||||
files << @latest_specs_index
|
||||
files << "#{@latest_specs_index}.gz"
|
||||
files << @prerelease_specs_index
|
||||
files << "#{@prerelease_specs_index}.gz"
|
||||
|
||||
files = files.map do |path|
|
||||
path.sub(%r{^#{Regexp.escape @directory}/?}, "") # HACK?
|
||||
end
|
||||
|
||||
files.each do |file|
|
||||
src_name = File.join @directory, file
|
||||
dst_name = File.join @dest_directory, file # REFACTOR: duped above
|
||||
|
||||
FileUtils.mv src_name, dst_name, verbose: verbose,
|
||||
force: true
|
||||
|
||||
File.utime newest_mtime, newest_mtime, dst_name
|
||||
end
|
||||
ensure
|
||||
FileUtils.rm_rf @directory
|
||||
end
|
||||
|
||||
##
|
||||
# Combines specs in +index+ and +source+ then writes out a new copy to
|
||||
# +dest+. For a latest index, does not ensure the new file is minimal.
|
||||
|
||||
def update_specs_index(index, source, dest)
|
||||
Gem.load_safe_marshal
|
||||
specs_index = Gem::SafeMarshal.safe_load Gem.read_binary(source)
|
||||
|
||||
index.each do |spec|
|
||||
platform = spec.original_platform
|
||||
platform = Gem::Platform::RUBY if platform.nil? || platform.empty?
|
||||
specs_index << [spec.name, spec.version, platform]
|
||||
end
|
||||
|
||||
specs_index = compact_specs specs_index.uniq.sort
|
||||
|
||||
File.open dest, "wb" do |io|
|
||||
Marshal.dump specs_index, io
|
||||
end
|
||||
end
|
||||
end
|
|
@ -556,7 +556,7 @@ RSpec.describe "bundle install with gem sources" do
|
|||
end
|
||||
|
||||
it "fails gracefully when downloading an invalid specification from the full index" do
|
||||
build_repo2 do
|
||||
build_repo2(build_compact_index: false) do
|
||||
build_gem "ajp-rails", "0.0.0", gemspec: false, skip_validation: true do |s|
|
||||
bad_deps = [["ruby-ajp", ">= 0.2.0"], ["rails", ">= 0.14"]]
|
||||
s.
|
||||
|
|
|
@ -44,7 +44,7 @@ RSpec.describe "compact index api" do
|
|||
end
|
||||
|
||||
it "should handle case sensitivity conflicts" do
|
||||
build_repo4 do
|
||||
build_repo4(build_compact_index: false) do
|
||||
build_gem "rack", "1.0" do |s|
|
||||
s.add_runtime_dependency("Rack", "0.1")
|
||||
end
|
||||
|
|
|
@ -191,25 +191,25 @@ module Spec
|
|||
end
|
||||
end
|
||||
|
||||
def build_repo2(&blk)
|
||||
def build_repo2(**kwargs, &blk)
|
||||
FileUtils.rm_rf gem_repo2
|
||||
FileUtils.cp_r gem_repo1, gem_repo2
|
||||
update_repo2(&blk) if block_given?
|
||||
update_repo2(**kwargs, &blk) if block_given?
|
||||
end
|
||||
|
||||
# A repo that has no pre-installed gems included. (The caller completely
|
||||
# determines the contents with the block.)
|
||||
def build_repo4(&blk)
|
||||
def build_repo4(**kwargs, &blk)
|
||||
FileUtils.rm_rf gem_repo4
|
||||
build_repo(gem_repo4, &blk)
|
||||
build_repo(gem_repo4, **kwargs, &blk)
|
||||
end
|
||||
|
||||
def update_repo4(&blk)
|
||||
update_repo(gem_repo4, &blk)
|
||||
end
|
||||
|
||||
def update_repo2(&blk)
|
||||
update_repo(gem_repo2, &blk)
|
||||
def update_repo2(**kwargs, &blk)
|
||||
update_repo(gem_repo2, **kwargs, &blk)
|
||||
end
|
||||
|
||||
def build_security_repo
|
||||
|
@ -227,12 +227,12 @@ module Spec
|
|||
end
|
||||
end
|
||||
|
||||
def build_repo(path, &blk)
|
||||
def build_repo(path, **kwargs, &blk)
|
||||
return if File.directory?(path)
|
||||
|
||||
FileUtils.mkdir_p("#{path}/gems")
|
||||
|
||||
update_repo(path, &blk)
|
||||
update_repo(path,**kwargs, &blk)
|
||||
end
|
||||
|
||||
def check_test_gems!
|
||||
|
@ -249,7 +249,7 @@ module Spec
|
|||
end
|
||||
end
|
||||
|
||||
def update_repo(path)
|
||||
def update_repo(path, build_compact_index: true)
|
||||
if path == gem_repo1 && caller.first.split(" ").last == "`build_repo`"
|
||||
raise "Updating gem_repo1 is unsupported -- use gem_repo2 instead"
|
||||
end
|
||||
|
@ -258,7 +258,12 @@ module Spec
|
|||
@_build_repo = File.basename(path)
|
||||
yield
|
||||
with_gem_path_as Path.base_system_gem_path do
|
||||
gem_command :generate_index, dir: path
|
||||
Dir[Spec::Path.base_system_gem_path.join("gems/rubygems-generate_index*/lib")].first ||
|
||||
raise("Could not find rubygems-generate_index lib directory in #{Spec::Path.base_system_gem_path}")
|
||||
|
||||
command = "generate_index"
|
||||
command += " --no-compact" if !build_compact_index && gem_command(command + " --help").include?("--[no-]compact")
|
||||
gem_command command, dir: path
|
||||
end
|
||||
ensure
|
||||
@_build_path = nil
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative "helper"
|
||||
require "rubygems/indexer"
|
||||
require "rubygems/commands/generate_index_command"
|
||||
|
||||
class TestGemCommandsGenerateIndexCommand < Gem::TestCase
|
||||
def setup
|
||||
super
|
||||
|
||||
@cmd = Gem::Commands::GenerateIndexCommand.new
|
||||
@cmd.options[:directory] = @gemhome
|
||||
end
|
||||
|
||||
def test_execute
|
||||
use_ui @ui do
|
||||
@cmd.execute
|
||||
end
|
||||
|
||||
specs = File.join @gemhome, "specs.4.8.gz"
|
||||
|
||||
assert File.exist?(specs), specs
|
||||
end
|
||||
|
||||
def test_execute_no_modern
|
||||
@cmd.options[:modern] = false
|
||||
|
||||
use_ui @ui do
|
||||
@cmd.execute
|
||||
end
|
||||
|
||||
specs = File.join @gemhome, "specs.4.8.gz"
|
||||
|
||||
assert File.exist?(specs), specs
|
||||
end
|
||||
|
||||
def test_handle_options_directory
|
||||
return if Gem.win_platform?
|
||||
refute_equal "/nonexistent", @cmd.options[:directory]
|
||||
|
||||
@cmd.handle_options %w[--directory /nonexistent]
|
||||
|
||||
assert_equal "/nonexistent", @cmd.options[:directory]
|
||||
end
|
||||
|
||||
def test_handle_options_directory_windows
|
||||
return unless Gem.win_platform?
|
||||
|
||||
refute_equal "/nonexistent", @cmd.options[:directory]
|
||||
|
||||
@cmd.handle_options %w[--directory C:/nonexistent]
|
||||
|
||||
assert_equal "C:/nonexistent", @cmd.options[:directory]
|
||||
end
|
||||
|
||||
def test_handle_options_update
|
||||
@cmd.handle_options %w[--update]
|
||||
|
||||
assert @cmd.options[:update]
|
||||
end
|
||||
|
||||
def test_handle_options_modern
|
||||
use_ui @ui do
|
||||
@cmd.handle_options %w[--modern]
|
||||
end
|
||||
|
||||
assert_equal \
|
||||
"WARNING: The \"--modern\" option has been deprecated and will be removed in Rubygems 4.0. Modern indexes (specs, latest_specs, and prerelease_specs) are always generated, so this option is not needed.\n",
|
||||
@ui.error
|
||||
end
|
||||
|
||||
def test_handle_options_no_modern
|
||||
use_ui @ui do
|
||||
@cmd.handle_options %w[--no-modern]
|
||||
end
|
||||
|
||||
assert_equal \
|
||||
"WARNING: The \"--no-modern\" option has been deprecated and will be removed in Rubygems 4.0. The `--no-modern` option is currently ignored. Modern indexes (specs, latest_specs, and prerelease_specs) are always generated.\n",
|
||||
@ui.error
|
||||
end
|
||||
end
|
|
@ -1,380 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative "helper"
|
||||
require "rubygems/indexer"
|
||||
|
||||
class TestGemIndexer < Gem::TestCase
|
||||
def setup
|
||||
super
|
||||
|
||||
util_make_gems
|
||||
|
||||
@d2_0 = util_spec "d", "2.0" do |s|
|
||||
s.date = Gem::Specification::TODAY - 86_400 * 3
|
||||
end
|
||||
util_build_gem @d2_0
|
||||
|
||||
@d2_0_a = util_spec "d", "2.0.a"
|
||||
util_build_gem @d2_0_a
|
||||
|
||||
@d2_0_b = util_spec "d", "2.0.b"
|
||||
util_build_gem @d2_0_b
|
||||
|
||||
@default = new_default_spec "default", 2
|
||||
install_default_gems @default
|
||||
|
||||
@indexerdir = File.join(@tempdir, "indexer")
|
||||
|
||||
gems = File.join(@indexerdir, "gems")
|
||||
FileUtils.mkdir_p gems
|
||||
FileUtils.mv Dir[File.join(@gemhome, "cache", "*.gem")], gems
|
||||
|
||||
@indexer = Gem::Indexer.new(@indexerdir)
|
||||
end
|
||||
|
||||
def teardown
|
||||
FileUtils.rm_rf(@indexer.directory)
|
||||
ensure
|
||||
super
|
||||
end
|
||||
|
||||
def with_indexer(dir, **opts)
|
||||
indexer = Gem::Indexer.new(dir, **opts)
|
||||
build_directory = indexer.directory
|
||||
yield indexer
|
||||
ensure
|
||||
FileUtils.rm_rf(build_directory) if build_directory
|
||||
end
|
||||
|
||||
def test_initialize
|
||||
assert_equal @indexerdir, @indexer.dest_directory
|
||||
Dir.mktmpdir("gem_generate_index") do |tmpdir|
|
||||
assert_match(%r{#{tmpdir.match(/.*-/)}}, @indexer.directory) # rubocop:disable Style/RegexpLiteral
|
||||
end
|
||||
|
||||
with_indexer(@indexerdir) do |indexer|
|
||||
assert_predicate indexer, :build_modern
|
||||
end
|
||||
|
||||
with_indexer(@indexerdir, build_modern: true) do |indexer|
|
||||
assert_predicate indexer, :build_modern
|
||||
end
|
||||
end
|
||||
|
||||
def test_build_indices
|
||||
@indexer.make_temp_directories
|
||||
|
||||
use_ui @ui do
|
||||
@indexer.build_indices
|
||||
end
|
||||
|
||||
specs_path = File.join @indexer.directory, "specs.#{@marshal_version}"
|
||||
specs_dump = Gem.read_binary specs_path
|
||||
specs = Marshal.load specs_dump
|
||||
|
||||
expected = [["a", Gem::Version.new("1"), "ruby"],
|
||||
["a", Gem::Version.new("2"), "ruby"],
|
||||
["a_evil", Gem::Version.new("9"), "ruby"],
|
||||
["b", Gem::Version.new("2"), "ruby"],
|
||||
["c", Gem::Version.new("1.2"), "ruby"],
|
||||
["d", Gem::Version.new("2.0"), "ruby"],
|
||||
["dep_x", Gem::Version.new("1"), "ruby"],
|
||||
["pl", Gem::Version.new("1"), "i386-linux"],
|
||||
["x", Gem::Version.new("1"), "ruby"]]
|
||||
|
||||
assert_equal expected, specs
|
||||
|
||||
latest_specs_path = File.join(@indexer.directory,
|
||||
"latest_specs.#{@marshal_version}")
|
||||
latest_specs_dump = Gem.read_binary latest_specs_path
|
||||
latest_specs = Marshal.load latest_specs_dump
|
||||
|
||||
expected = [["a", Gem::Version.new("2"), "ruby"],
|
||||
["a_evil", Gem::Version.new("9"), "ruby"],
|
||||
["b", Gem::Version.new("2"), "ruby"],
|
||||
["c", Gem::Version.new("1.2"), "ruby"],
|
||||
["d", Gem::Version.new("2.0"), "ruby"],
|
||||
["dep_x", Gem::Version.new("1"), "ruby"],
|
||||
["pl", Gem::Version.new("1"), "i386-linux"],
|
||||
["x", Gem::Version.new("1"), "ruby"]]
|
||||
|
||||
assert_equal expected, latest_specs, "latest_specs"
|
||||
end
|
||||
|
||||
def test_generate_index
|
||||
use_ui @ui do
|
||||
@indexer.generate_index
|
||||
end
|
||||
|
||||
quickdir = File.join @indexerdir, "quick"
|
||||
marshal_quickdir = File.join quickdir, "Marshal.#{@marshal_version}"
|
||||
|
||||
assert_directory_exists quickdir
|
||||
assert_directory_exists marshal_quickdir
|
||||
|
||||
assert_indexed marshal_quickdir, "#{File.basename(@a1.spec_file)}.rz"
|
||||
assert_indexed marshal_quickdir, "#{File.basename(@a2.spec_file)}.rz"
|
||||
|
||||
refute_indexed marshal_quickdir, File.basename(@c1_2.spec_file)
|
||||
|
||||
assert_indexed @indexerdir, "specs.#{@marshal_version}"
|
||||
assert_indexed @indexerdir, "specs.#{@marshal_version}.gz"
|
||||
|
||||
assert_indexed @indexerdir, "latest_specs.#{@marshal_version}"
|
||||
assert_indexed @indexerdir, "latest_specs.#{@marshal_version}.gz"
|
||||
|
||||
refute_directory_exists @indexer.directory
|
||||
end
|
||||
|
||||
def test_generate_index_modern
|
||||
@indexer.build_modern = true
|
||||
|
||||
use_ui @ui do
|
||||
@indexer.generate_index
|
||||
end
|
||||
|
||||
refute_indexed @indexerdir, "yaml"
|
||||
refute_indexed @indexerdir, "yaml.Z"
|
||||
refute_indexed @indexerdir, "Marshal.#{@marshal_version}"
|
||||
refute_indexed @indexerdir, "Marshal.#{@marshal_version}.Z"
|
||||
|
||||
quickdir = File.join @indexerdir, "quick"
|
||||
marshal_quickdir = File.join quickdir, "Marshal.#{@marshal_version}"
|
||||
|
||||
assert_directory_exists quickdir, "quickdir should be directory"
|
||||
assert_directory_exists marshal_quickdir
|
||||
|
||||
refute_indexed quickdir, "index"
|
||||
refute_indexed quickdir, "index.rz"
|
||||
|
||||
refute_indexed quickdir, "latest_index"
|
||||
refute_indexed quickdir, "latest_index.rz"
|
||||
|
||||
refute_indexed quickdir, "#{File.basename(@a1.spec_file)}.rz"
|
||||
refute_indexed quickdir, "#{File.basename(@a2.spec_file)}.rz"
|
||||
refute_indexed quickdir, "#{File.basename(@b2.spec_file)}.rz"
|
||||
refute_indexed quickdir, "#{File.basename(@c1_2.spec_file)}.rz"
|
||||
|
||||
refute_indexed quickdir, "#{@pl1.original_name}.gemspec.rz"
|
||||
refute_indexed quickdir, "#{File.basename(@pl1.spec_file)}.rz"
|
||||
|
||||
assert_indexed marshal_quickdir, "#{File.basename(@a1.spec_file)}.rz"
|
||||
assert_indexed marshal_quickdir, "#{File.basename(@a2.spec_file)}.rz"
|
||||
|
||||
refute_indexed quickdir, File.basename(@c1_2.spec_file).to_s
|
||||
refute_indexed marshal_quickdir, File.basename(@c1_2.spec_file).to_s
|
||||
|
||||
assert_indexed @indexerdir, "specs.#{@marshal_version}"
|
||||
assert_indexed @indexerdir, "specs.#{@marshal_version}.gz"
|
||||
|
||||
assert_indexed @indexerdir, "latest_specs.#{@marshal_version}"
|
||||
assert_indexed @indexerdir, "latest_specs.#{@marshal_version}.gz"
|
||||
end
|
||||
|
||||
def test_generate_index_modern_back_to_back
|
||||
@indexer.build_modern = true
|
||||
|
||||
use_ui @ui do
|
||||
@indexer.generate_index
|
||||
end
|
||||
|
||||
with_indexer @indexerdir do |indexer|
|
||||
indexer.build_modern = true
|
||||
|
||||
use_ui @ui do
|
||||
indexer.generate_index
|
||||
end
|
||||
quickdir = File.join @indexerdir, "quick"
|
||||
marshal_quickdir = File.join quickdir, "Marshal.#{@marshal_version}"
|
||||
|
||||
assert_directory_exists quickdir
|
||||
assert_directory_exists marshal_quickdir
|
||||
|
||||
assert_indexed marshal_quickdir, "#{File.basename(@a1.spec_file)}.rz"
|
||||
assert_indexed marshal_quickdir, "#{File.basename(@a2.spec_file)}.rz"
|
||||
|
||||
assert_indexed @indexerdir, "specs.#{@marshal_version}"
|
||||
assert_indexed @indexerdir, "specs.#{@marshal_version}.gz"
|
||||
|
||||
assert_indexed @indexerdir, "latest_specs.#{@marshal_version}"
|
||||
assert_indexed @indexerdir, "latest_specs.#{@marshal_version}.gz"
|
||||
end
|
||||
end
|
||||
|
||||
def test_generate_index_ui
|
||||
use_ui @ui do
|
||||
@indexer.generate_index
|
||||
end
|
||||
|
||||
assert_match(/^\.\.\.\.\.\.\.\.\.\.\.\.$/, @ui.output)
|
||||
assert_match(/^Generating Marshal quick index gemspecs for 12 gems$/, @ui.output)
|
||||
assert_match(/^Complete$/, @ui.output)
|
||||
assert_match(/^Generating specs index$/, @ui.output)
|
||||
assert_match(/^Generating latest specs index$/, @ui.output)
|
||||
assert_match(/^Generating prerelease specs index$/, @ui.output)
|
||||
assert_match(/^Complete$/, @ui.output)
|
||||
assert_match(/^Compressing indices$/, @ui.output)
|
||||
|
||||
assert_equal "", @ui.error
|
||||
end
|
||||
|
||||
def test_generate_index_specs
|
||||
use_ui @ui do
|
||||
@indexer.generate_index
|
||||
end
|
||||
|
||||
specs_path = File.join @indexerdir, "specs.#{@marshal_version}"
|
||||
|
||||
specs_dump = Gem.read_binary specs_path
|
||||
specs = Marshal.load specs_dump
|
||||
|
||||
expected = [
|
||||
["a", Gem::Version.new(1), "ruby"],
|
||||
["a", Gem::Version.new(2), "ruby"],
|
||||
["a_evil", Gem::Version.new(9), "ruby"],
|
||||
["b", Gem::Version.new(2), "ruby"],
|
||||
["c", Gem::Version.new("1.2"), "ruby"],
|
||||
["d", Gem::Version.new("2.0"), "ruby"],
|
||||
["dep_x", Gem::Version.new(1), "ruby"],
|
||||
["pl", Gem::Version.new(1), "i386-linux"],
|
||||
["x", Gem::Version.new(1), "ruby"],
|
||||
]
|
||||
|
||||
assert_equal expected, specs
|
||||
|
||||
assert_same specs[0].first, specs[1].first,
|
||||
"identical names not identical"
|
||||
|
||||
assert_same specs[0][1], specs[-1][1],
|
||||
"identical versions not identical"
|
||||
|
||||
assert_same specs[0].last, specs[1].last,
|
||||
"identical platforms not identical"
|
||||
|
||||
refute_same specs[1][1], specs[5][1],
|
||||
"different versions not different"
|
||||
end
|
||||
|
||||
def test_generate_index_latest_specs
|
||||
use_ui @ui do
|
||||
@indexer.generate_index
|
||||
end
|
||||
|
||||
latest_specs_path = File.join @indexerdir, "latest_specs.#{@marshal_version}"
|
||||
|
||||
latest_specs_dump = Gem.read_binary latest_specs_path
|
||||
latest_specs = Marshal.load latest_specs_dump
|
||||
|
||||
expected = [
|
||||
["a", Gem::Version.new(2), "ruby"],
|
||||
["a_evil", Gem::Version.new(9), "ruby"],
|
||||
["b", Gem::Version.new(2), "ruby"],
|
||||
["c", Gem::Version.new("1.2"), "ruby"],
|
||||
["d", Gem::Version.new("2.0"), "ruby"],
|
||||
["dep_x", Gem::Version.new(1), "ruby"],
|
||||
["pl", Gem::Version.new(1), "i386-linux"],
|
||||
["x", Gem::Version.new(1), "ruby"],
|
||||
]
|
||||
|
||||
assert_equal expected, latest_specs
|
||||
|
||||
assert_same latest_specs[0][1], latest_specs[2][1],
|
||||
"identical versions not identical"
|
||||
|
||||
assert_same latest_specs[0].last, latest_specs[1].last,
|
||||
"identical platforms not identical"
|
||||
end
|
||||
|
||||
def test_generate_index_prerelease_specs
|
||||
use_ui @ui do
|
||||
@indexer.generate_index
|
||||
end
|
||||
|
||||
prerelease_specs_path = File.join @indexerdir, "prerelease_specs.#{@marshal_version}"
|
||||
|
||||
prerelease_specs_dump = Gem.read_binary prerelease_specs_path
|
||||
prerelease_specs = Marshal.load prerelease_specs_dump
|
||||
|
||||
assert_equal [["a", Gem::Version.new("3.a"), "ruby"],
|
||||
["d", Gem::Version.new("2.0.a"), "ruby"],
|
||||
["d", Gem::Version.new("2.0.b"), "ruby"]],
|
||||
prerelease_specs
|
||||
end
|
||||
|
||||
##
|
||||
# Emulate the starting state of Gem::Specification in a live environment,
|
||||
# where it will carry the list of system gems
|
||||
def with_system_gems
|
||||
Gem::Specification.reset
|
||||
|
||||
sys_gem = util_spec "systemgem", "1.0"
|
||||
util_build_gem sys_gem
|
||||
install_default_gems sys_gem
|
||||
yield
|
||||
util_remove_gem sys_gem
|
||||
end
|
||||
|
||||
def test_update_index
|
||||
use_ui @ui do
|
||||
@indexer.generate_index
|
||||
end
|
||||
|
||||
quickdir = File.join @indexerdir, "quick"
|
||||
marshal_quickdir = File.join quickdir, "Marshal.#{@marshal_version}"
|
||||
|
||||
assert_directory_exists quickdir
|
||||
assert_directory_exists marshal_quickdir
|
||||
|
||||
@d2_1 = util_spec "d", "2.1"
|
||||
util_build_gem @d2_1
|
||||
@d2_1_tuple = [@d2_1.name, @d2_1.version, @d2_1.original_platform]
|
||||
|
||||
@d2_1_a = util_spec "d", "2.2.a"
|
||||
util_build_gem @d2_1_a
|
||||
@d2_1_a_tuple = [@d2_1_a.name, @d2_1_a.version, @d2_1_a.original_platform]
|
||||
|
||||
gems = File.join @indexerdir, "gems"
|
||||
|
||||
FileUtils.mv @d2_1.cache_file, gems
|
||||
FileUtils.mv @d2_1_a.cache_file, gems
|
||||
|
||||
with_system_gems do
|
||||
use_ui @ui do
|
||||
@indexer.update_index
|
||||
end
|
||||
|
||||
assert_indexed marshal_quickdir, "#{File.basename(@d2_1.spec_file)}.rz"
|
||||
|
||||
specs_index = Marshal.load Gem.read_binary(@indexer.dest_specs_index)
|
||||
|
||||
assert_includes specs_index, @d2_1_tuple
|
||||
refute_includes specs_index, @d2_1_a_tuple
|
||||
|
||||
latest_specs_index = Marshal.load \
|
||||
Gem.read_binary(@indexer.dest_latest_specs_index)
|
||||
|
||||
assert_includes latest_specs_index, @d2_1_tuple
|
||||
assert_includes latest_specs_index,
|
||||
[@d2_0.name, @d2_0.version, @d2_0.original_platform]
|
||||
refute_includes latest_specs_index, @d2_1_a_tuple
|
||||
|
||||
pre_specs_index = Marshal.load \
|
||||
Gem.read_binary(@indexer.dest_prerelease_specs_index)
|
||||
|
||||
assert_includes pre_specs_index, @d2_1_a_tuple
|
||||
refute_includes pre_specs_index, @d2_1_tuple
|
||||
|
||||
refute_directory_exists @indexer.directory
|
||||
end
|
||||
end
|
||||
|
||||
def assert_indexed(dir, name)
|
||||
file = File.join dir, name
|
||||
assert File.exist?(file), "#{file} does not exist"
|
||||
end
|
||||
|
||||
def refute_indexed(dir, name)
|
||||
file = File.join dir, name
|
||||
refute File.exist?(file), "#{file} exists"
|
||||
end
|
||||
end
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
require_relative "helper"
|
||||
require "rubygems/source"
|
||||
require "rubygems/indexer"
|
||||
|
||||
class TestGemSource < Gem::TestCase
|
||||
def tuple(*args)
|
||||
|
@ -55,7 +54,8 @@ class TestGemSource < Gem::TestCase
|
|||
end
|
||||
|
||||
def test_dependency_resolver_set_file_uri
|
||||
Gem::Indexer.new(@tempdir).generate_index
|
||||
File.write(File.join(@tempdir, "prerelease_specs.4.8.gz"), Gem::Util.gzip("\x04\x08[\x05".b))
|
||||
File.write(File.join(@tempdir, "specs.4.8.gz"), Gem::Util.gzip("\x04\x08[\x05".b))
|
||||
|
||||
source = Gem::Source.new "file://#{@tempdir}/"
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче