Skip to content

Commit

Permalink
Showing 23 changed files with 582 additions and 522 deletions.
4 changes: 2 additions & 2 deletions lib/ruby/stdlib/rubygems.rb
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@
require 'thread'

module Gem
VERSION = '2.4.5'
VERSION = '2.4.6'
end

# Must be first since it unloads the prelude from 1.9.2
@@ -598,7 +598,7 @@ def self.load_yaml

unless test_syck
begin
gem 'psych', '~> 1.2', '>= 1.2.1'
gem 'psych', '>= 1.2.1'
rescue Gem::LoadError
# It's OK if the user does not have the psych gem installed. We will
# attempt to require the stdlib version
5 changes: 2 additions & 3 deletions lib/ruby/stdlib/rubygems/basic_specification.rb
Original file line number Diff line number Diff line change
@@ -61,8 +61,7 @@ def contains_requirable_file? file
@contains_requirable_file ||= {}
@contains_requirable_file[file] ||=
begin
if instance_variable_defined?(:@ignored) or
instance_variable_defined?('@ignored') then
if instance_variable_defined?(:@ignored) then
return false
elsif missing_extensions? then
@ignored = true
@@ -145,7 +144,7 @@ def full_require_paths
File.join full_gem_path, path
end

full_paths.unshift extension_dir unless @extensions.nil? || @extensions.empty?
full_paths << extension_dir unless @extensions.nil? || @extensions.empty?

full_paths
end
4 changes: 2 additions & 2 deletions lib/ruby/stdlib/rubygems/commands/help_command.rb
Original file line number Diff line number Diff line change
@@ -176,7 +176,7 @@ class Gem::Commands::HelpCommand < Gem::Command
Ruby Version and Engine Dependency
==================================
You can specifiy the version, engine and engine version of ruby to use with
You can specify 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.
@@ -223,7 +223,7 @@ class Gem::Commands::HelpCommand < Gem::Command
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:
default. This may be overridden with the :development_group option:
gemspec development_group: :other
4 changes: 3 additions & 1 deletion lib/ruby/stdlib/rubygems/commands/open_command.rb
Original file line number Diff line number Diff line change
@@ -61,7 +61,9 @@ def open_gem name
end

def open_editor path
system(*@editor.split(/\s+/) + [path])
Dir.chdir(path) do
system(*@editor.split(/\s+/) + [path])
end
end

def spec_for name
2 changes: 1 addition & 1 deletion lib/ruby/stdlib/rubygems/commands/yank_command.rb
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ def description # :nodoc:
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
http://help.rubygems.org for permanent removal. Be sure to mention this
as the reason for the removal request.
EOF
end
3 changes: 1 addition & 2 deletions lib/ruby/stdlib/rubygems/compatibility.rb
Original file line number Diff line number Diff line change
@@ -20,8 +20,7 @@ module Gem

$LOADED_FEATURES.delete Gem::QuickLoader.path_to_full_rubygems_library

if $LOADED_FEATURES.any? do |path| path.end_with? '/rubygems.rb' end then
# TODO path does not exist here
if path = $LOADED_FEATURES.find {|n| n.end_with? '/rubygems.rb'} then
raise LoadError, "another rubygems is already loaded from #{path}"
end

12 changes: 11 additions & 1 deletion lib/ruby/stdlib/rubygems/dependency_installer.rb
Original file line number Diff line number Diff line change
@@ -218,7 +218,17 @@ def find_gems_with_sources dep, best_only=false # :nodoc:
tuples, errors = Gem::SpecFetcher.fetcher.search_for_dependency dep

if best_only && !tuples.empty?
tuples.sort! { |a,b| b[0].version <=> a[0].version }
tuples.sort! do |a,b|
if b[0].version == a[0].version
if b[0].platform != Gem::Platform::RUBY
1
else
-1
end
else
b[0].version <=> a[0].version
end
end
tuples = [tuples.first]
end

2 changes: 1 addition & 1 deletion lib/ruby/stdlib/rubygems/installer.rb
Original file line number Diff line number Diff line change
@@ -681,7 +681,7 @@ def app_script_text(bin_file_name)
# return the stub script text used to launch the true Ruby script

def windows_stub_script(bindir, bin_file_name)
ruby = Gem.ruby.chomp('"').tr(File::SEPARATOR, "\\")
ruby = Gem.ruby.gsub(/^\"|\"$/, "").tr(File::SEPARATOR, "\\")
return <<-TEXT
@ECHO OFF
IF NOT "%~f0" == "~f0" GOTO :WinNT
3 changes: 2 additions & 1 deletion lib/ruby/stdlib/rubygems/package.rb
Original file line number Diff line number Diff line change
@@ -366,8 +366,9 @@ def extract_tar_gz io, destination_dir, pattern = "*" # :nodoc:

FileUtils.mkdir_p mkdir, mkdir_options

open destination, 'wb', entry.header.mode do |out|
open destination, 'wb' do |out|
out.write entry.read
FileUtils.chmod entry.header.mode, destination
end if entry.file?

verbose destination
8 changes: 4 additions & 4 deletions lib/ruby/stdlib/rubygems/package/tar_writer.rb
Original file line number Diff line number Diff line change
@@ -291,7 +291,7 @@ def mkdir(name, mode)

def split_name(name) # :nodoc:
if name.bytesize > 256
raise Gem::Package::TooLongFileName.new("File \"#{name}\" has a too long path (should be 256 or less)")
raise Gem::Package::TooLongFileName.new("File \"#{name}\" has a too long path (should be 256 or less)")
end

if name.bytesize <= 100 then
@@ -311,11 +311,11 @@ def split_name(name) # :nodoc:
name = newname

if name.bytesize > 100
raise Gem::Package::TooLongFileName.new("File \"#{prefix}/#{name}\" has a too long name (should be 100 or less)")
raise Gem::Package::TooLongFileName.new("File \"#{prefix}/#{name}\" has a too long name (should be 100 or less)")
end

if prefix.bytesize > 155 then
raise Gem::Package::TooLongFileName.new("File \"#{prefix}/#{name}\" has a too long base path (should be 155 or less)")
raise Gem::Package::TooLongFileName.new("File \"#{prefix}/#{name}\" has a too long base path (should be 155 or less)")
end
end

7 changes: 0 additions & 7 deletions lib/ruby/stdlib/rubygems/path_support.rb
Original file line number Diff line number Diff line change
@@ -42,13 +42,6 @@ def initialize(env=ENV)

private

##
# Set the Gem home directory (as reported by Gem.dir).

def home=(home)
@home = home.to_s
end

##
# Set the Gem search path (as reported by Gem.path).

2 changes: 1 addition & 1 deletion lib/ruby/stdlib/rubygems/psych_additions.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# This exists just to satify bugs in marshal'd gemspecs that
# This exists just to satisfy bugs in marshal'd gemspecs that
# contain a reference to YAML::PrivateType. We prune these out
# in Specification._load, but if we don't have the constant, Marshal
# blows up.
2 changes: 1 addition & 1 deletion lib/ruby/stdlib/rubygems/remote_fetcher.rb
Original file line number Diff line number Diff line change
@@ -103,7 +103,7 @@ def api_endpoint(uri)
# filename. Returns nil if the gem cannot be located.
#--
# Should probably be integrated with #download below, but that will be a
# larger, more emcompassing effort. -erikh
# larger, more encompassing effort. -erikh

def download_to_cache dependency
found, _ = Gem::SpecFetcher.fetcher.spec_for_dependency dependency
14 changes: 10 additions & 4 deletions lib/ruby/stdlib/rubygems/request_set.rb
Original file line number Diff line number Diff line change
@@ -116,7 +116,7 @@ def gem name, *reqs
if dep = @dependency_names[name] then
dep.requirement.concat reqs
else
dep = Gem::Dependency.new name, reqs
dep = Gem::Dependency.new name, *reqs
@dependency_names[name] = dep
@dependencies << dep
end
@@ -223,7 +223,7 @@ def install_from_gemdeps options, &block

if options.fetch :lock, true then
lockfile =
Gem::RequestSet::Lockfile.new self, gemdeps, gem_deps_api.dependencies
Gem::RequestSet::Lockfile.build self, gemdeps, gem_deps_api.dependencies
lockfile.write
end

@@ -275,8 +275,13 @@ def load_gemdeps path, without_groups = [], installing = false

@git_set.root_dir = @install_dir

lockfile = Gem::RequestSet::Lockfile.new self, path
lockfile.parse
lock_file = "#{File.expand_path(path)}.lock".untaint
begin
tokenizer = Gem::RequestSet::Lockfile::Tokenizer.from_file lock_file
parser = tokenizer.make_parser self, []
parser.parse
rescue Errno::ENOENT
end

gf = Gem::RequestSet::GemDependencyAPI.new self, path
gf.installing = installing
@@ -411,3 +416,4 @@ def tsort_each_child node # :nodoc:

require 'rubygems/request_set/gem_dependency_api'
require 'rubygems/request_set/lockfile'
require 'rubygems/request_set/lockfile/tokenizer'
8 changes: 4 additions & 4 deletions lib/ruby/stdlib/rubygems/request_set/gem_dependency_api.rb
Original file line number Diff line number Diff line change
@@ -367,11 +367,11 @@ def gem name, *requirements

@dependencies[name] =
if requirements.empty? and not source_set then
nil
Gem::Requirement.default
elsif source_set then
'!'
Gem::Requirement.source_set
else
requirements
Gem::Requirement.create requirements
end

return unless gem_platforms options
@@ -601,7 +601,7 @@ def gemspec options = {}
add_dependencies groups, [self_dep]
add_dependencies groups, spec.runtime_dependencies

@dependencies[spec.name] = '!'
@dependencies[spec.name] = Gem::Requirement.source_set

spec.dependencies.each do |dep|
@dependencies[dep.name] = dep.requirement
516 changes: 52 additions & 464 deletions lib/ruby/stdlib/rubygems/request_set/lockfile.rb

Large diffs are not rendered by default.

334 changes: 334 additions & 0 deletions lib/ruby/stdlib/rubygems/request_set/lockfile/parser.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,334 @@
class Gem::RequestSet::Lockfile::Parser
###
# Parses lockfiles

def initialize tokenizer, set, platforms, filename = nil
@tokens = tokenizer
@filename = filename
@set = set
@platforms = platforms
end

def parse
until @tokens.empty? do
type, data, column, line = get

case type
when :section then
@tokens.skip :newline

case data
when 'DEPENDENCIES' then
parse_DEPENDENCIES
when 'GIT' then
parse_GIT
when 'GEM' then
parse_GEM
when 'PATH' then
parse_PATH
when 'PLATFORMS' then
parse_PLATFORMS
else
type, = get until @tokens.empty? or peek.first == :section
end
else
raise "BUG: unhandled token #{type} (#{data.inspect}) at line #{line} column #{column}"
end
end
end

##
# Gets the next token for a Lockfile

def get expected_types = nil, expected_value = nil # :nodoc:
current_token = @tokens.shift

type, value, column, line = current_token

if expected_types and not Array(expected_types).include? type then
unget current_token

message = "unexpected token [#{type.inspect}, #{value.inspect}], " +
"expected #{expected_types.inspect}"

raise Gem::RequestSet::Lockfile::ParseError.new message, column, line, @filename
end

if expected_value and expected_value != value then
unget current_token

message = "unexpected token [#{type.inspect}, #{value.inspect}], " +
"expected [#{expected_types.inspect}, " +
"#{expected_value.inspect}]"

raise Gem::RequestSet::Lockfile::ParseError.new message, column, line, @filename
end

current_token
end

def parse_DEPENDENCIES # :nodoc:
while not @tokens.empty? and :text == peek.first do
_, name, = get :text

requirements = []

case peek[0]
when :bang then
get :bang

requirements << pinned_requirement(name)
when :l_paren then
get :l_paren

loop do
_, op, = get :requirement
_, version, = get :text

requirements << "#{op} #{version}"

break unless peek[0] == :comma

get :comma
end

get :r_paren

if peek[0] == :bang then
requirements.clear
requirements << pinned_requirement(name)

get :bang
end
end

@set.gem name, *requirements

skip :newline
end
end

def parse_GEM # :nodoc:
sources = []

while [:entry, 'remote'] == peek.first(2) do
get :entry, 'remote'
_, data, = get :text
skip :newline

sources << Gem::Source.new(data)
end

sources << Gem::Source.new(Gem::DEFAULT_HOST) if sources.empty?

get :entry, 'specs'

skip :newline

set = Gem::Resolver::LockSet.new sources
last_specs = nil

while not @tokens.empty? and :text == peek.first do
_, name, column, = get :text

case peek[0]
when :newline then
last_specs.each do |spec|
spec.add_dependency Gem::Dependency.new name if column == 6
end
when :l_paren then
get :l_paren

type, data, = get [:text, :requirement]

if type == :text and column == 4 then
version, platform = data.split '-', 2

platform =
platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY

last_specs = set.add name, version, platform
else
dependency = parse_dependency name, data

last_specs.each do |spec|
spec.add_dependency dependency
end
end

get :r_paren
else
raise "BUG: unknown token #{peek}"
end

skip :newline
end

@set.sets << set
end

def parse_GIT # :nodoc:
get :entry, 'remote'
_, repository, = get :text

skip :newline

get :entry, 'revision'
_, revision, = get :text

skip :newline

type, value = peek.first 2
if type == :entry and %w[branch ref tag].include? value then
get
get :text

skip :newline
end

get :entry, 'specs'

skip :newline

set = Gem::Resolver::GitSet.new
set.root_dir = @set.install_dir

last_spec = nil

while not @tokens.empty? and :text == peek.first do
_, name, column, = get :text

case peek[0]
when :newline then
last_spec.add_dependency Gem::Dependency.new name if column == 6
when :l_paren then
get :l_paren

type, data, = get [:text, :requirement]

if type == :text and column == 4 then
last_spec = set.add_git_spec name, data, repository, revision, true
else
dependency = parse_dependency name, data

last_spec.add_dependency dependency
end

get :r_paren
else
raise "BUG: unknown token #{peek}"
end

skip :newline
end

@set.sets << set
end

def parse_PATH # :nodoc:
get :entry, 'remote'
_, directory, = get :text

skip :newline

get :entry, 'specs'

skip :newline

set = Gem::Resolver::VendorSet.new
last_spec = nil

while not @tokens.empty? and :text == peek.first do
_, name, column, = get :text

case peek[0]
when :newline then
last_spec.add_dependency Gem::Dependency.new name if column == 6
when :l_paren then
get :l_paren

type, data, = get [:text, :requirement]

if type == :text and column == 4 then
last_spec = set.add_vendor_gem name, directory
else
dependency = parse_dependency name, data

last_spec.dependencies << dependency
end

get :r_paren
else
raise "BUG: unknown token #{peek}"
end

skip :newline
end

@set.sets << set
end

def parse_PLATFORMS # :nodoc:
while not @tokens.empty? and :text == peek.first do
_, name, = get :text

@platforms << name

skip :newline
end
end

##
# Parses the requirements following the dependency +name+ and the +op+ for
# the first token of the requirements and returns a Gem::Dependency object.

def parse_dependency name, op # :nodoc:
return Gem::Dependency.new name, op unless peek[0] == :text

_, version, = get :text

requirements = ["#{op} #{version}"]

while peek[0] == :comma do
get :comma
_, op, = get :requirement
_, version, = get :text

requirements << "#{op} #{version}"
end

Gem::Dependency.new name, requirements
end

private

def skip type # :nodoc:
@tokens.skip type
end

##
# Peeks at the next token for Lockfile

def peek # :nodoc:
@tokens.peek
end

def pinned_requirement name # :nodoc:
spec = @set.sets.select { |set|
Gem::Resolver::GitSet === set or
Gem::Resolver::VendorSet === set
}.map { |set|
set.specs[name]
}.compact.first

spec.version
end

##
# Ungets the last token retrieved by #get

def unget token # :nodoc:
@tokens.unshift token
end
end

108 changes: 108 additions & 0 deletions lib/ruby/stdlib/rubygems/request_set/lockfile/tokenizer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
require 'strscan'
require 'rubygems/request_set/lockfile/parser'

class Gem::RequestSet::Lockfile::Tokenizer
def self.from_file file
new File.read(file), file
end

def initialize input, filename = nil, line = 0, pos = 0
@line = line
@line_pos = pos
@tokens = []
@filename = filename
tokenize input
end

def make_parser set, platforms
Gem::RequestSet::Lockfile::Parser.new self, set, platforms, @filename
end

def to_a
@tokens
end

def skip type
@tokens.shift while not @tokens.empty? and peek.first == type
end

##
# Calculates the column (by byte) and the line of the current token based on
# +byte_offset+.

def token_pos byte_offset # :nodoc:
[byte_offset - @line_pos, @line]
end

def empty?
@tokens.empty?
end

def unshift token
@tokens.unshift token
end

def next_token
@tokens.shift
end
alias :shift :next_token

def peek
@tokens.first || [:EOF]
end

private

def tokenize input
s = StringScanner.new input

until s.eos? do
pos = s.pos

pos = s.pos if leading_whitespace = s.scan(/ +/)

if s.scan(/[<|=>]{7}/) then
message = "your #{@filename} contains merge conflict markers"
column, line = token_pos pos

raise Gem::RequestSet::Lockfile::ParseError.new message, column, line, @filename
end

@tokens <<
case
when s.scan(/\r?\n/) then
token = [:newline, nil, *token_pos(pos)]
@line_pos = s.pos
@line += 1
token
when s.scan(/[A-Z]+/) then
if leading_whitespace then
text = s.matched
text += s.scan(/[^\s)]*/).to_s # in case of no match
[:text, text, *token_pos(pos)]
else
[:section, s.matched, *token_pos(pos)]
end
when s.scan(/([a-z]+):\s/) then
s.pos -= 1 # rewind for possible newline
[:entry, s[1], *token_pos(pos)]
when s.scan(/\(/) then
[:l_paren, nil, *token_pos(pos)]
when s.scan(/\)/) then
[:r_paren, nil, *token_pos(pos)]
when s.scan(/<=|>=|=|~>|<|>|!=/) then
[:requirement, s.matched, *token_pos(pos)]
when s.scan(/,/) then
[:comma, nil, *token_pos(pos)]
when s.scan(/!/) then
[:bang, nil, *token_pos(pos)]
when s.scan(/[^\s),!]*/) then
[:text, s.matched, *token_pos(pos)]
else
raise "BUG: can't create token for: #{s.string[s.pos..-1].inspect}"
end
end

@tokens
end
end
13 changes: 12 additions & 1 deletion lib/ruby/stdlib/rubygems/requirement.rb
Original file line number Diff line number Diff line change
@@ -23,6 +23,8 @@ class Gem::Requirement
"~>" => lambda { |v, r| v >= r && v.release < r.bump }
}

SOURCE_SET_REQUIREMENT = Struct.new(:for_lockfile).new "!" # :nodoc:

quoted = OPS.keys.map { |k| Regexp.quote k }.join "|"
PATTERN_RAW = "\\s*(#{quoted})?\\s*(#{Gem::Version::VERSION_PATTERN})\\s*" # :nodoc:

@@ -54,6 +56,8 @@ def self.create input
input
when Gem::Version, Array then
new input
when '!' then
source_set
else
if input.respond_to? :to_str then
new [input.to_str]
@@ -70,6 +74,13 @@ def self.default
new '>= 0'
end

###
# A source set requirement, used for Gemfiles and lockfiles

def self.source_set # :nodoc:
SOURCE_SET_REQUIREMENT
end

##
# Parse +obj+, returning an <tt>[op, version]</tt> pair. +obj+ can
# be a String or a Gem::Version.
@@ -171,7 +182,7 @@ def as_list # :nodoc:
end

def hash # :nodoc:
requirements.hash
requirements.sort.hash
end

def marshal_dump # :nodoc:
2 changes: 1 addition & 1 deletion lib/ruby/stdlib/rubygems/security/signer.rb
Original file line number Diff line number Diff line change
@@ -122,7 +122,7 @@ def sign data
# ~/.gem/gem-public_cert.pem.expired.%Y%m%d%H%M%S
#
# If the signing certificate can be re-signed the expired certificate will
# be saved as ~/.gem/gem-pubilc_cert.pem.expired.%Y%m%d%H%M%S where the
# be saved as ~/.gem/gem-public_cert.pem.expired.%Y%m%d%H%M%S where the
# expiry time (not after) is used for the timestamp.

def re_sign_key # :nodoc:
24 changes: 12 additions & 12 deletions lib/ruby/stdlib/rubygems/specification.rb
Original file line number Diff line number Diff line change
@@ -1028,8 +1028,8 @@ def self.load file
file = file.dup.untaint
return unless File.file?(file)

spec = LOAD_CACHE[file]
return spec if spec
_spec = LOAD_CACHE[file]
return _spec if _spec

code = if defined? Encoding
File.read file, :mode => 'r:UTF-8:-'
@@ -1040,15 +1040,15 @@ def self.load file
code.untaint

begin
spec = eval code, binding, file
_spec = eval code, binding, file

if Gem::Specification === spec
spec.loaded_from = File.expand_path file.to_s
LOAD_CACHE[file] = spec
return spec
if Gem::Specification === _spec
_spec.loaded_from = File.expand_path file.to_s
LOAD_CACHE[file] = _spec
return _spec
end

warn "[#{file}] isn't a Gem::Specification (#{spec.class} instead)."
warn "[#{file}] isn't a Gem::Specification (#{_spec.class} instead)."
rescue SignalException, SystemExit
raise
rescue SyntaxError, Exception => e
@@ -1350,7 +1350,7 @@ def add_dependency_with_type(dependency, type, *requirements)
end

unless dependency.respond_to?(:name) &&
dependency.respond_to?(:version_requirements)
dependency.respond_to?(:requirement)
dependency = Gem::Dependency.new(dependency.to_s, requirements, type)
end

@@ -1932,7 +1932,7 @@ def lib_files
# Singular accessor for #licenses

def license
val = licenses and val.first
licenses.first
end

##
@@ -2456,8 +2456,8 @@ def validate packaging = true
extend Gem::UserInteraction
normalize

nil_attributes = self.class.non_nil_attributes.find_all do |name|
instance_variable_get("@#{name}").nil?
nil_attributes = self.class.non_nil_attributes.find_all do |attrname|
instance_variable_get("@#{attrname}").nil?
end

unless nil_attributes.empty? then
19 changes: 18 additions & 1 deletion lib/ruby/stdlib/rubygems/test_case.rb
Original file line number Diff line number Diff line change
@@ -1426,5 +1426,22 @@ def self.key_path key_name

end

require 'rubygems/test_utilities'
# require dependencies that are not discoverable once GEM_HOME and GEM_PATH
# are wiped
begin
gem 'rake'
rescue Gem::LoadError
end

require 'rake/packagetask'

begin
gem 'rdoc'
require 'rdoc'
rescue LoadError, Gem::LoadError
end

require 'rubygems/test_utilities'
ENV['GEM_HOME'] = Dir.mktmpdir "home"
ENV['GEM_PATH'] = Dir.mktmpdir "path"
Gem.clear_paths
8 changes: 0 additions & 8 deletions lib/ruby/stdlib/rubygems/user_interaction.rb
Original file line number Diff line number Diff line change
@@ -396,10 +396,6 @@ def close
# Return a progress reporter object chosen from the current verbosity.

def progress_reporter(*args)
if self.kind_of?(Gem::SilentUI)
return SilentProgressReporter.new(@outs, *args)
end

case Gem.configuration.verbose
when nil, false
SilentProgressReporter.new(@outs, *args)
@@ -533,10 +529,6 @@ def done
# Return a download reporter object chosen from the current verbosity

def download_reporter(*args)
if self.kind_of?(Gem::SilentUI)
return SilentDownloadReporter.new(@outs, *args)
end

case Gem.configuration.verbose
when nil, false
SilentDownloadReporter.new(@outs, *args)

0 comments on commit c38758f

Please sign in to comment.