1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Merge RubyGems 3.2.31 and Bundler 2.2.31

This commit is contained in:
Hiroshi SHIBATA 2021-11-11 11:13:48 +09:00 committed by nagachika
parent e27381d289
commit b19b2e9867
111 changed files with 4469 additions and 376 deletions

View file

@ -552,7 +552,7 @@ module Bundler
method_option :version, :type => :boolean, :default => false, :aliases => "-v", :desc => "Set to show each gem version."
method_option :without, :type => :array, :default => [], :aliases => "-W", :banner => "GROUP[ GROUP...]", :desc => "Exclude gems that are part of the specified named group."
def viz
SharedHelpers.major_deprecation 2, "The `viz` command has been moved to the `bundle-viz` gem, see https://github.com/bundler/bundler-viz"
SharedHelpers.major_deprecation 2, "The `viz` command has been moved to the `bundle-viz` gem, see https://github.com/rubygems/bundler-graph"
require_relative "cli/viz"
Viz.new(options.dup).run
end
@ -575,6 +575,8 @@ module Bundler
:desc => "Generate a test directory for your library, either rspec, minitest or test-unit. Set a default with `bundle config set --global gem.test (rspec|minitest|test-unit)`."
method_option :ci, :type => :string, :lazy_default => Bundler.settings["gem.ci"] || "",
:desc => "Generate CI configuration, either GitHub Actions, Travis CI, GitLab CI or CircleCI. Set a default with `bundle config set --global gem.ci (github|travis|gitlab|circle)`"
method_option :linter, :type => :string, :lazy_default => Bundler.settings["gem.linter"] || "",
:desc => "Add a linter and code formatter, either RuboCop or Standard. Set a default with `bundle config set --global gem.linter (rubocop|standard)`"
method_option :github_username, :type => :string, :default => Bundler.settings["gem.github_username"], :banner => "Set your username on GitHub", :desc => "Fill in GitHub username on README so that you don't have to do it manually. Set a default with `bundle config set --global gem.github_username <your_username>`."
def gem(name)

View file

@ -163,15 +163,16 @@ module Bundler
templates.merge!("CHANGELOG.md.tt" => "CHANGELOG.md")
end
if ask_and_set(:rubocop, "Do you want to add rubocop as a dependency for gems you generate?",
"RuboCop is a static code analyzer that has out-of-the-box rules for many " \
"of the guidelines in the community style guide. " \
"For more information, see the RuboCop docs (https://docs.rubocop.org/en/stable/) " \
"and the Ruby Style Guides (https://github.com/rubocop-hq/ruby-style-guide).")
config[:rubocop] = true
config[:rubocop_version] = rubocop_version
config[:linter] = ask_and_set_linter
case config[:linter]
when "rubocop"
config[:linter_version] = rubocop_version
Bundler.ui.info "RuboCop enabled in config"
templates.merge!("rubocop.yml.tt" => ".rubocop.yml")
when "standard"
config[:linter_version] = standard_version
Bundler.ui.info "Standard enabled in config"
templates.merge!("standard.yml.tt" => ".standard.yml")
end
templates.merge!("exe/newgem.tt" => "exe/#{name}") if config[:exe]
@ -317,6 +318,58 @@ module Bundler
ci_template
end
def ask_and_set_linter
linter_template = options[:linter] || Bundler.settings["gem.linter"]
linter_template = deprecated_rubocop_option if linter_template.nil?
if linter_template.to_s.empty?
Bundler.ui.confirm "Do you want to add a code linter and formatter to your gem? " \
"Supported Linters:\n" \
"* RuboCop: https://rubocop.org\n" \
"* Standard: https://github.com/testdouble/standard\n" \
"\n"
Bundler.ui.info hint_text("linter")
result = Bundler.ui.ask "Enter a linter. rubocop/standard/(none):"
if result =~ /rubocop|standard/
linter_template = result
else
linter_template = false
end
end
if Bundler.settings["gem.linter"].nil?
Bundler.settings.set_global("gem.linter", linter_template)
end
# Once gem.linter safely set, unset the deprecated gem.rubocop
unless Bundler.settings["gem.rubocop"].nil?
Bundler.settings.set_global("gem.rubocop", nil)
end
if options[:linter] == Bundler.settings["gem.linter"]
Bundler.ui.info "#{options[:linter]} is already configured, ignoring --linter flag."
end
linter_template
end
def deprecated_rubocop_option
if !options[:rubocop].nil?
if options[:rubocop]
Bundler::SharedHelpers.major_deprecation 2, "--rubocop is deprecated, use --linter=rubocop"
"rubocop"
else
Bundler::SharedHelpers.major_deprecation 2, "--no-rubocop is deprecated, use --linter"
false
end
elsif !Bundler.settings["gem.rubocop"].nil?
Bundler::SharedHelpers.major_deprecation 2,
"config gem.rubocop is deprecated; we've updated your config to use gem.linter instead"
Bundler.settings["gem.rubocop"] ? "rubocop" : false
end
end
def bundler_dependency_version
v = Gem::Version.new(Bundler::VERSION)
req = v.segments[0..1]
@ -367,5 +420,13 @@ module Bundler
"1.21"
end
end
def standard_version
if Gem.ruby_version < Gem::Version.new("2.4.a") then "0.2.5"
elsif Gem.ruby_version < Gem::Version.new("2.5.a") then "1.0"
else
"1.3"
end
end
end
end

View file

@ -138,7 +138,7 @@ module Bundler
@dependency_changes = converge_dependencies
@local_changes = converge_locals
@locked_specs_incomplete_for_platform = !@locked_specs.for(expand_dependencies(requested_dependencies & locked_dependencies), true, true)
@locked_specs_incomplete_for_platform = !@locked_specs.for(requested_dependencies & expand_dependencies(locked_dependencies), true, true)
@requires = compute_requires
end
@ -234,16 +234,17 @@ module Bundler
end
def specs_for(groups)
groups = requested_groups if groups.empty?
return specs if groups.empty?
deps = dependencies_for(groups)
materialize(expand_dependencies(deps))
materialize(deps)
end
def dependencies_for(groups)
groups.map!(&:to_sym)
current_dependencies.reject do |d|
deps = current_dependencies.reject do |d|
(d.groups & groups).empty?
end
expand_dependencies(deps)
end
# Resolve all the dependencies specified in Gemfile. It ensures that

View file

@ -86,6 +86,7 @@ module Bundler
def warn_for_outdated_bundler_version
return unless bundler_version
return if bundler_version.segments.last == "dev"
prerelease_text = bundler_version.prerelease? ? " --pre" : ""
current_version = Gem::Version.create(Bundler::VERSION)
return unless current_version < bundler_version

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BUNDLE\-ADD" "1" "June 2021" "" ""
.TH "BUNDLE\-ADD" "1" "November 2021" "" ""
.
.SH "NAME"
\fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BUNDLE\-BINSTUBS" "1" "June 2021" "" ""
.TH "BUNDLE\-BINSTUBS" "1" "November 2021" "" ""
.
.SH "NAME"
\fBbundle\-binstubs\fR \- Install the binstubs of the listed gems

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BUNDLE\-CACHE" "1" "June 2021" "" ""
.TH "BUNDLE\-CACHE" "1" "November 2021" "" ""
.
.SH "NAME"
\fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BUNDLE\-CHECK" "1" "June 2021" "" ""
.TH "BUNDLE\-CHECK" "1" "November 2021" "" ""
.
.SH "NAME"
\fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BUNDLE\-CLEAN" "1" "June 2021" "" ""
.TH "BUNDLE\-CLEAN" "1" "November 2021" "" ""
.
.SH "NAME"
\fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BUNDLE\-CONFIG" "1" "June 2021" "" ""
.TH "BUNDLE\-CONFIG" "1" "November 2021" "" ""
.
.SH "NAME"
\fBbundle\-config\fR \- Set bundler configuration options
@ -462,13 +462,13 @@ export BUNDLE_GITHUB__COM=abcd0123generatedtoken:x\-oauth\-basic
.IP "" 0
.
.P
Note that any configured credentials will be redacted by informative commands such as \fBbundle config list\fR or \fBbundle config get\fR, unless you use the \fB\-\-parseable\fR flag\. This is to avoid unintentially leaking credentials when copy\-pasting bundler output\.
Note that any configured credentials will be redacted by informative commands such as \fBbundle config list\fR or \fBbundle config get\fR, unless you use the \fB\-\-parseable\fR flag\. This is to avoid unintentionally leaking credentials when copy\-pasting bundler output\.
.
.P
Also note that to guarantee a sane mapping between valid environment variable names and valid host names, bundler makes the following transformations:
.
.IP "\(bu" 4
Any \fB\-\fR characters in a host name are mapped to a triple dash (\fB___\fR) in the corresponding enviroment variable\.
Any \fB\-\fR characters in a host name are mapped to a triple dash (\fB___\fR) in the corresponding environment variable\.
.
.IP "\(bu" 4
Any \fB\.\fR characters in a host name are mapped to a double dash (\fB__\fR) in the corresponding environment variable\.

View file

@ -367,14 +367,14 @@ where you can use personal OAuth tokens:
Note that any configured credentials will be redacted by informative commands
such as `bundle config list` or `bundle config get`, unless you use the
`--parseable` flag. This is to avoid unintentially leaking credentials when
`--parseable` flag. This is to avoid unintentionally leaking credentials when
copy-pasting bundler output.
Also note that to guarantee a sane mapping between valid environment variable
names and valid host names, bundler makes the following transformations:
* Any `-` characters in a host name are mapped to a triple dash (`___`) in the
corresponding enviroment variable.
corresponding environment variable.
* Any `.` characters in a host name are mapped to a double dash (`__`) in the
corresponding environment variable.

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BUNDLE\-DOCTOR" "1" "June 2021" "" ""
.TH "BUNDLE\-DOCTOR" "1" "November 2021" "" ""
.
.SH "NAME"
\fBbundle\-doctor\fR \- Checks the bundle for common problems

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BUNDLE\-EXEC" "1" "June 2021" "" ""
.TH "BUNDLE\-EXEC" "1" "November 2021" "" ""
.
.SH "NAME"
\fBbundle\-exec\fR \- Execute a command in the context of the bundle

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BUNDLE\-GEM" "1" "June 2021" "" ""
.TH "BUNDLE\-GEM" "1" "November 2021" "" ""
.
.SH "NAME"
\fBbundle\-gem\fR \- Generate a project skeleton for creating a rubygem
@ -90,6 +90,19 @@ When Bundler is configured to not generate CI files, an interactive prompt will
When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\.
.
.TP
\fB\-\-linter\fR, \fB\-\-linter=rubocop\fR, \fB\-\-linter=standard\fR
Specify the linter and code formatter that Bundler should add to the project\'s development dependencies\. Acceptable values are \fBrubocop\fR and \fBstandard\fR\. A configuration file will be generated in the project directory\. Given no option is specified:
.
.IP
When Bundler is configured to add a linter, this defaults to Bundler\'s global config setting \fBgem\.linter\fR\.
.
.IP
When Bundler is configured not to add a linter, an interactive prompt will be displayed and the answer will be used for the current rubygem project\.
.
.IP
When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\.
.
.TP
\fB\-e\fR, \fB\-\-edit[=EDITOR]\fR
Open the resulting GEM_NAME\.gemspec in EDITOR, or the default editor if not specified\. The default is \fB$BUNDLER_EDITOR\fR, \fB$VISUAL\fR, or \fB$EDITOR\fR\.
.

View file

@ -92,6 +92,22 @@ configuration file using the following names:
the answer will be saved in Bundler's global config for future `bundle gem`
use.
* `--linter`, `--linter=rubocop`, `--linter=standard`:
Specify the linter and code formatter that Bundler should add to the
project's development dependencies. Acceptable values are `rubocop` and
`standard`. A configuration file will be generated in the project directory.
Given no option is specified:
When Bundler is configured to add a linter, this defaults to Bundler's
global config setting `gem.linter`.
When Bundler is configured not to add a linter, an interactive prompt
will be displayed and the answer will be used for the current rubygem project.
When Bundler is unconfigured, an interactive prompt will be displayed and
the answer will be saved in Bundler's global config for future `bundle gem`
use.
* `-e`, `--edit[=EDITOR]`:
Open the resulting GEM_NAME.gemspec in EDITOR, or the default editor if not
specified. The default is `$BUNDLER_EDITOR`, `$VISUAL`, or `$EDITOR`.

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BUNDLE\-INFO" "1" "June 2021" "" ""
.TH "BUNDLE\-INFO" "1" "November 2021" "" ""
.
.SH "NAME"
\fBbundle\-info\fR \- Show information for the given gem in your bundle

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BUNDLE\-INIT" "1" "June 2021" "" ""
.TH "BUNDLE\-INIT" "1" "November 2021" "" ""
.
.SH "NAME"
\fBbundle\-init\fR \- Generates a Gemfile into the current working directory

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BUNDLE\-INJECT" "1" "June 2021" "" ""
.TH "BUNDLE\-INJECT" "1" "November 2021" "" ""
.
.SH "NAME"
\fBbundle\-inject\fR \- Add named gem(s) with version requirements to Gemfile

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BUNDLE\-INSTALL" "1" "June 2021" "" ""
.TH "BUNDLE\-INSTALL" "1" "November 2021" "" ""
.
.SH "NAME"
\fBbundle\-install\fR \- Install the dependencies specified in your Gemfile

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BUNDLE\-LIST" "1" "June 2021" "" ""
.TH "BUNDLE\-LIST" "1" "November 2021" "" ""
.
.SH "NAME"
\fBbundle\-list\fR \- List all the gems in the bundle

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BUNDLE\-LOCK" "1" "June 2021" "" ""
.TH "BUNDLE\-LOCK" "1" "November 2021" "" ""
.
.SH "NAME"
\fBbundle\-lock\fR \- Creates / Updates a lockfile without installing

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BUNDLE\-OPEN" "1" "June 2021" "" ""
.TH "BUNDLE\-OPEN" "1" "November 2021" "" ""
.
.SH "NAME"
\fBbundle\-open\fR \- Opens the source directory for a gem in your bundle

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BUNDLE\-OUTDATED" "1" "June 2021" "" ""
.TH "BUNDLE\-OUTDATED" "1" "November 2021" "" ""
.
.SH "NAME"
\fBbundle\-outdated\fR \- List installed gems with newer versions available

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BUNDLE\-PLATFORM" "1" "June 2021" "" ""
.TH "BUNDLE\-PLATFORM" "1" "November 2021" "" ""
.
.SH "NAME"
\fBbundle\-platform\fR \- Displays platform compatibility information

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BUNDLE\-PRISTINE" "1" "June 2021" "" ""
.TH "BUNDLE\-PRISTINE" "1" "November 2021" "" ""
.
.SH "NAME"
\fBbundle\-pristine\fR \- Restores installed gems to their pristine condition

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BUNDLE\-REMOVE" "1" "June 2021" "" ""
.TH "BUNDLE\-REMOVE" "1" "November 2021" "" ""
.
.SH "NAME"
\fBbundle\-remove\fR \- Removes gems from the Gemfile

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BUNDLE\-SHOW" "1" "June 2021" "" ""
.TH "BUNDLE\-SHOW" "1" "November 2021" "" ""
.
.SH "NAME"
\fBbundle\-show\fR \- Shows all the gems in your bundle, or the path to a gem

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BUNDLE\-UPDATE" "1" "June 2021" "" ""
.TH "BUNDLE\-UPDATE" "1" "November 2021" "" ""
.
.SH "NAME"
\fBbundle\-update\fR \- Update your gems to the latest available versions

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BUNDLE\-VIZ" "1" "June 2021" "" ""
.TH "BUNDLE\-VIZ" "1" "November 2021" "" ""
.
.SH "NAME"
\fBbundle\-viz\fR \- Generates a visual dependency graph for your Gemfile

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "BUNDLE" "1" "June 2021" "" ""
.TH "BUNDLE" "1" "November 2021" "" ""
.
.SH "NAME"
\fBbundle\fR \- Ruby Dependency Management

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "GEMFILE" "5" "June 2021" "" ""
.TH "GEMFILE" "5" "November 2021" "" ""
.
.SH "NAME"
\fBGemfile\fR \- A format for describing gem dependencies for Ruby programs

View file

@ -265,7 +265,7 @@ module Bundler
return if manuals.empty?
Bundler::SharedHelpers.set_env "MANPATH", manuals.concat(
ENV["MANPATH"].to_s.split(File::PATH_SEPARATOR)
ENV["MANPATH"] ? ENV["MANPATH"].to_s.split(File::PATH_SEPARATOR) : [""]
).uniq.join(File::PATH_SEPARATOR)
end

View file

@ -56,7 +56,6 @@ module Bundler
@ref = ref
@revision = revision
@git = git
raise GitNotInstalledError.new if allow? && !Bundler.git_present?
end
def revision
@ -208,7 +207,11 @@ module Bundler
end
def allow?
@git ? @git.allow_git_ops? : true
allowed = @git ? @git.allow_git_ops? : true
raise GitNotInstalledError.new if allowed && !Bundler.git_present?
allowed
end
def with_path(&blk)

View file

@ -162,7 +162,7 @@ module Bundler
begin
s = Bundler.rubygems.spec_from_gem(path, Bundler.settings["trust-policy"])
spec.__swap__(s)
rescue StandardError
rescue Gem::Package::FormatError
Bundler.rm_rf(path)
raise
end

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require "tsort"
require_relative "vendored_tsort"
module Bundler
class SpecSet

View file

@ -14,7 +14,10 @@ gem "rake-compiler"
gem "<%= config[:test] %>", "~> <%= config[:test_framework_version] %>"
<%- end -%>
<%- if config[:rubocop] -%>
<%- if config[:linter] == "rubocop" -%>
gem "rubocop", "~> <%= config[:rubocop_version] %>"
gem "rubocop", "~> <%= config[:linter_version] %>"
<%- elsif config[:linter] == "standard" -%>
gem "standard", "~> <%= config[:linter_version] %>"
<%- end -%>

View file

@ -18,12 +18,16 @@ require "rspec/core/rake_task"
RSpec::Core::RakeTask.new(:spec)
<% end -%>
<% if config[:rubocop] -%>
<% if config[:linter] == "rubocop" -%>
<% default_task_names << :rubocop -%>
require "rubocop/rake_task"
RuboCop::RakeTask.new
<% elsif config[:linter] == "standard" -%>
<% default_task_names << :standard -%>
require "standard/rake"
<% end -%>
<% if config[:ext] -%>
<% default_task_names.unshift(:clobber, :compile) -%>

View file

@ -3,16 +3,16 @@
require_relative "lib/<%=config[:namespaced_path]%>/version"
Gem::Specification.new do |spec|
spec.name = <%= config[:name].inspect %>
spec.version = <%= config[:constant_name] %>::VERSION
spec.authors = [<%= config[:author].inspect %>]
spec.email = [<%= config[:email].inspect %>]
spec.name = <%= config[:name].inspect %>
spec.version = <%= config[:constant_name] %>::VERSION
spec.authors = [<%= config[:author].inspect %>]
spec.email = [<%= config[:email].inspect %>]
spec.summary = "TODO: Write a short summary, because RubyGems requires one."
spec.description = "TODO: Write a longer description or delete this line."
spec.homepage = "TODO: Put your gem's website or public repo URL here."
spec.summary = "TODO: Write a short summary, because RubyGems requires one."
spec.description = "TODO: Write a longer description or delete this line."
spec.homepage = "TODO: Put your gem's website or public repo URL here."
<%- if config[:mit] -%>
spec.license = "MIT"
spec.license = "MIT"
<%- end -%>
spec.required_ruby_version = ">= <%= config[:required_ruby_version] %>"
@ -29,11 +29,11 @@ Gem::Specification.new do |spec|
(f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
end
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
<%- if config[:ext] -%>
spec.extensions = ["ext/<%= config[:underscored_name] %>/extconf.rb"]
spec.extensions = ["ext/<%= config[:underscored_name] %>/extconf.rb"]
<%- end -%>
# Uncomment to register a new dependency of your gem

View file

@ -0,0 +1,4 @@
# For available configuration options, see:
# https://github.com/testdouble/standard
default_ignores: false

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'tsort'
require_relative '../../../../vendored_tsort'
require_relative 'dependency_graph/log'
require_relative 'dependency_graph/vertex'
@ -17,7 +17,7 @@ module Bundler::Molinillo
vertices.values.each { |v| yield v }
end
include TSort
include Bundler::TSort
# @!visibility private
alias tsort_each_node each

453
lib/bundler/vendor/tsort/lib/tsort.rb vendored Normal file
View file

@ -0,0 +1,453 @@
# frozen_string_literal: true
#--
# tsort.rb - provides a module for topological sorting and strongly connected components.
#++
#
#
# TSort implements topological sorting using Tarjan's algorithm for
# strongly connected components.
#
# TSort is designed to be able to be used with any object which can be
# interpreted as a directed graph.
#
# TSort requires two methods to interpret an object as a graph,
# tsort_each_node and tsort_each_child.
#
# * tsort_each_node is used to iterate for all nodes over a graph.
# * tsort_each_child is used to iterate for child nodes of a given node.
#
# The equality of nodes are defined by eql? and hash since
# TSort uses Hash internally.
#
# == A Simple Example
#
# The following example demonstrates how to mix the TSort module into an
# existing class (in this case, Hash). Here, we're treating each key in
# the hash as a node in the graph, and so we simply alias the required
# #tsort_each_node method to Hash's #each_key method. For each key in the
# hash, the associated value is an array of the node's child nodes. This
# choice in turn leads to our implementation of the required #tsort_each_child
# method, which fetches the array of child nodes and then iterates over that
# array using the user-supplied block.
#
# require 'tsort'
#
# class Hash
# include TSort
# alias tsort_each_node each_key
# def tsort_each_child(node, &block)
# fetch(node).each(&block)
# end
# end
#
# {1=>[2, 3], 2=>[3], 3=>[], 4=>[]}.tsort
# #=> [3, 2, 1, 4]
#
# {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}.strongly_connected_components
# #=> [[4], [2, 3], [1]]
#
# == A More Realistic Example
#
# A very simple `make' like tool can be implemented as follows:
#
# require 'tsort'
#
# class Make
# def initialize
# @dep = {}
# @dep.default = []
# end
#
# def rule(outputs, inputs=[], &block)
# triple = [outputs, inputs, block]
# outputs.each {|f| @dep[f] = [triple]}
# @dep[triple] = inputs
# end
#
# def build(target)
# each_strongly_connected_component_from(target) {|ns|
# if ns.length != 1
# fs = ns.delete_if {|n| Array === n}
# raise TSort::Cyclic.new("cyclic dependencies: #{fs.join ', '}")
# end
# n = ns.first
# if Array === n
# outputs, inputs, block = n
# inputs_time = inputs.map {|f| File.mtime f}.max
# begin
# outputs_time = outputs.map {|f| File.mtime f}.min
# rescue Errno::ENOENT
# outputs_time = nil
# end
# if outputs_time == nil ||
# inputs_time != nil && outputs_time <= inputs_time
# sleep 1 if inputs_time != nil && inputs_time.to_i == Time.now.to_i
# block.call
# end
# end
# }
# end
#
# def tsort_each_child(node, &block)
# @dep[node].each(&block)
# end
# include TSort
# end
#
# def command(arg)
# print arg, "\n"
# system arg
# end
#
# m = Make.new
# m.rule(%w[t1]) { command 'date > t1' }
# m.rule(%w[t2]) { command 'date > t2' }
# m.rule(%w[t3]) { command 'date > t3' }
# m.rule(%w[t4], %w[t1 t3]) { command 'cat t1 t3 > t4' }
# m.rule(%w[t5], %w[t4 t2]) { command 'cat t4 t2 > t5' }
# m.build('t5')
#
# == Bugs
#
# * 'tsort.rb' is wrong name because this library uses
# Tarjan's algorithm for strongly connected components.
# Although 'strongly_connected_components.rb' is correct but too long.
#
# == References
#
# R. E. Tarjan, "Depth First Search and Linear Graph Algorithms",
# <em>SIAM Journal on Computing</em>, Vol. 1, No. 2, pp. 146-160, June 1972.
#
module Bundler
module TSort
class Cyclic < StandardError
end
# Returns a topologically sorted array of nodes.
# The array is sorted from children to parents, i.e.
# the first element has no child and the last node has no parent.
#
# If there is a cycle, TSort::Cyclic is raised.
#
# class G
# include TSort
# def initialize(g)
# @g = g
# end
# def tsort_each_child(n, &b) @g[n].each(&b) end
# def tsort_each_node(&b) @g.each_key(&b) end
# end
#
# graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
# p graph.tsort #=> [4, 2, 3, 1]
#
# graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
# p graph.tsort # raises TSort::Cyclic
#
def tsort
each_node = method(:tsort_each_node)
each_child = method(:tsort_each_child)
TSort.tsort(each_node, each_child)
end
# Returns a topologically sorted array of nodes.
# The array is sorted from children to parents, i.e.
# the first element has no child and the last node has no parent.
#
# The graph is represented by _each_node_ and _each_child_.
# _each_node_ should have +call+ method which yields for each node in the graph.
# _each_child_ should have +call+ method which takes a node argument and yields for each child node.
#
# If there is a cycle, TSort::Cyclic is raised.
#
# g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
# each_node = lambda {|&b| g.each_key(&b) }
# each_child = lambda {|n, &b| g[n].each(&b) }
# p TSort.tsort(each_node, each_child) #=> [4, 2, 3, 1]
#
# g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
# each_node = lambda {|&b| g.each_key(&b) }
# each_child = lambda {|n, &b| g[n].each(&b) }
# p TSort.tsort(each_node, each_child) # raises TSort::Cyclic
#
def TSort.tsort(each_node, each_child)
TSort.tsort_each(each_node, each_child).to_a
end
# The iterator version of the #tsort method.
# <tt><em>obj</em>.tsort_each</tt> is similar to <tt><em>obj</em>.tsort.each</tt>, but
# modification of _obj_ during the iteration may lead to unexpected results.
#
# #tsort_each returns +nil+.
# If there is a cycle, TSort::Cyclic is raised.
#
# class G
# include TSort
# def initialize(g)
# @g = g
# end
# def tsort_each_child(n, &b) @g[n].each(&b) end
# def tsort_each_node(&b) @g.each_key(&b) end
# end
#
# graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
# graph.tsort_each {|n| p n }
# #=> 4
# # 2
# # 3
# # 1
#
def tsort_each(&block) # :yields: node
each_node = method(:tsort_each_node)
each_child = method(:tsort_each_child)
TSort.tsort_each(each_node, each_child, &block)
end
# The iterator version of the TSort.tsort method.
#
# The graph is represented by _each_node_ and _each_child_.
# _each_node_ should have +call+ method which yields for each node in the graph.
# _each_child_ should have +call+ method which takes a node argument and yields for each child node.
#
# g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
# each_node = lambda {|&b| g.each_key(&b) }
# each_child = lambda {|n, &b| g[n].each(&b) }
# TSort.tsort_each(each_node, each_child) {|n| p n }
# #=> 4
# # 2
# # 3
# # 1
#
def TSort.tsort_each(each_node, each_child) # :yields: node
return to_enum(__method__, each_node, each_child) unless block_given?
TSort.each_strongly_connected_component(each_node, each_child) {|component|
if component.size == 1
yield component.first
else
raise Cyclic.new("topological sort failed: #{component.inspect}")
end
}
end
# Returns strongly connected components as an array of arrays of nodes.
# The array is sorted from children to parents.
# Each elements of the array represents a strongly connected component.
#
# class G
# include TSort
# def initialize(g)
# @g = g
# end
# def tsort_each_child(n, &b) @g[n].each(&b) end
# def tsort_each_node(&b) @g.each_key(&b) end
# end
#
# graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
# p graph.strongly_connected_components #=> [[4], [2], [3], [1]]
#
# graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
# p graph.strongly_connected_components #=> [[4], [2, 3], [1]]
#
def strongly_connected_components
each_node = method(:tsort_each_node)
each_child = method(:tsort_each_child)
TSort.strongly_connected_components(each_node, each_child)
end
# Returns strongly connected components as an array of arrays of nodes.
# The array is sorted from children to parents.
# Each elements of the array represents a strongly connected component.
#
# The graph is represented by _each_node_ and _each_child_.
# _each_node_ should have +call+ method which yields for each node in the graph.
# _each_child_ should have +call+ method which takes a node argument and yields for each child node.
#
# g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
# each_node = lambda {|&b| g.each_key(&b) }
# each_child = lambda {|n, &b| g[n].each(&b) }
# p TSort.strongly_connected_components(each_node, each_child)
# #=> [[4], [2], [3], [1]]
#
# g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
# each_node = lambda {|&b| g.each_key(&b) }
# each_child = lambda {|n, &b| g[n].each(&b) }
# p TSort.strongly_connected_components(each_node, each_child)
# #=> [[4], [2, 3], [1]]
#
def TSort.strongly_connected_components(each_node, each_child)
TSort.each_strongly_connected_component(each_node, each_child).to_a
end
# The iterator version of the #strongly_connected_components method.
# <tt><em>obj</em>.each_strongly_connected_component</tt> is similar to
# <tt><em>obj</em>.strongly_connected_components.each</tt>, but
# modification of _obj_ during the iteration may lead to unexpected results.
#
# #each_strongly_connected_component returns +nil+.
#
# class G
# include TSort
# def initialize(g)
# @g = g
# end
# def tsort_each_child(n, &b) @g[n].each(&b) end
# def tsort_each_node(&b) @g.each_key(&b) end
# end
#
# graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
# graph.each_strongly_connected_component {|scc| p scc }
# #=> [4]
# # [2]
# # [3]
# # [1]
#
# graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
# graph.each_strongly_connected_component {|scc| p scc }
# #=> [4]
# # [2, 3]
# # [1]
#
def each_strongly_connected_component(&block) # :yields: nodes
each_node = method(:tsort_each_node)
each_child = method(:tsort_each_child)
TSort.each_strongly_connected_component(each_node, each_child, &block)
end
# The iterator version of the TSort.strongly_connected_components method.
#
# The graph is represented by _each_node_ and _each_child_.
# _each_node_ should have +call+ method which yields for each node in the graph.
# _each_child_ should have +call+ method which takes a node argument and yields for each child node.
#
# g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
# each_node = lambda {|&b| g.each_key(&b) }
# each_child = lambda {|n, &b| g[n].each(&b) }
# TSort.each_strongly_connected_component(each_node, each_child) {|scc| p scc }
# #=> [4]
# # [2]
# # [3]
# # [1]
#
# g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
# each_node = lambda {|&b| g.each_key(&b) }
# each_child = lambda {|n, &b| g[n].each(&b) }
# TSort.each_strongly_connected_component(each_node, each_child) {|scc| p scc }
# #=> [4]
# # [2, 3]
# # [1]
#
def TSort.each_strongly_connected_component(each_node, each_child) # :yields: nodes
return to_enum(__method__, each_node, each_child) unless block_given?
id_map = {}
stack = []
each_node.call {|node|
unless id_map.include? node
TSort.each_strongly_connected_component_from(node, each_child, id_map, stack) {|c|
yield c
}
end
}
nil
end
# Iterates over strongly connected component in the subgraph reachable from
# _node_.
#
# Return value is unspecified.
#
# #each_strongly_connected_component_from doesn't call #tsort_each_node.
#
# class G
# include TSort
# def initialize(g)
# @g = g
# end
# def tsort_each_child(n, &b) @g[n].each(&b) end
# def tsort_each_node(&b) @g.each_key(&b) end
# end
#
# graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
# graph.each_strongly_connected_component_from(2) {|scc| p scc }
# #=> [4]
# # [2]
#
# graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
# graph.each_strongly_connected_component_from(2) {|scc| p scc }
# #=> [4]
# # [2, 3]
#
def each_strongly_connected_component_from(node, id_map={}, stack=[], &block) # :yields: nodes
TSort.each_strongly_connected_component_from(node, method(:tsort_each_child), id_map, stack, &block)
end
# Iterates over strongly connected components in a graph.
# The graph is represented by _node_ and _each_child_.
#
# _node_ is the first node.
# _each_child_ should have +call+ method which takes a node argument
# and yields for each child node.
#
# Return value is unspecified.
#
# #TSort.each_strongly_connected_component_from is a class method and
# it doesn't need a class to represent a graph which includes TSort.
#
# graph = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
# each_child = lambda {|n, &b| graph[n].each(&b) }
# TSort.each_strongly_connected_component_from(1, each_child) {|scc|
# p scc
# }
# #=> [4]
# # [2, 3]
# # [1]
#
def TSort.each_strongly_connected_component_from(node, each_child, id_map={}, stack=[]) # :yields: nodes
return to_enum(__method__, node, each_child, id_map, stack) unless block_given?
minimum_id = node_id = id_map[node] = id_map.size
stack_length = stack.length
stack << node
each_child.call(node) {|child|
if id_map.include? child
child_id = id_map[child]
minimum_id = child_id if child_id && child_id < minimum_id
else
sub_minimum_id =
TSort.each_strongly_connected_component_from(child, each_child, id_map, stack) {|c|
yield c
}
minimum_id = sub_minimum_id if sub_minimum_id < minimum_id
end
}
if node_id == minimum_id
component = stack.slice!(stack_length .. -1)
component.each {|n| id_map[n] = nil}
yield component
end
minimum_id
end
# Should be implemented by a extended class.
#
# #tsort_each_node is used to iterate for all nodes over a graph.
#
def tsort_each_node # :yields: node
raise NotImplementedError.new
end
# Should be implemented by a extended class.
#
# #tsort_each_child is used to iterate for child nodes of _node_.
#
def tsort_each_child(node) # :yields: child
raise NotImplementedError.new
end
end
end

View file

@ -0,0 +1,4 @@
# frozen_string_literal: true
module Bundler; end
require_relative "vendor/tsort/lib/tsort"

View file

@ -1,7 +1,7 @@
# frozen_string_literal: false
module Bundler
VERSION = "2.2.30".freeze
VERSION = "2.2.31".freeze
def self.bundler_major_version
@bundler_major_version ||= VERSION.split(".").first.to_i

View file

@ -8,7 +8,7 @@
require 'rbconfig'
module Gem
VERSION = "3.2.30".freeze
VERSION = "3.2.31".freeze
end
# Must be first since it unloads the prelude from 1.9.2

View file

@ -5,7 +5,7 @@
# See LICENSE.txt for permissions.
#++
require 'optparse'
require_relative 'optparse'
require_relative 'requirement'
require_relative 'user_interaction'
@ -19,7 +19,7 @@ require_relative 'user_interaction'
class Gem::Command
include Gem::UserInteraction
OptionParser.accept Symbol do |value|
Gem::OptionParser.accept Symbol do |value|
value.to_sym
end
@ -344,7 +344,7 @@ class Gem::Command
##
# Add a command-line option and handler to the command.
#
# See OptionParser#make_switch for an explanation of +opts+.
# See Gem::OptionParser#make_switch for an explanation of +opts+.
#
# +handler+ will be called with two values, the value of the argument and
# the options hash.
@ -540,7 +540,7 @@ class Gem::Command
# command.
def create_option_parser
@parser = OptionParser.new
@parser = Gem::OptionParser.new
add_parser_options

View file

@ -51,7 +51,7 @@ class Gem::Commands::CertCommand < Gem::Command
add_option('-s', '--sign CERT',
'Signs CERT with the key from -K',
'and the certificate from -C') do |cert_file, options|
raise OptionParser::InvalidArgument, "#{cert_file}: does not exist" unless
raise Gem::OptionParser::InvalidArgument, "#{cert_file}: does not exist" unless
File.file? cert_file
options[:sign] << cert_file
@ -85,9 +85,9 @@ class Gem::Commands::CertCommand < Gem::Command
check_openssl
OpenSSL::X509::Certificate.new File.read certificate_file
rescue Errno::ENOENT
raise OptionParser::InvalidArgument, "#{certificate_file}: does not exist"
raise Gem::OptionParser::InvalidArgument, "#{certificate_file}: does not exist"
rescue OpenSSL::X509::CertificateError
raise OptionParser::InvalidArgument,
raise Gem::OptionParser::InvalidArgument,
"#{certificate_file}: invalid X509 certificate"
end
@ -95,13 +95,13 @@ class Gem::Commands::CertCommand < Gem::Command
check_openssl
passphrase = ENV['GEM_PRIVATE_KEY_PASSPHRASE']
key = OpenSSL::PKey.read File.read(key_file), passphrase
raise OptionParser::InvalidArgument,
raise Gem::OptionParser::InvalidArgument,
"#{key_file}: private key not found" unless key.private?
key
rescue Errno::ENOENT
raise OptionParser::InvalidArgument, "#{key_file}: does not exist"
raise Gem::OptionParser::InvalidArgument, "#{key_file}: does not exist"
rescue OpenSSL::PKey::PKeyError, ArgumentError
raise OptionParser::InvalidArgument, "#{key_file}: invalid RSA, DSA, or EC key"
raise Gem::OptionParser::InvalidArgument, "#{key_file}: invalid RSA, DSA, or EC key"
end
def execute

View file

@ -60,7 +60,7 @@ then repackaging it.
specs_and_sources = filtered unless filtered.empty?
end
spec, source = specs_and_sources.max_by {|s,| s.version }
spec, source = specs_and_sources.max_by {|s,| s }
if spec.nil?
show_lookup_failure gem_name, version, errors, options[:domain]

View file

@ -11,10 +11,10 @@ class Gem::Commands::ServerCommand < Gem::Command
super 'server', 'Documentation and gem repository HTTP server',
:port => 8808, :gemdir => [], :daemon => false
OptionParser.accept :Port do |port|
Gem::OptionParser.accept :Port do |port|
if port =~ /\A\d+\z/
port = Integer port
raise OptionParser::InvalidArgument, "#{port}: not a port number" if
raise Gem::OptionParser::InvalidArgument, "#{port}: not a port number" if
port > 65535
port
@ -22,7 +22,7 @@ class Gem::Commands::ServerCommand < Gem::Command
begin
Socket.getservbyname port
rescue SocketError
raise OptionParser::InvalidArgument, "#{port}: no such named service"
raise Gem::OptionParser::InvalidArgument, "#{port}: no such named service"
end
end
end

View file

@ -149,13 +149,6 @@ By default, this RubyGems will install gem as:
def execute
@verbose = Gem.configuration.really_verbose
install_destdir = options[:destdir]
unless install_destdir.empty?
ENV['GEM_HOME'] ||= File.join(install_destdir,
Gem.default_dir.gsub(/^[a-zA-Z]:/, ''))
end
check_ruby_version
require 'fileutils'
@ -166,8 +159,8 @@ By default, this RubyGems will install gem as:
end
extend MakeDirs
lib_dir, bin_dir = make_destination_dirs install_destdir
man_dir = generate_default_man_dir install_destdir
lib_dir, bin_dir = make_destination_dirs
man_dir = generate_default_man_dir
install_lib lib_dir
@ -258,35 +251,32 @@ By default, this RubyGems will install gem as:
say "Installing #{tool} executable" if @verbose
Dir.chdir path do
bin_files = Dir['*']
bin_file = "gem"
bin_files -= %w[update_rubygems]
dest_file = target_bin_path(bin_dir, bin_file)
bin_tmp_file = File.join Dir.tmpdir, "#{bin_file}.#{$$}"
bin_files.each do |bin_file|
dest_file = target_bin_path(bin_dir, bin_file)
bin_tmp_file = File.join Dir.tmpdir, "#{bin_file}.#{$$}"
begin
bin = File.readlines bin_file
bin[0] = shebang
begin
bin = File.readlines bin_file
bin[0] = shebang
File.open bin_tmp_file, 'w' do |fp|
fp.puts bin.join
end
install bin_tmp_file, dest_file, :mode => prog_mode
bin_file_names << dest_file
ensure
rm bin_tmp_file
File.open bin_tmp_file, 'w' do |fp|
fp.puts bin.join
end
next unless Gem.win_platform?
install bin_tmp_file, dest_file, :mode => prog_mode
bin_file_names << dest_file
ensure
rm bin_tmp_file
end
begin
bin_cmd_file = File.join Dir.tmpdir, "#{bin_file}.bat"
next unless Gem.win_platform?
File.open bin_cmd_file, 'w' do |file|
file.puts <<-TEXT
begin
bin_cmd_file = File.join Dir.tmpdir, "#{bin_file}.bat"
File.open bin_cmd_file, 'w' do |file|
file.puts <<-TEXT
@ECHO OFF
IF NOT "%~f0" == "~f0" GOTO :WinNT
@"#{File.basename(Gem.ruby).chomp('"')}" "#{dest_file}" %1 %2 %3 %4 %5 %6 %7 %8 %9
@ -294,12 +284,11 @@ By default, this RubyGems will install gem as:
:WinNT
@"#{File.basename(Gem.ruby).chomp('"')}" "%~dpn0" %*
TEXT
end
install bin_cmd_file, "#{dest_file}.bat", :mode => prog_mode
ensure
rm bin_cmd_file
end
install bin_cmd_file, "#{dest_file}.bat", :mode => prog_mode
ensure
rm bin_cmd_file
end
end
end
@ -371,8 +360,7 @@ By default, this RubyGems will install gem as:
end
def install_default_bundler_gem(bin_dir)
specs_dir = Gem.default_specifications_dir
specs_dir = File.join(options[:destdir], specs_dir) unless Gem.win_platform?
specs_dir = File.join(default_dir, "specifications", "default")
mkdir_p specs_dir, :mode => 0755
bundler_spec = Dir.chdir("bundler") { Gem::Specification.load("bundler.gemspec") }
@ -387,8 +375,20 @@ By default, this RubyGems will install gem as:
bundler_spec = Gem::Specification.load(default_spec_path)
# The base_dir value for a specification is inferred by walking up from the
# folder where the spec was `loaded_from`. In the case of default gems, we
# walk up two levels, because they live at `specifications/default/`, whereas
# in the case of regular gems we walk up just one level because they live at
# `specifications/`. However, in this case, the gem we are installing is
# misdetected as a regular gem, when it's a default gem in reality. This is
# because when there's a `:destdir`, the `loaded_from` path has changed and
# doesn't match `Gem.default_specifications_dir` which is the criteria to
# tag a gem as a default gem. So, in that case, write the correct
# `@base_dir` directly.
bundler_spec.instance_variable_set(:@base_dir, File.dirname(File.dirname(specs_dir)))
# Remove gemspec that was same version of vendored bundler.
normal_gemspec = File.join(Gem.default_dir, "specifications", "bundler-#{bundler_spec.version}.gemspec")
normal_gemspec = File.join(default_dir, "specifications", "bundler-#{bundler_spec.version}.gemspec")
if File.file? normal_gemspec
File.delete normal_gemspec
end
@ -401,7 +401,6 @@ By default, this RubyGems will install gem as:
end
bundler_bin_dir = bundler_spec.bin_dir
bundler_bin_dir = File.join(options[:destdir], bundler_bin_dir) unless Gem.win_platform?
mkdir_p bundler_bin_dir, :mode => 0755
bundler_spec.executables.each do |e|
cp File.join("bundler", bundler_spec.bindir, e), File.join(bundler_bin_dir, e)
@ -424,11 +423,11 @@ By default, this RubyGems will install gem as:
say "Bundler #{bundler_spec.version} installed"
end
def make_destination_dirs(install_destdir)
def make_destination_dirs
lib_dir, bin_dir = Gem.default_rubygems_dirs
unless lib_dir
lib_dir, bin_dir = generate_default_dirs(install_destdir)
lib_dir, bin_dir = generate_default_dirs
end
mkdir_p lib_dir, :mode => 0755
@ -437,7 +436,7 @@ By default, this RubyGems will install gem as:
return lib_dir, bin_dir
end
def generate_default_man_dir(install_destdir)
def generate_default_man_dir
prefix = options[:prefix]
if prefix.empty?
@ -447,14 +446,10 @@ By default, this RubyGems will install gem as:
man_dir = File.join prefix, 'man'
end
unless install_destdir.empty?
man_dir = File.join install_destdir, man_dir.gsub(/^[a-zA-Z]:/, '')
end
man_dir
prepend_destdir_if_present(man_dir)
end
def generate_default_dirs(install_destdir)
def generate_default_dirs
prefix = options[:prefix]
site_or_vendor = options[:site_or_vendor]
@ -478,12 +473,7 @@ By default, this RubyGems will install gem as:
end
end
unless install_destdir.empty?
lib_dir = File.join install_destdir, lib_dir.gsub(/^[a-zA-Z]:/, '')
bin_dir = File.join install_destdir, bin_dir.gsub(/^[a-zA-Z]:/, '')
end
[lib_dir, bin_dir]
[prepend_destdir_if_present(lib_dir), prepend_destdir_if_present(bin_dir)]
end
def files_in(dir)
@ -629,6 +619,25 @@ abort "#{deprecation_message}"
private
def default_dir
prefix = options[:prefix]
if prefix.empty?
dir = Gem.default_dir
else
dir = prefix
end
prepend_destdir_if_present(dir)
end
def prepend_destdir_if_present(path)
destdir = options[:destdir]
return path if destdir.empty?
File.join(options[:destdir], path.gsub(/^[a-zA-Z]:/, ''))
end
def install_file_list(files, dest_dir)
files.each do |file|
install_file file, dest_dir

View file

@ -81,7 +81,7 @@ class Gem::Commands::UninstallCommand < Gem::Command
'Uninstall gem from the vendor directory.',
'Only for use by gem repackagers.') do |value, options|
unless Gem.vendor_dir
raise OptionParser::InvalidOption.new 'your platform is not supported'
raise Gem::OptionParser::InvalidOption.new 'your platform is not supported'
end
alert_warning 'Use your OS package manager to uninstall vendor gems'

View file

@ -25,7 +25,7 @@ class Gem::Commands::UpdateCommand < Gem::Command
add_install_update_options
OptionParser.accept Gem::Version do |value|
Gem::OptionParser.accept Gem::Version do |value|
Gem::Version.new value
value

View file

@ -5,7 +5,7 @@
# See LICENSE.txt for permissions.
#++
require 'tsort'
require_relative 'tsort'
require_relative 'deprecate'
##
@ -20,7 +20,7 @@ class Gem::DependencyList
attr_reader :specs
include Enumerable
include TSort
include Gem::TSort
##
# Allows enabling/disabling use of development dependencies

View file

@ -24,13 +24,14 @@ class Gem::Ext::Builder
# try to find make program from Ruby configure arguments first
RbConfig::CONFIG['configure_args'] =~ /with-make-prog\=(\w+)/
make_program = ENV['MAKE'] || ENV['make'] || $1
unless make_program
make_program = (/mswin/ =~ RUBY_PLATFORM) ? 'nmake' : 'make'
make_program_name = ENV['MAKE'] || ENV['make'] || $1
unless make_program_name
make_program_name = (/mswin/ =~ RUBY_PLATFORM) ? 'nmake' : 'make'
end
make_program = Shellwords.split(make_program)
make_program = Shellwords.split(make_program_name)
destdir = 'DESTDIR=%s' % ENV['DESTDIR']
# The installation of the bundled gems is failed when DESTDIR is empty in mswin platform.
destdir = (/\bnmake/i !~ make_program_name || ENV['DESTDIR'] && ENV['DESTDIR'] != "") ? 'DESTDIR=%s' % ENV['DESTDIR'] : ''
['clean', '', 'install'].each do |target|
# Pass DESTDIR via command line to override what's in MAKEFLAGS

View file

@ -1,9 +1,9 @@
# frozen_string_literal: true
require_relative '../command'
class Gem::Ext::CmakeBuilder < Gem::Ext::Builder
def self.build(extension, dest_path, results, args=[], lib_dir=nil, cmake_dir=Dir.pwd)
unless File.exist?(File.join(cmake_dir, 'Makefile'))
require_relative '../command'
cmd = ["cmake", ".", "-DCMAKE_INSTALL_PREFIX=#{dest_path}", *Gem::Command.build_args]
run cmd, results, class_name, cmake_dir

View file

@ -51,7 +51,7 @@ module Gem::InstallUpdateOptions
'Install gem into the vendor directory.',
'Only for use by gem repackagers.') do |value, options|
unless Gem.vendor_dir
raise OptionParser::InvalidOption.new 'your platform is not supported'
raise Gem::OptionParser::InvalidOption.new 'your platform is not supported'
end
options[:vendor] = true
@ -143,7 +143,7 @@ module Gem::InstallUpdateOptions
unless v
message = v ? v : "(tried #{Gem::GEM_DEP_FILES.join ', '})"
raise OptionParser::InvalidArgument,
raise Gem::OptionParser::InvalidArgument,
"cannot find gem dependencies file #{message}"
end

View file

@ -5,7 +5,6 @@
# See LICENSE.txt for permissions.
#++
require_relative 'command'
require_relative 'installer_uninstaller_utils'
require_relative 'exceptions'
require_relative 'deprecate'
@ -71,6 +70,23 @@ class Gem::Installer
@install_lock = Thread::Mutex.new
class << self
#
# Changes in rubygems to lazily loading `rubygems/command` (in order to
# lazily load `optparse` as a side effect) affect bundler's custom installer
# which uses `Gem::Command` without requiring it (up until bundler 2.2.29).
# This hook is to compensate for that missing require.
#
# TODO: Remove when rubygems no longer supports running on bundler older
# than 2.2.29.
def inherited(klass)
if klass.name == "Bundler::RubyGemsGemInstaller"
require "rubygems/command"
end
super(klass)
end
##
# True if we've warned about PATH not including Gem.bindir
@ -676,7 +692,7 @@ class Gem::Installer
@development = options[:development]
@build_root = options[:build_root]
@build_args = options[:build_args] || Gem::Command.build_args
@build_args = options[:build_args]
unless @build_root.nil?
@bin_dir = File.join(@build_root, @bin_dir.gsub(/^[a-zA-Z]:/, ''))
@ -832,7 +848,7 @@ TEXT
# configure scripts and rakefiles or mkrf_conf files.
def build_extensions
builder = Gem::Ext::Builder.new spec, @build_args
builder = Gem::Ext::Builder.new spec, build_args
builder.build_extensions
end
@ -919,7 +935,7 @@ TEXT
# extensions.
def write_build_info_file
return if @build_args.empty?
return if build_args.empty?
build_info_dir = File.join gem_home, 'build_info'
@ -929,7 +945,7 @@ TEXT
build_info_file = File.join build_info_dir, "#{spec.full_name}.info"
File.open build_info_file, 'w' do |io|
@build_args.each do |arg|
build_args.each do |arg|
io.puts arg
end
end
@ -954,4 +970,13 @@ TEXT
raise Gem::FilePermissionError.new(dir) unless File.writable? dir
end
private
def build_args
@build_args ||= begin
require_relative "command"
Gem::Command.build_args
end
end
end

View file

@ -14,14 +14,14 @@ require_relative '../rubygems'
module Gem::LocalRemoteOptions
##
# Allows OptionParser to handle HTTP URIs.
# Allows Gem::OptionParser to handle HTTP URIs.
def accept_uri_http
OptionParser.accept URI::HTTP do |value|
Gem::OptionParser.accept URI::HTTP do |value|
begin
uri = URI.parse value
rescue URI::InvalidURIError
raise OptionParser::InvalidArgument, value
raise Gem::OptionParser::InvalidArgument, value
end
valid_uri_schemes = ["http", "https", "file", "s3"]

3
lib/rubygems/optparse.rb Normal file
View file

@ -0,0 +1,3 @@
# frozen_string_literal: true
require_relative 'optparse/lib/optparse'

View file

@ -0,0 +1,2 @@
# frozen_string_literal: false
require_relative 'optparse'

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,54 @@
# frozen_string_literal: false
require 'rubygems/optparse/lib/optparse'
class Gem::OptionParser::AC < Gem::OptionParser
private
def _check_ac_args(name, block)
unless /\A\w[-\w]*\z/ =~ name
raise ArgumentError, name
end
unless block
raise ArgumentError, "no block given", ParseError.filter_backtrace(caller)
end
end
ARG_CONV = proc {|val| val.nil? ? true : val}
def _ac_arg_enable(prefix, name, help_string, block)
_check_ac_args(name, block)
sdesc = []
ldesc = ["--#{prefix}-#{name}"]
desc = [help_string]
q = name.downcase
ac_block = proc {|val| block.call(ARG_CONV.call(val))}
enable = Switch::PlacedArgument.new(nil, ARG_CONV, sdesc, ldesc, nil, desc, ac_block)
disable = Switch::NoArgument.new(nil, proc {false}, sdesc, ldesc, nil, desc, ac_block)
top.append(enable, [], ["enable-" + q], disable, ['disable-' + q])
enable
end
public
def ac_arg_enable(name, help_string, &block)
_ac_arg_enable("enable", name, help_string, block)
end
def ac_arg_disable(name, help_string, &block)
_ac_arg_enable("disable", name, help_string, block)
end
def ac_arg_with(name, help_string, &block)
_check_ac_args(name, block)
sdesc = []
ldesc = ["--with-#{name}"]
desc = [help_string]
q = name.downcase
with = Switch::PlacedArgument.new(*search(:atype, String), sdesc, ldesc, nil, desc, block)
without = Switch::NoArgument.new(nil, proc {}, sdesc, ldesc, nil, desc, block)
top.append(with, [], ["with-" + q], without, ['without-' + q])
with
end
end

View file

@ -0,0 +1,18 @@
# frozen_string_literal: false
require 'rubygems/optparse/lib/optparse'
require 'date'
Gem::OptionParser.accept(DateTime) do |s,|
begin
DateTime.parse(s) if s
rescue ArgumentError
raise Gem::OptionParser::InvalidArgument, s
end
end
Gem::OptionParser.accept(Date) do |s,|
begin
Date.parse(s) if s
rescue ArgumentError
raise Gem::OptionParser::InvalidArgument, s
end
end

View file

@ -0,0 +1,22 @@
# frozen_string_literal: true
require 'rubygems/optparse/lib/optparse'
class Gem::OptionParser
# :call-seq:
# define_by_keywords(options, method, **params)
#
# :include: ../../doc/optparse/creates_option.rdoc
#
def define_by_keywords(options, meth, **opts)
meth.parameters.each do |type, name|
case type
when :key, :keyreq
op, cl = *(type == :key ? %w"[ ]" : ["", ""])
define("--#{name}=#{op}#{name.upcase}#{cl}", *opts[name]) do |o|
options[name] = o
end
end
end
options
end
end

View file

@ -0,0 +1,7 @@
# frozen_string_literal: false
# -*- ruby -*-
require 'shellwords'
require 'rubygems/optparse/lib/optparse'
Gem::OptionParser.accept(Shellwords) {|s,| Shellwords.shellwords(s)}

View file

@ -0,0 +1,11 @@
# frozen_string_literal: false
require 'rubygems/optparse/lib/optparse'
require 'time'
Gem::OptionParser.accept(Time) do |s,|
begin
(Time.httpdate(s) rescue Time.parse(s)) if s
rescue
raise Gem::OptionParser::InvalidArgument, s
end
end

View file

@ -0,0 +1,7 @@
# frozen_string_literal: false
# -*- ruby -*-
require 'rubygems/optparse/lib/optparse'
require 'uri'
Gem::OptionParser.accept(URI) {|s,| URI.parse(s) if s}

View file

@ -0,0 +1,71 @@
# frozen_string_literal: false
# Gem::OptionParser internal utility
class << Gem::OptionParser
def show_version(*pkgs)
progname = ARGV.options.program_name
result = false
show = proc do |klass, cname, version|
str = "#{progname}"
unless klass == ::Object and cname == :VERSION
version = version.join(".") if Array === version
str << ": #{klass}" unless klass == Object
str << " version #{version}"
end
[:Release, :RELEASE].find do |rel|
if klass.const_defined?(rel)
str << " (#{klass.const_get(rel)})"
end
end
puts str
result = true
end
if pkgs.size == 1 and pkgs[0] == "all"
self.search_const(::Object, /\AV(?:ERSION|ersion)\z/) do |klass, cname, version|
unless cname[1] == ?e and klass.const_defined?(:Version)
show.call(klass, cname.intern, version)
end
end
else
pkgs.each do |pkg|
begin
pkg = pkg.split(/::|\//).inject(::Object) {|m, c| m.const_get(c)}
v = case
when pkg.const_defined?(:Version)
pkg.const_get(n = :Version)
when pkg.const_defined?(:VERSION)
pkg.const_get(n = :VERSION)
else
n = nil
"unknown"
end
show.call(pkg, n, v)
rescue NameError
end
end
end
result
end
def each_const(path, base = ::Object)
path.split(/::|\//).inject(base) do |klass, name|
raise NameError, path unless Module === klass
klass.constants.grep(/#{name}/i) do |c|
klass.const_defined?(c) or next
klass.const_get(c)
end
end
end
def search_const(klass, name)
klasses = [klass]
while klass = klasses.shift
klass.constants.each do |cname|
klass.const_defined?(cname) or next
const = klass.const_get(cname)
yield klass, cname, const if name === cname
klasses << const if Module === const and const != ::Object
end
end
end
end

View file

@ -1,5 +1,5 @@
# frozen_string_literal: true
require 'tsort'
require_relative 'tsort'
##
# A RequestSet groups a request to activate a set of dependencies.
@ -15,7 +15,7 @@ require 'tsort'
# #=> ["nokogiri-1.6.0", "mini_portile-0.5.1", "pg-0.17.0"]
class Gem::RequestSet
include TSort
include Gem::TSort
##
# Array of gems to install even if already installed

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'tsort'
require_relative '../../../../tsort'
require_relative 'dependency_graph/log'
require_relative 'dependency_graph/vertex'
@ -17,7 +17,7 @@ module Gem::Resolver::Molinillo
vertices.values.each { |v| yield v }
end
include TSort
include Gem::TSort
# @!visibility private
alias tsort_each_node each

View file

@ -19,16 +19,16 @@ end
module Gem::SecurityOption
def add_security_option
OptionParser.accept Gem::Security::Policy do |value|
Gem::OptionParser.accept Gem::Security::Policy do |value|
require_relative 'security'
raise OptionParser::InvalidArgument, 'OpenSSL not installed' unless
raise Gem::OptionParser::InvalidArgument, 'OpenSSL not installed' unless
defined?(Gem::Security::HighSecurity)
policy = Gem::Security::Policies[value]
unless policy
valid = Gem::Security::Policies.keys.sort
raise OptionParser::InvalidArgument, "#{value} (#{valid.join ', '} are valid)"
raise Gem::OptionParser::InvalidArgument, "#{value} (#{valid.join ', '} are valid)"
end
policy
end

View file

@ -324,17 +324,21 @@ class Gem::Specification < Gem::BasicSpecification
# This should just be the name of your license. The full text of the license
# should be inside of the gem (at the top level) when you build it.
#
# The simplest way, is to specify the standard SPDX ID
# The simplest way is to specify the standard SPDX ID
# https://spdx.org/licenses/ for the license.
# Ideally you should pick one that is OSI (Open Source Initiative)
# Ideally, you should pick one that is OSI (Open Source Initiative)
# http://opensource.org/licenses/alphabetical approved.
#
# The most commonly used OSI approved licenses are MIT and Apache-2.0.
# The most commonly used OSI-approved licenses are MIT and Apache-2.0.
# GitHub also provides a license picker at http://choosealicense.com/.
#
# You can also use a custom license file along with your gemspec and specify
# a LicenseRef-<idstring>, where idstring is the name of the file containing
# the license text.
#
# You should specify a license for your gem so that people know how they are
# permitted to use it, and any restrictions you're placing on it. Not
# specifying a license means all rights are reserved; others have no rights
# permitted to use it and any restrictions you're placing on it. Not
# specifying a license means all rights are reserved; others have no right
# to use the code for any purpose.
#
# You can set multiple licenses with #licenses=

3
lib/rubygems/tsort.rb Normal file
View file

@ -0,0 +1,3 @@
# frozen_string_literal: true
require_relative 'tsort/lib/tsort'

View file

@ -0,0 +1,454 @@
# frozen_string_literal: true
#--
# tsort.rb - provides a module for topological sorting and strongly connected components.
#++
#
#
# Gem::TSort implements topological sorting using Tarjan's algorithm for
# strongly connected components.
#
# Gem::TSort is designed to be able to be used with any object which can be
# interpreted as a directed graph.
#
# Gem::TSort requires two methods to interpret an object as a graph,
# tsort_each_node and tsort_each_child.
#
# * tsort_each_node is used to iterate for all nodes over a graph.
# * tsort_each_child is used to iterate for child nodes of a given node.
#
# The equality of nodes are defined by eql? and hash since
# Gem::TSort uses Hash internally.
#
# == A Simple Example
#
# The following example demonstrates how to mix the Gem::TSort module into an
# existing class (in this case, Hash). Here, we're treating each key in
# the hash as a node in the graph, and so we simply alias the required
# #tsort_each_node method to Hash's #each_key method. For each key in the
# hash, the associated value is an array of the node's child nodes. This
# choice in turn leads to our implementation of the required #tsort_each_child
# method, which fetches the array of child nodes and then iterates over that
# array using the user-supplied block.
#
# require 'rubygems/tsort/lib/tsort'
#
# class Hash
# include Gem::TSort
# alias tsort_each_node each_key
# def tsort_each_child(node, &block)
# fetch(node).each(&block)
# end
# end
#
# {1=>[2, 3], 2=>[3], 3=>[], 4=>[]}.tsort
# #=> [3, 2, 1, 4]
#
# {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}.strongly_connected_components
# #=> [[4], [2, 3], [1]]
#
# == A More Realistic Example
#
# A very simple `make' like tool can be implemented as follows:
#
# require 'rubygems/tsort/lib/tsort'
#
# class Make
# def initialize
# @dep = {}
# @dep.default = []
# end
#
# def rule(outputs, inputs=[], &block)
# triple = [outputs, inputs, block]
# outputs.each {|f| @dep[f] = [triple]}
# @dep[triple] = inputs
# end
#
# def build(target)
# each_strongly_connected_component_from(target) {|ns|
# if ns.length != 1
# fs = ns.delete_if {|n| Array === n}
# raise Gem::TSort::Cyclic.new("cyclic dependencies: #{fs.join ', '}")
# end
# n = ns.first
# if Array === n
# outputs, inputs, block = n
# inputs_time = inputs.map {|f| File.mtime f}.max
# begin
# outputs_time = outputs.map {|f| File.mtime f}.min
# rescue Errno::ENOENT
# outputs_time = nil
# end
# if outputs_time == nil ||
# inputs_time != nil && outputs_time <= inputs_time
# sleep 1 if inputs_time != nil && inputs_time.to_i == Time.now.to_i
# block.call
# end
# end
# }
# end
#
# def tsort_each_child(node, &block)
# @dep[node].each(&block)
# end
# include Gem::TSort
# end
#
# def command(arg)
# print arg, "\n"
# system arg
# end
#
# m = Make.new
# m.rule(%w[t1]) { command 'date > t1' }
# m.rule(%w[t2]) { command 'date > t2' }
# m.rule(%w[t3]) { command 'date > t3' }
# m.rule(%w[t4], %w[t1 t3]) { command 'cat t1 t3 > t4' }
# m.rule(%w[t5], %w[t4 t2]) { command 'cat t4 t2 > t5' }
# m.build('t5')
#
# == Bugs
#
# * 'tsort.rb' is wrong name because this library uses
# Tarjan's algorithm for strongly connected components.
# Although 'strongly_connected_components.rb' is correct but too long.
#
# == References
#
# R. E. Tarjan, "Depth First Search and Linear Graph Algorithms",
# <em>SIAM Journal on Computing</em>, Vol. 1, No. 2, pp. 146-160, June 1972.
#
module Gem
module TSort
class Cyclic < StandardError
end
# Returns a topologically sorted array of nodes.
# The array is sorted from children to parents, i.e.
# the first element has no child and the last node has no parent.
#
# If there is a cycle, Gem::TSort::Cyclic is raised.
#
# class G
# include Gem::TSort
# def initialize(g)
# @g = g
# end
# def tsort_each_child(n, &b) @g[n].each(&b) end
# def tsort_each_node(&b) @g.each_key(&b) end
# end
#
# graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
# p graph.tsort #=> [4, 2, 3, 1]
#
# graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
# p graph.tsort # raises Gem::TSort::Cyclic
#
def tsort
each_node = method(:tsort_each_node)
each_child = method(:tsort_each_child)
Gem::TSort.tsort(each_node, each_child)
end
# Returns a topologically sorted array of nodes.
# The array is sorted from children to parents, i.e.
# the first element has no child and the last node has no parent.
#
# The graph is represented by _each_node_ and _each_child_.
# _each_node_ should have +call+ method which yields for each node in the graph.
# _each_child_ should have +call+ method which takes a node argument and yields for each child node.
#
# If there is a cycle, Gem::TSort::Cyclic is raised.
#
# g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
# each_node = lambda {|&b| g.each_key(&b) }
# each_child = lambda {|n, &b| g[n].each(&b) }
# p Gem::TSort.tsort(each_node, each_child) #=> [4, 2, 3, 1]
#
# g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
# each_node = lambda {|&b| g.each_key(&b) }
# each_child = lambda {|n, &b| g[n].each(&b) }
# p Gem::TSort.tsort(each_node, each_child) # raises Gem::TSort::Cyclic
#
def TSort.tsort(each_node, each_child)
Gem::TSort.tsort_each(each_node, each_child).to_a
end
# The iterator version of the #tsort method.
# <tt><em>obj</em>.tsort_each</tt> is similar to <tt><em>obj</em>.tsort.each</tt>, but
# modification of _obj_ during the iteration may lead to unexpected results.
#
# #tsort_each returns +nil+.
# If there is a cycle, Gem::TSort::Cyclic is raised.
#
# class G
# include Gem::TSort
# def initialize(g)
# @g = g
# end
# def tsort_each_child(n, &b) @g[n].each(&b) end
# def tsort_each_node(&b) @g.each_key(&b) end
# end
#
# graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
# graph.tsort_each {|n| p n }
# #=> 4
# # 2
# # 3
# # 1
#
def tsort_each(&block) # :yields: node
each_node = method(:tsort_each_node)
each_child = method(:tsort_each_child)
Gem::TSort.tsort_each(each_node, each_child, &block)
end
# The iterator version of the Gem::TSort.tsort method.
#
# The graph is represented by _each_node_ and _each_child_.
# _each_node_ should have +call+ method which yields for each node in the graph.
# _each_child_ should have +call+ method which takes a node argument and yields for each child node.
#
# g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
# each_node = lambda {|&b| g.each_key(&b) }
# each_child = lambda {|n, &b| g[n].each(&b) }
# Gem::TSort.tsort_each(each_node, each_child) {|n| p n }
# #=> 4
# # 2
# # 3
# # 1
#
def TSort.tsort_each(each_node, each_child) # :yields: node
return to_enum(__method__, each_node, each_child) unless block_given?
Gem::TSort.each_strongly_connected_component(each_node, each_child) {|component|
if component.size == 1
yield component.first
else
raise Cyclic.new("topological sort failed: #{component.inspect}")
end
}
end
# Returns strongly connected components as an array of arrays of nodes.
# The array is sorted from children to parents.
# Each elements of the array represents a strongly connected component.
#
# class G
# include Gem::TSort
# def initialize(g)
# @g = g
# end
# def tsort_each_child(n, &b) @g[n].each(&b) end
# def tsort_each_node(&b) @g.each_key(&b) end
# end
#
# graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
# p graph.strongly_connected_components #=> [[4], [2], [3], [1]]
#
# graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
# p graph.strongly_connected_components #=> [[4], [2, 3], [1]]
#
def strongly_connected_components
each_node = method(:tsort_each_node)
each_child = method(:tsort_each_child)
Gem::TSort.strongly_connected_components(each_node, each_child)
end
# Returns strongly connected components as an array of arrays of nodes.
# The array is sorted from children to parents.
# Each elements of the array represents a strongly connected component.
#
# The graph is represented by _each_node_ and _each_child_.
# _each_node_ should have +call+ method which yields for each node in the graph.
# _each_child_ should have +call+ method which takes a node argument and yields for each child node.
#
# g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
# each_node = lambda {|&b| g.each_key(&b) }
# each_child = lambda {|n, &b| g[n].each(&b) }
# p Gem::TSort.strongly_connected_components(each_node, each_child)
# #=> [[4], [2], [3], [1]]
#
# g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
# each_node = lambda {|&b| g.each_key(&b) }
# each_child = lambda {|n, &b| g[n].each(&b) }
# p Gem::TSort.strongly_connected_components(each_node, each_child)
# #=> [[4], [2, 3], [1]]
#
def TSort.strongly_connected_components(each_node, each_child)
Gem::TSort.each_strongly_connected_component(each_node, each_child).to_a
end
# The iterator version of the #strongly_connected_components method.
# <tt><em>obj</em>.each_strongly_connected_component</tt> is similar to
# <tt><em>obj</em>.strongly_connected_components.each</tt>, but
# modification of _obj_ during the iteration may lead to unexpected results.
#
# #each_strongly_connected_component returns +nil+.
#
# class G
# include Gem::TSort
# def initialize(g)
# @g = g
# end
# def tsort_each_child(n, &b) @g[n].each(&b) end
# def tsort_each_node(&b) @g.each_key(&b) end
# end
#
# graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
# graph.each_strongly_connected_component {|scc| p scc }
# #=> [4]
# # [2]
# # [3]
# # [1]
#
# graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
# graph.each_strongly_connected_component {|scc| p scc }
# #=> [4]
# # [2, 3]
# # [1]
#
def each_strongly_connected_component(&block) # :yields: nodes
each_node = method(:tsort_each_node)
each_child = method(:tsort_each_child)
Gem::TSort.each_strongly_connected_component(each_node, each_child, &block)
end
# The iterator version of the Gem::TSort.strongly_connected_components method.
#
# The graph is represented by _each_node_ and _each_child_.
# _each_node_ should have +call+ method which yields for each node in the graph.
# _each_child_ should have +call+ method which takes a node argument and yields for each child node.
#
# g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
# each_node = lambda {|&b| g.each_key(&b) }
# each_child = lambda {|n, &b| g[n].each(&b) }
# Gem::TSort.each_strongly_connected_component(each_node, each_child) {|scc| p scc }
# #=> [4]
# # [2]
# # [3]
# # [1]
#
# g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
# each_node = lambda {|&b| g.each_key(&b) }
# each_child = lambda {|n, &b| g[n].each(&b) }
# Gem::TSort.each_strongly_connected_component(each_node, each_child) {|scc| p scc }
# #=> [4]
# # [2, 3]
# # [1]
#
def TSort.each_strongly_connected_component(each_node, each_child) # :yields: nodes
return to_enum(__method__, each_node, each_child) unless block_given?
id_map = {}
stack = []
each_node.call {|node|
unless id_map.include? node
Gem::TSort.each_strongly_connected_component_from(node, each_child, id_map, stack) {|c|
yield c
}
end
}
nil
end
# Iterates over strongly connected component in the subgraph reachable from
# _node_.
#
# Return value is unspecified.
#
# #each_strongly_connected_component_from doesn't call #tsort_each_node.
#
# class G
# include Gem::TSort
# def initialize(g)
# @g = g
# end
# def tsort_each_child(n, &b) @g[n].each(&b) end
# def tsort_each_node(&b) @g.each_key(&b) end
# end
#
# graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
# graph.each_strongly_connected_component_from(2) {|scc| p scc }
# #=> [4]
# # [2]
#
# graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
# graph.each_strongly_connected_component_from(2) {|scc| p scc }
# #=> [4]
# # [2, 3]
#
def each_strongly_connected_component_from(node, id_map={}, stack=[], &block) # :yields: nodes
Gem::TSort.each_strongly_connected_component_from(node, method(:tsort_each_child), id_map, stack, &block)
end
# Iterates over strongly connected components in a graph.
# The graph is represented by _node_ and _each_child_.
#
# _node_ is the first node.
# _each_child_ should have +call+ method which takes a node argument
# and yields for each child node.
#
# Return value is unspecified.
#
# #Gem::TSort.each_strongly_connected_component_from is a class method and
# it doesn't need a class to represent a graph which includes Gem::TSort.
#
# graph = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
# each_child = lambda {|n, &b| graph[n].each(&b) }
# Gem::TSort.each_strongly_connected_component_from(1, each_child) {|scc|
# p scc
# }
# #=> [4]
# # [2, 3]
# # [1]
#
def TSort.each_strongly_connected_component_from(node, each_child, id_map={}, stack=[]) # :yields: nodes
return to_enum(__method__, node, each_child, id_map, stack) unless block_given?
minimum_id = node_id = id_map[node] = id_map.size
stack_length = stack.length
stack << node
each_child.call(node) {|child|
if id_map.include? child
child_id = id_map[child]
minimum_id = child_id if child_id && child_id < minimum_id
else
sub_minimum_id =
Gem::TSort.each_strongly_connected_component_from(child, each_child, id_map, stack) {|c|
yield c
}
minimum_id = sub_minimum_id if sub_minimum_id < minimum_id
end
}
if node_id == minimum_id
component = stack.slice!(stack_length .. -1)
component.each {|n| id_map[n] = nil}
yield component
end
minimum_id
end
# Should be implemented by a extended class.
#
# #tsort_each_node is used to iterate for all nodes over a graph.
#
def tsort_each_node # :yields: node
raise NotImplementedError.new
end
# Should be implemented by a extended class.
#
# #tsort_each_child is used to iterate for child nodes of _node_.
#
def tsort_each_child(node) # :yields: child
raise NotImplementedError.new
end
end
end

View file

@ -5,6 +5,7 @@ class Gem::Licenses
extend Gem::Text
NONSTANDARD = 'Nonstandard'.freeze
LICENSE_REF = 'LicenseRef-.+'.freeze
# Software Package Data Exchange (SPDX) standard open-source software
# license identifiers
@ -523,6 +524,7 @@ class Gem::Licenses
\+?
(?:\s WITH \s #{Regexp.union(EXCEPTION_IDENTIFIERS)})?
| #{NONSTANDARD}
| #{LICENSE_REF}
)
\Z
}ox.freeze

View file

@ -16,7 +16,7 @@ module Gem::VersionOption
# Add the --platform option to the option parser.
def add_platform_option(task = command, *wrap)
OptionParser.accept Gem::Platform do |value|
Gem::OptionParser.accept Gem::Platform do |value|
if value == Gem::Platform::RUBY
value
else
@ -51,7 +51,7 @@ module Gem::VersionOption
# Add the --version option to the option parser.
def add_version_option(task = command, *wrap)
OptionParser.accept Gem::Requirement do |value|
Gem::OptionParser.accept Gem::Requirement do |value|
Gem::Requirement.new(*value.split(/\s*,\s*/))
end

View file

@ -193,7 +193,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
let(:message) { "undefined method 'undefined_method_call'" }
it "should raise the original NoMethodError" do
expect { subject.request(uri, options) }.to raise_error(NoMethodError, "undefined method 'undefined_method_call'")
expect { subject.request(uri, options) }.to raise_error(NoMethodError, /undefined method 'undefined_method_call'/)
end
end
end

View file

@ -9,7 +9,7 @@ RSpec.describe Bundler::GemHelper do
let(:app_gemspec_path) { app_path.join("#{app_name}.gemspec") }
before(:each) do
global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__RUBOCOP" => "false",
global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__LINTER" => "false",
"BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__CHANGELOG" => "false"
bundle "gem #{app_name}"
prepare_gemspec(app_gemspec_path)

View file

@ -612,6 +612,36 @@ RSpec.describe "bundle exec" do
expect(out).to include("Installing foo 1.0")
end
it "loads the correct optparse when `auto_install` is set, and optparse is a dependency" do
if Gem.ruby_version >= Gem::Version.new("3.0.0") && Gem.rubygems_version < Gem::Version.new("3.3.0.a")
skip "optparse is a default gem, and rubygems loads install during install"
end
build_repo4 do
build_gem "fastlane", "2.192.0" do |s|
s.executables = "fastlane"
s.add_dependency "optparse", "~> 0.1.1"
end
build_gem "optparse", "0.1.0"
build_gem "optparse", "0.1.1"
end
system_gems "optparse-0.1.0", :gem_repo => gem_repo4
bundle "config set auto_install 1"
bundle "config set --local path vendor/bundle"
gemfile <<~G
source "#{file_uri_for(gem_repo4)}"
gem "fastlane"
G
bundle "exec fastlane"
expect(out).to include("Installing optparse 0.1.1")
expect(out).to include("2.192.0")
end
describe "with gems bundled via :path with invalid gemspecs" do
it "outputs the gemspec validation errors" do
build_lib "foo"

View file

@ -16,6 +16,12 @@ RSpec.describe "bundle gem" do
bundle "exec rubocop --debug --config .rubocop.yml", :dir => bundled_app(gem_name)
end
def bundle_exec_standardrb
prepare_gemspec(bundled_app(gem_name, "#{gem_name}.gemspec"))
bundle "config set path #{standard_gems}", :dir => bundled_app(gem_name)
bundle "exec standardrb --debug", :dir => bundled_app(gem_name)
end
let(:generated_gemspec) { Bundler.load_gemspec_uncached(bundled_app(gem_name).join("#{gem_name}.gemspec")) }
let(:gem_name) { "mygem" }
@ -138,8 +144,68 @@ RSpec.describe "bundle gem" do
end
shared_examples_for "--rubocop flag" do
context "is deprecated", :bundler => "< 3" do
before do
bundle "gem #{gem_name} --rubocop"
end
it "generates a gem skeleton with rubocop" do
gem_skeleton_assertions
expect(bundled_app("test-gem/Rakefile")).to read_as(
include("# frozen_string_literal: true").
and(include('require "rubocop/rake_task"').
and(include("RuboCop::RakeTask.new").
and(match(/default:.+:rubocop/))))
)
end
it "includes rubocop in generated Gemfile" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
builder = Bundler::Dsl.new
builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
builder.dependencies
rubocop_dep = builder.dependencies.find {|d| d.name == "rubocop" }
expect(rubocop_dep).not_to be_nil
end
it "generates a default .rubocop.yml" do
expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist
end
end
end
shared_examples_for "--no-rubocop flag" do
context "is deprecated", :bundler => "< 3" do
define_negated_matcher :exclude, :include
before do
bundle "gem #{gem_name} --no-rubocop"
end
it "generates a gem skeleton without rubocop" do
gem_skeleton_assertions
expect(bundled_app("test-gem/Rakefile")).to read_as(exclude("rubocop"))
expect(bundled_app("test-gem/#{gem_name}.gemspec")).to read_as(exclude("rubocop"))
end
it "does not include rubocop in generated Gemfile" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
builder = Bundler::Dsl.new
builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
builder.dependencies
rubocop_dep = builder.dependencies.find {|d| d.name == "rubocop" }
expect(rubocop_dep).to be_nil
end
it "doesn't generate a default .rubocop.yml" do
expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist
end
end
end
shared_examples_for "--linter=rubocop flag" do
before do
bundle "gem #{gem_name} --rubocop"
bundle "gem #{gem_name} --linter=rubocop"
end
it "generates a gem skeleton with rubocop" do
@ -166,11 +232,38 @@ RSpec.describe "bundle gem" do
end
end
shared_examples_for "--no-rubocop flag" do
shared_examples_for "--linter=standard flag" do
before do
bundle "gem #{gem_name} --linter=standard"
end
it "generates a gem skeleton with standard" do
gem_skeleton_assertions
expect(bundled_app("test-gem/Rakefile")).to read_as(
include('require "standard/rake"').
and(match(/default:.+:standard/))
)
end
it "includes standard in generated Gemfile" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
builder = Bundler::Dsl.new
builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
builder.dependencies
standard_dep = builder.dependencies.find {|d| d.name == "standard" }
expect(standard_dep).not_to be_nil
end
it "generates a default .standard.yml" do
expect(bundled_app("#{gem_name}/.standard.yml")).to exist
end
end
shared_examples_for "--linter=none flag" do
define_negated_matcher :exclude, :include
before do
bundle "gem #{gem_name} --no-rubocop"
bundle "gem #{gem_name} --linter=none"
end
it "generates a gem skeleton without rubocop" do
@ -188,46 +281,66 @@ RSpec.describe "bundle gem" do
expect(rubocop_dep).to be_nil
end
it "does not include standard in generated Gemfile" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
builder = Bundler::Dsl.new
builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
builder.dependencies
standard_dep = builder.dependencies.find {|d| d.name == "standard" }
expect(standard_dep).to be_nil
end
it "doesn't generate a default .rubocop.yml" do
expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist
end
it "doesn't generate a default .standard.yml" do
expect(bundled_app("#{gem_name}/.standard.yml")).to_not exist
end
end
it "has no rubocop offenses when using --rubocop flag", :readline do
it "has no rubocop offenses when using --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
bundle "gem #{gem_name} --rubocop"
bundle "gem #{gem_name} --linter=rubocop"
bundle_exec_rubocop
expect(last_command).to be_success
end
it "has no rubocop offenses when using --ext and --rubocop flag", :readline do
it "has no rubocop offenses when using --ext and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
bundle "gem #{gem_name} --ext --rubocop"
bundle "gem #{gem_name} --ext --linter=rubocop"
bundle_exec_rubocop
expect(last_command).to be_success
end
it "has no rubocop offenses when using --ext, --test=minitest, and --rubocop flag", :readline do
it "has no rubocop offenses when using --ext, --test=minitest, and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
bundle "gem #{gem_name} --ext --test=minitest --rubocop"
bundle "gem #{gem_name} --ext --test=minitest --linter=rubocop"
bundle_exec_rubocop
expect(last_command).to be_success
end
it "has no rubocop offenses when using --ext, --test=rspec, and --rubocop flag", :readline do
it "has no rubocop offenses when using --ext, --test=rspec, and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
bundle "gem #{gem_name} --ext --test=rspec --rubocop"
bundle "gem #{gem_name} --ext --test=rspec --linter=rubocop"
bundle_exec_rubocop
expect(last_command).to be_success
end
it "has no rubocop offenses when using --ext, --ext=test-unit, and --rubocop flag", :readline do
it "has no rubocop offenses when using --ext, --ext=test-unit, and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
bundle "gem #{gem_name} --ext --test=test-unit --rubocop"
bundle "gem #{gem_name} --ext --test=test-unit --linter=rubocop"
bundle_exec_rubocop
expect(last_command).to be_success
end
it "has no standard offenses when using --linter=standard flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
bundle "gem #{gem_name} --linter=standard"
bundle_exec_standardrb
expect(err).to be_empty
end
shared_examples_for "CI config is absent" do
it "does not create any CI files" do
expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to_not exist
@ -889,6 +1002,127 @@ RSpec.describe "bundle gem" do
end
end
context "--linter with no argument" do
it "does not generate any linter config" do
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist
expect(bundled_app("#{gem_name}/.standard.yml")).to_not exist
end
end
context "--linter set to rubocop" do
it "generates a RuboCop config" do
bundle "gem #{gem_name} --linter=rubocop"
expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist
expect(bundled_app("#{gem_name}/.standard.yml")).to_not exist
end
end
context "--linter set to standard" do
it "generates a Standard config" do
bundle "gem #{gem_name} --linter=standard"
expect(bundled_app("#{gem_name}/.standard.yml")).to exist
expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist
end
end
context "gem.linter setting set to none" do
it "doesn't generate any linter config" do
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist
expect(bundled_app("#{gem_name}/.standard.yml")).to_not exist
end
end
context "gem.linter setting set to rubocop" do
it "generates a RuboCop config file" do
bundle "config set gem.linter rubocop"
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist
end
end
context "gem.linter setting set to standard" do
it "generates a Standard config file" do
bundle "config set gem.linter standard"
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/.standard.yml")).to exist
end
end
context "gem.rubocop setting set to true", :bundler => "< 3" do
before do
bundle "config set gem.rubocop true"
bundle "gem #{gem_name}"
end
it "generates rubocop config" do
expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist
end
it "unsets gem.rubocop" do
bundle "config gem.rubocop"
expect(out).to include("You have not configured a value for `gem.rubocop`")
end
it "sets gem.linter=rubocop instead" do
bundle "config gem.linter"
expect(out).to match(/Set for the current user .*: "rubocop"/)
end
end
context "gem.linter set to rubocop and --linter with no arguments", :hint_text do
before do
bundle "config set gem.linter rubocop"
bundle "gem #{gem_name} --linter"
end
it "generates a RuboCop config file" do
expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist
end
it "hints that --linter is already configured" do
expect(out).to match("rubocop is already configured, ignoring --linter flag.")
end
end
context "gem.linter setting set to false and --linter with no arguments", :hint_text do
before do
bundle "config set gem.linter false"
bundle "gem #{gem_name} --linter"
end
it "asks to setup a linter" do
expect(out).to match("Do you want to add a code linter and formatter to your gem?")
end
it "hints that the choice will only be applied to the current gem" do
expect(out).to match("Your choice will only be applied to this gem.")
end
end
context "gem.linter setting not set and --linter with no arguments", :hint_text do
before do
bundle "gem #{gem_name} --linter"
end
it "asks to setup a linter" do
expect(out).to match("Do you want to add a code linter and formatter to your gem?")
end
it "hints that the choice will be applied to future bundle gem calls" do
hint = "Future `bundle gem` calls will use your choice. " \
"This setting can be changed anytime with `bundle config gem.linter`."
expect(out).to match(hint)
end
end
context "--edit option" do
it "opens the generated gemspec in the user's text editor" do
output = bundle "gem #{gem_name} --edit=echo"
@ -939,6 +1173,9 @@ RSpec.describe "bundle gem" do
before do
global_config "BUNDLE_GEM__RUBOCOP" => "true"
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
it_behaves_like "--linter=none flag"
it_behaves_like "--rubocop flag"
it_behaves_like "--no-rubocop flag"
end
@ -947,10 +1184,40 @@ RSpec.describe "bundle gem" do
before do
global_config "BUNDLE_GEM__RUBOCOP" => "false"
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
it_behaves_like "--linter=none flag"
it_behaves_like "--rubocop flag"
it_behaves_like "--no-rubocop flag"
end
context "with linter option in bundle config settings set to rubocop" do
before do
global_config "BUNDLE_GEM__LINTER" => "rubocop"
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
it_behaves_like "--linter=none flag"
end
context "with linter option in bundle config settings set to standard" do
before do
global_config "BUNDLE_GEM__LINTER" => "standard"
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
it_behaves_like "--linter=none flag"
end
context "with linter option in bundle config settings set to false" do
before do
global_config "BUNDLE_GEM__LINTER" => "false"
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
it_behaves_like "--linter=none flag"
end
context "with changelog option in bundle config settings set to true" do
before do
global_config "BUNDLE_GEM__CHANGELOG" => "true"
@ -1172,7 +1439,7 @@ Usage: "bundle gem NAME [OPTIONS]"
end
it "asks about CI service" do
global_config "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__RUBOCOP" => "false"
global_config "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__LINTER" => "false"
bundle "gem foobar" do |input, _, _|
input.puts "github"
@ -1182,7 +1449,7 @@ Usage: "bundle gem NAME [OPTIONS]"
end
it "asks about MIT license" do
global_config "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__RUBOCOP" => "false"
global_config "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__LINTER" => "false"
bundle "config list"
@ -1194,7 +1461,7 @@ Usage: "bundle gem NAME [OPTIONS]"
end
it "asks about CoC" do
global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__RUBOCOP" => "false"
global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__LINTER" => "false"
bundle "gem foobar" do |input, _, _|
input.puts "yes"
@ -1204,7 +1471,7 @@ Usage: "bundle gem NAME [OPTIONS]"
end
it "asks about CHANGELOG" do
global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__RUBOCOP" => "false",
global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__LINTER" => "false",
"BUNDLE_GEM__COC" => "false"
bundle "gem foobar" do |input, _, _|

View file

@ -1436,7 +1436,44 @@ In Gemfile:
end
describe "without git installed" do
it "prints a better error message" do
it "prints a better error message when installing" do
build_git "foo"
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rake", git: "https://github.com/ruby/rake"
G
lockfile <<-L
GIT
remote: https://github.com/ruby/rake
revision: 5c60da8644a9e4f655e819252e3b6ca77f42b7af
specs:
rake (13.0.6)
GEM
remote: https://rubygems.org/
specs:
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
rake!
BUNDLED WITH
#{Bundler::VERSION}
L
with_path_as("") do
bundle "install", :raise_on_error => false
end
expect(err).
to include("You need to install git to be able to use gems from git repositories. For help installing git, please refer to GitHub's tutorial at https://help.github.com/articles/set-up-git")
end
it "prints a better error message when updating" do
build_git "foo"
install_gemfile <<-G

View file

@ -20,7 +20,7 @@ RSpec.describe "bundle install with specific platforms" do
])
end
it "understands that a non-plaform specific gem in a old lockfile doesn't necessarily mean installing the non-specific variant" do
it "understands that a non-platform specific gem in a old lockfile doesn't necessarily mean installing the non-specific variant" do
setup_multiplatform_gem
system_gems "bundler-2.1.4"
@ -54,7 +54,7 @@ RSpec.describe "bundle install with specific platforms" do
expect(the_bundle).to include_gem("google-protobuf 3.0.0.alpha.5.0.5.1 universal-darwin")
end
it "understands that a non-plaform specific gem in a new lockfile locked only to RUBY doesn't necessarily mean installing the non-specific variant" do
it "understands that a non-platform specific gem in a new lockfile locked only to RUBY doesn't necessarily mean installing the non-specific variant" do
setup_multiplatform_gem
system_gems "bundler-2.1.4"

View file

@ -115,7 +115,7 @@ RSpec.shared_examples "bundle install --standalone" do
realworld_system_gems "fiddle --version 1.0.6", "tsort --version 0.1.0"
necessary_system_gems = ["optparse --version 0.1.1", "psych --version 3.3.2", "yaml --version 0.1.1", "logger --version 1.4.3", "etc --version 1.2.0"]
necessary_system_gems = ["optparse --version 0.1.1", "psych --version 3.3.2", "yaml --version 0.1.1", "logger --version 1.4.3", "etc --version 1.2.0", "stringio --version 3.0.0"]
necessary_system_gems += ["shellwords --version 0.1.0", "base64 --version 0.1.0", "resolv --version 0.2.1"] if Gem.rubygems_version < Gem::Version.new("3.3.3.a")
realworld_system_gems(*necessary_system_gems, :path => scoped_gem_path(bundled_app("bundle")))

View file

@ -166,9 +166,10 @@ RSpec.describe "the lockfile format" do
G
end
it "warns if the current is older than lockfile's bundler version" do
current_version = Bundler::VERSION
newer_minor = bump_minor(current_version)
it "warns if the current version is older than lockfile's bundler version, and locked version is a final release" do
current_version = "999.998.999"
system_gems "bundler-#{current_version}"
newer_minor = "999.999.0"
lockfile <<-L
GEM
@ -186,17 +187,16 @@ RSpec.describe "the lockfile format" do
#{newer_minor}
L
install_gemfile <<-G
install_gemfile <<-G, :env => { "BUNDLER_VERSION" => current_version }
source "#{file_uri_for(gem_repo2)}"
gem "rack"
G
pre_flag = prerelease?(newer_minor) ? " --pre" : ""
warning_message = "the running version of Bundler (#{current_version}) is older " \
"than the version that created the lockfile (#{newer_minor}). " \
"We suggest you to upgrade to the version that created the " \
"lockfile by running `gem install bundler:#{newer_minor}#{pre_flag}`."
"lockfile by running `gem install bundler:#{newer_minor}`."
expect(err).to include warning_message
lockfile_should_be <<-G
@ -216,6 +216,102 @@ RSpec.describe "the lockfile format" do
G
end
it "warns if the current version is older than lockfile's bundler version, and locked version is a prerelease" do
current_version = "999.998.999"
system_gems "bundler-#{current_version}"
newer_minor = "999.999.0.pre1"
lockfile <<-L
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
rack
BUNDLED WITH
#{newer_minor}
L
install_gemfile <<-G, :env => { "BUNDLER_VERSION" => current_version }
source "#{file_uri_for(gem_repo2)}"
gem "rack"
G
warning_message = "the running version of Bundler (#{current_version}) is older " \
"than the version that created the lockfile (#{newer_minor}). " \
"We suggest you to upgrade to the version that created the " \
"lockfile by running `gem install bundler:#{newer_minor} --pre`."
expect(err).to include warning_message
lockfile_should_be <<-G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
rack
BUNDLED WITH
#{newer_minor}
G
end
it "doesn't warn if the current version is older than lockfile's bundler version, and locked version is a dev version" do
current_version = "999.998.999"
system_gems "bundler-#{current_version}"
newer_minor = "999.999.0.dev"
lockfile <<-L
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
rack
BUNDLED WITH
#{newer_minor}
L
install_gemfile <<-G, :env => { "BUNDLER_VERSION" => current_version }
source "#{file_uri_for(gem_repo2)}"
gem "rack"
G
expect(err).to be_empty
lockfile_should_be <<-G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
rack
BUNDLED WITH
#{newer_minor}
G
end
it "warns when updating bundler major version" do
current_version = Bundler::VERSION
older_major = previous_major(current_version)

View file

@ -665,9 +665,55 @@ The :gist git source is deprecated, and will be removed in the future. Add this
end
it "prints a deprecation warning", :bundler => "< 3" do
expect(deprecations).to include "The `viz` command has been moved to the `bundle-viz` gem, see https://github.com/bundler/bundler-viz"
expect(deprecations).to include "The `viz` command has been moved to the `bundle-viz` gem, see https://github.com/rubygems/bundler-graph"
end
pending "fails with a helpful message", :bundler => "3"
end
describe "deprecating rubocop", :readline do
context "bundle gem --rubocop" do
before do
bundle "gem my_new_gem --rubocop", :raise_on_error => false
end
it "prints a deprecation warning", :bundler => "< 3" do
expect(deprecations).to include \
"--rubocop is deprecated, use --linter=rubocop"
end
end
context "bundle gem --no-rubocop" do
before do
bundle "gem my_new_gem --no-rubocop", :raise_on_error => false
end
it "prints a deprecation warning", :bundler => "< 3" do
expect(deprecations).to include \
"--no-rubocop is deprecated, use --linter"
end
end
context "bundle gem with gem.rubocop set to true" do
before do
bundle "gem my_new_gem", :env => { "BUNDLE_GEM__RUBOCOP" => "true" }, :raise_on_error => false
end
it "prints a deprecation warning", :bundler => "< 3" do
expect(deprecations).to include \
"config gem.rubocop is deprecated; we've updated your config to use gem.linter instead"
end
end
context "bundle gem with gem.rubocop set to false" do
before do
bundle "gem my_new_gem", :env => { "BUNDLE_GEM__RUBOCOP" => "false" }, :raise_on_error => false
end
it "prints a deprecation warning", :bundler => "< 3" do
expect(deprecations).to include \
"config gem.rubocop is deprecated; we've updated your config to use gem.linter instead"
end
end
end
end

View file

@ -3,25 +3,6 @@
require "set"
RSpec.describe "The library itself" do
def check_for_debugging_mechanisms(filename)
debugging_mechanisms_regex = /
(binding\.pry)|
(debugger)|
(sleep\s*\(?\d+)|
(fit\s*\(?("|\w))
/x
failing_lines = []
each_line(filename) do |line, number|
if line =~ debugging_mechanisms_regex && !line.end_with?("# ignore quality_spec\n")
failing_lines << number + 1
end
end
return if failing_lines.empty?
"#{filename} has debugging mechanisms (like binding.pry, sleep, debugger, rspec focusing, etc.) on lines #{failing_lines.join(", ")}"
end
def check_for_git_merge_conflicts(filename)
merge_conflicts_regex = /
<<<<<<<|
@ -125,16 +106,6 @@ RSpec.describe "The library itself" do
expect(error_messages.compact).to be_well_formed
end
it "does not include any leftover debugging or development mechanisms" do
exempt = %r{quality_spec.rb|support/helpers|vcr_cassettes|\.md|\.ronn|index\.txt|\.5|\.1}
error_messages = []
tracked_files.each do |filename|
next if filename =~ exempt
error_messages << check_for_debugging_mechanisms(filename)
end
expect(error_messages.compact).to be_well_formed
end
it "does not include any unresolved merge conflicts" do
error_messages = []
exempt = %r{lock/lockfile_spec|quality_spec|vcr_cassettes|\.ronn|lockfile_parser\.rb}

View file

@ -197,10 +197,11 @@ RSpec.describe "real world edgecases", :realworld => true do
end
it "outputs a helpful error message when gems have invalid gemspecs" do
install_gemfile <<-G, :standalone => true, :raise_on_error => false
install_gemfile <<-G, :standalone => true, :raise_on_error => false, :env => { "BUNDLE_FORCE_RUBY_PLATFORM" => "1" }
source 'https://rubygems.org'
gem "resque-scheduler", "2.2.0"
gem "redis-namespace", "1.6.0" # for a consistent resolution including ruby 2.3.0
gem "ruby2_keywords", "0.0.5"
G
expect(err).to include("You have one or more invalid gemspecs that need to be fixed.")
expect(err).to include("resque-scheduler 2.2.0 has an invalid gemspec")

View file

@ -74,10 +74,10 @@ RSpec.describe "fetching dependencies with a not available mirror", :realworld =
bundle :install, :artifice => nil, :raise_on_error => false
expect(out).to include("Fetching source index from #{mirror}")
expect(err).to include("Retrying fetcher due to error (2/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2) for \"#{host}\" port #{@mirror_port}) (#{mirror}/specs.4.8.gz)>")
expect(err).to include("Retrying fetcher due to error (3/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2) for \"#{host}\" port #{@mirror_port}) (#{mirror}/specs.4.8.gz)>")
expect(err).to include("Retrying fetcher due to error (4/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2) for \"#{host}\" port #{@mirror_port}) (#{mirror}/specs.4.8.gz)>")
expect(err).to include("Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2) for \"#{host}\" port #{@mirror_port}) (#{mirror}/specs.4.8.gz)>")
expect(err).to include("Retrying fetcher due to error (2/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2)")
expect(err).to include("Retrying fetcher due to error (3/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2)")
expect(err).to include("Retrying fetcher due to error (4/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2)")
expect(err).to include("Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2)")
end
it "prints each error and warning on a new line" do
@ -89,12 +89,7 @@ RSpec.describe "fetching dependencies with a not available mirror", :realworld =
bundle :install, :artifice => nil, :raise_on_error => false
expect(out).to include "Fetching source index from #{mirror}/"
expect(err).to include <<-EOS.strip
Retrying fetcher due to error (2/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2) for \"#{host}\" port #{@mirror_port}) (#{mirror}/specs.4.8.gz)>
Retrying fetcher due to error (3/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2) for \"#{host}\" port #{@mirror_port}) (#{mirror}/specs.4.8.gz)>
Retrying fetcher due to error (4/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2) for \"#{host}\" port #{@mirror_port}) (#{mirror}/specs.4.8.gz)>
Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2) for \"#{host}\" port #{@mirror_port}) (#{mirror}/specs.4.8.gz)>
EOS
expect(err.split("\n").count).to eq(4)
end
end
@ -112,10 +107,10 @@ Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUS
bundle :install, :artifice => nil, :raise_on_error => false
expect(out).to include("Fetching source index from #{mirror}")
expect(err).to include("Retrying fetcher due to error (2/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2) for \"#{host}\" port #{@mirror_port}) (#{mirror}/specs.4.8.gz)>")
expect(err).to include("Retrying fetcher due to error (3/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2) for \"#{host}\" port #{@mirror_port}) (#{mirror}/specs.4.8.gz)>")
expect(err).to include("Retrying fetcher due to error (4/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2) for \"#{host}\" port #{@mirror_port}) (#{mirror}/specs.4.8.gz)>")
expect(err).to include("Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2) for \"#{host}\" port #{@mirror_port}) (#{mirror}/specs.4.8.gz)>")
expect(err).to include("Retrying fetcher due to error (2/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2)")
expect(err).to include("Retrying fetcher due to error (3/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2)")
expect(err).to include("Retrying fetcher due to error (4/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2)")
expect(err).to include("Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2)")
end
end

View file

@ -390,7 +390,7 @@ RSpec.describe "bundler/inline#gemfile" do
dependency_installer_loads_fileutils = ruby "require 'rubygems/dependency_installer'; puts $LOADED_FEATURES.grep(/fileutils/)", :raise_on_error => false
skip "does not work if rubygems/dependency_installer loads fileutils, which happens until rubygems 3.2.0" unless dependency_installer_loads_fileutils.empty?
skip "does not work on ruby 3.0 because it changes the path to look for default gems, tsort is a default gem there, and we can't install it either like we do with fiddle because it doesn't yet exist" unless RUBY_VERSION < "3.0.0"
skip "pathname does not install cleanly on this ruby" if RUBY_VERSION < "2.7.0"
Dir.mkdir tmp("path_without_gemfile")
@ -399,6 +399,8 @@ RSpec.describe "bundler/inline#gemfile" do
realworld_system_gems "fileutils --version 1.4.1"
realworld_system_gems "pathname --version 0.2.0"
realworld_system_gems "fiddle" # not sure why, but this is needed on Windows to boot rubygems successfully
realworld_system_gems "timeout uri" # this spec uses net/http which requires these default gems

View file

@ -61,7 +61,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
build_repo4 do
build_gem "nokogiri", "1.11.1" do |s|
s.add_dependency "mini_portile2", "~> 2.5.0"
s.add_dependency "racc", "~> 1.4"
s.add_dependency "racc", "~> 1.5.2"
end
build_gem "nokogiri", "1.11.1" do |s|
@ -80,7 +80,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
mini_portile2 (2.5.0)
nokogiri (1.11.1)
mini_portile2 (~> 2.5.0)
racc (~> 1.4)
racc (~> 1.5.2)
nokogiri (1.11.1-#{Bundler.local_platform})
racc (~> 1.4)
racc (1.5.2)

View file

@ -745,41 +745,68 @@ end
expect(err).to be_empty
end
describe "$MANPATH" do
before do
context "when the user has `MANPATH` set", :man do
before { ENV["MANPATH"] = "/foo#{File::PATH_SEPARATOR}" }
it "adds the gem's man dir to the MANPATH" do
build_repo4 do
build_gem "with_man" do |s|
s.write("man/man1/page.1", "MANPAGE")
end
end
install_gemfile <<-G
source "#{file_uri_for(gem_repo4)}"
gem "with_man"
G
run "puts ENV['MANPATH']"
expect(out).to eq("#{default_bundle_path("gems/with_man-1.0/man")}#{File::PATH_SEPARATOR}/foo")
end
end
context "when the user has one set" do
before { ENV["MANPATH"] = "/foo#{File::PATH_SEPARATOR}" }
context "when the user does not have `MANPATH` set", :man do
before { ENV.delete("MANPATH") }
it "adds the gem's man dir to the MANPATH" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo4)}"
gem "with_man"
G
it "adds the gem's man dir to the MANPATH, leaving : in the end so that system man pages still work" do
build_repo4 do
build_gem "with_man" do |s|
s.write("man/man1/page.1", "MANPAGE")
end
run "puts ENV['MANPATH']"
expect(out).to eq("#{default_bundle_path("gems/with_man-1.0/man")}#{File::PATH_SEPARATOR}/foo")
build_gem "with_man_overriding_system_man" do |s|
s.write("man/man1/ls.1", "LS MANPAGE")
end
end
end
context "when the user does not have one set" do
before { ENV.delete("MANPATH") }
install_gemfile <<-G
source "#{file_uri_for(gem_repo4)}"
gem "with_man"
G
it "adds the gem's man dir to the MANPATH" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo4)}"
gem "with_man"
G
run <<~RUBY
puts ENV['MANPATH']
require "open3"
puts Open3.capture2e("man", "ls")[1].success?
RUBY
run "puts ENV['MANPATH']"
expect(out).to eq(default_bundle_path("gems/with_man-1.0/man").to_s)
end
expect(out).to eq("#{default_bundle_path("gems/with_man-1.0/man")}#{File::PATH_SEPARATOR}\ntrue")
install_gemfile <<-G
source "#{file_uri_for(gem_repo4)}"
gem "with_man_overriding_system_man"
G
run <<~RUBY
puts ENV['MANPATH']
require "open3"
puts Open3.capture2e("man", "ls")[0]
RUBY
lines = out.split("\n")
expect(lines).to include("#{default_bundle_path("gems/with_man_overriding_system_man-1.0/man")}#{File::PATH_SEPARATOR}")
expect(lines).to include("LS MANPAGE")
end
end
@ -1298,7 +1325,9 @@ end
exempts << "uri" if Gem.ruby_version >= Gem::Version.new("2.7")
exempts << "pathname" if Gem.ruby_version >= Gem::Version.new("3.0")
exempts << "set" unless Gem.rubygems_version >= Gem::Version.new("3.2.6")
exempts << "tsort" if Gem.ruby_version >= Gem::Version.new("3.0")
exempts << "tsort" unless Gem.rubygems_version >= Gem::Version.new("3.2.31")
exempts << "error_highlight" # added in Ruby 3.1 as a default gem
exempts << "ruby2_keywords" # added in Ruby 3.1 as a default gem
exempts
end
@ -1466,5 +1495,21 @@ end
expect(last_command.stdboth).to eq("true")
end
it "memoizes initial set of specs when requiring bundler/setup, so that even if further code mutates dependencies, Bundler.definition.specs is not affected" do
install_gemfile <<~G
source "#{file_uri_for(gem_repo1)}"
gem "yard"
gem "rack", :group => :test
G
ruby <<-RUBY, :raise_on_error => false
require "bundler/setup"
Bundler.require(:test).select! {|d| (d.groups & [:test]).any? }
puts Bundler.definition.specs.map(&:name).join(", ")
RUBY
expect(out).to include("rack, yard")
end
end
end

View file

@ -34,6 +34,7 @@ RSpec.configure do |config|
config.filter_run_excluding :readline => Gem.win_platform?
config.filter_run_excluding :jruby => RUBY_ENGINE != "jruby"
config.filter_run_excluding :truffleruby => RUBY_ENGINE != "truffleruby"
config.filter_run_excluding :man => Gem.win_platform?
config.filter_run_when_matching :focus unless ENV["CI"]
end

View file

@ -10,7 +10,7 @@ module Spec
def reset!
Dir.glob("#{tmp}/{gems/*,*}", File::FNM_DOTMATCH).each do |dir|
next if %w[base base_system remote1 rubocop gems rubygems . ..].include?(File.basename(dir))
next if %w[base base_system remote1 rubocop standard gems rubygems . ..].include?(File.basename(dir))
FileUtils.rm_rf(dir)
end
FileUtils.mkdir_p(home)

View file

@ -37,6 +37,10 @@ module Spec
@rubocop_gemfile ||= source_root.join(rubocop_gemfile_basename)
end
def standard_gemfile
@standard_gemfile ||= source_root.join(standard_gemfile_basename)
end
def dev_gemfile
@dev_gemfile ||= git_root.join("dev_gems.rb")
end
@ -150,6 +154,10 @@ module Spec
tmp.join("gems/rubocop")
end
def standard_gems
tmp.join("gems/standard")
end
def file_uri_for(path)
protocol = "file://"
root = Gem.win_platform? ? "/" : ""
@ -285,6 +293,17 @@ module Spec
source_root.join("tool/bundler/#{filename}.rb")
end
def standard_gemfile_basename
filename = if RUBY_VERSION.start_with?("2.3")
"standard23_gems"
elsif RUBY_VERSION.start_with?("2.4")
"standard24_gems"
else
"standard_gems"
end
source_root.join("tool/bundler/#{filename}.rb")
end
extend self
end
end

View file

@ -69,6 +69,7 @@ module Spec
install_gems(test_gemfile)
install_gems(rubocop_gemfile, Path.rubocop_gems.to_s)
install_gems(standard_gemfile, Path.standard_gems.to_s)
end
private
@ -118,6 +119,10 @@ module Spec
Path.rubocop_gemfile
end
def standard_gemfile
Path.standard_gemfile
end
def dev_gemfile
Path.dev_gemfile
end

View file

@ -1,30 +1,30 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-CBC,4E38D58B5A059DB6
DEK-Info: AES-256-CBC,CB6FD0B173EF450C6EE21A01DD785C1D
IgWLfnHVnkErKkhysrUMoE0ubkRDtJXZv9KR02jGGFk/kGqWyTqPk08uzhwVNM+l
eOk0qfPykkJM3KZgqTsD6xfA1D5WqFp5mLoFXVVTn9I3acSZsqOY0FweCipwdVpI
x+9Fl+v62kIW06dOjyWLE1abed9hHiXesGGsD87/RJSywy4OBxOcrhR1fJLK4ElR
ya0UzI7rWnmZMChjaZBssfzT1DR79/dARXhon2m5EiIJDjMpc8BKGYlQy5RHCHwA
cnrhUTTvsggZbQtmLZ/yVx8FSJ273XpYR0pmwbw4j1R+zeXQRK5MroBnCfOGcYa7
rmpERmDW3VAuxXR20SUAGdo1XOMTDe1uLbaotn6e56pXghIaYROTPS+HsuOkAZGY
OYWEkUoyog4l4n+h/C1umFfTFGvKNATLgDugONFvTw/PLbjvl+sWMy2QfqH0MlNB
DIUPxhEVCFD9oB4nfB86WDAmPp1DH9/IBet/21kbQ2eTIzakTdG3XiC+xzAQRu68
EOCTbasFWGxlCix66gt4xWMLksEg8UhWSpjS3/HsifrKyNMB8sfUFYmZmOYMW4mf
NuEtpBL3AdHNObN8nQ75HfehukzNpbYVRsLzWrVgtxvXHVpnvoCCpCvQBMHeRZxK
6m028mhH1m6yYE/uGFiRKLrN7BKAttbUiqnGgVIg/lQQilFWwylxQ6aXqJGmNgxa
oihzWZRlXivIhhrM7VMnLoKAF/YfmWpP3zahGpBQGfObtPtm44R0ezXPdtsivnyu
CmFOPGzRNMKZtH/lwVhuIIK3AFIGDsRRP9ySN4YfjQZnTdu2sRlxBnANP9m8W9T2
p+C4zVkDYAbsuWq2HpHwsdL8gqIiXeptsHLqkNw+ulSSLyeBCgM9fpV3RsNGjwqu
k8QLb1CYp2VX46CE8UKvOd/nyFnEsD+EAc3WangEwA41m2IaXcbs9Au7xsG9oacZ
DrxlJVNxlxO9YyP9dNOTfP0fHIiygKQQY2aU3y3oRneu7ogYES5V2mUNH7cYUWVL
CHPXAoUXJErvDQ/opW2DroA9Eqv9sST6WqBf6LXRcWU0ntfzcFUbEqgmCmB7Cbu2
8udEn6iWilQahLyDoAShLkU7+Tk78Z1c6RuqjyY4VboZPzxrTYK8YIXzwX+jj9bG
KIIGS5eghK185+AjlwtzJ7MBdoL323YIik6uOZluhnJHLaxjxUXGa1VqDgsyqGi7
ISRMTpVTrbR+UtoEi4ZhMjobtFUr7lGkt24VkXwBKdoyryj4RPHGdp7Tf6XDJufQ
+KKhqt8QrpOTPiMskFN2disOSF5/YZCmtT84nkhU7Hf1lkQ2kfx1zfNk0GqYYXOW
zHOAczy8gWBRetDMnhRYohDzQGWn//b+2Wr2n1RD8D9kyjMRhpFMYfQGfRcuPGjW
91k/T0XFcjcjeZPL9s+HITmrh7zg5WxbCfTEp91j3Oy1bns196SY77TE0BzUsqR2
geJggcUMEfyvHiiCMtijmSSD9nf8tNIxLVL8Jaf1coA6e1CrlHnYAu2f/Q3GIcvU
EEEmw+cZRwsk4fffYzh5psxxGdXKBv1KcQ/CeBhZL0WJsCp2y5oxwg==
KqHn2Df8hSuwNE+W+60MnGtc6xpoXmF3iN25iVwcN67krYn+N6cBhjFeXwXccYwJ
2gHSu4iEK9Qe32vK0yuv8N9h/fmsabZl0TotnEem/pqO5T8W4LxyK+Rw0s6RB30S
C+mUisRADTanAxyBxsNU8xR8OAUNMAAxV1me6It0W2lfNE3t5jg/Kr0NWMoRUNRx
dkE6WlD5D8jBeC3QdZ6OuE7QXOCEAWAjcFMc0d1WJq2t2r3TrLVfTH7EOoRyvL1H
rrFRx/dEW1UJfM6P11wB5R0nhg3rDXF7oDFszjwO/3tzARke0NZuN37l301lYRl1
aolO6sShJLa0Ml/TgNcJw0S6rc6a1Z52gTfQKztKcL1UX4HLZg75zKmn6qfatMBC
iXn+pQRYNsOPQ5h4r7lBBqvuV+gBw+rN768tYpZ2/YVDaygxETHcZAFCdAw/JNbP
d0XPIbP79NRrCgzSo58LKQGuOQf3Hh0vp1YS+MilMtm/eogoj1enSPM+ymStHRwG
i+D00xCQ6blSOZ2eUUBJXt11YzP22GYnv+XTR/5kGKkTIvoRMfd+39bQyR32IEv2
Z+yweAGQInD94eifT9ObbIayJ47y01KP0+Vj6hz4RCFsmJKsYiai5JiKlmf7lV9w
7zH3TtCOx/xSyomesXVRkqvFkdyeguU72kXc5tiMPaDXGCOeV0GWyR1GU1DUX9/K
60E7ym0Wx77WGMKk2fkirZzBdOeliyCRUXd7ccN2rBCjTwtjAUIk27lwzdUaTUv7
EmjauDvSMFtir58c+zjlLmBaSQOzKcj0KXMp0Oucls9bD85WGGbGyzGhTa0AZ+/+
cCEJt7RAwW0kTEO/uO+BAZe/zBoi9ek+QBn54FK3E7CXfS4Oi9Qbc3fwlVyTlVmz
ZGrCncO0TIVGErFWK24Z7lX8rBnk8enfnamrPfKtwn4LG9aDfhSj8DtisjlRUVT5
chDQ+CCi9rh3wXh28lyS+nXJ3yFidCzRgcsc3PpN/c4DNRggZc+C/KDw+J2FW+8Y
p65OliBQHQcG0PnCa2xRyCGevytPG0rfNDgyaY33dPEo90mBLVcwLbzGiSGBHgFl
pr8A/rqbnFpRO39NYbACeRFCqPpzyzfARCCcjcDoFrENdIaJui0fjlBkoV3B/KiK
EVjDcgwt1HAtz8bV2YJ+OpQbhD7E90e2vTRMuXAH21Ygo32VOS0LRlCRc9ZyZW4z
PTyO/6a+FbXZ1zhVJxu/0bmBERZ14WVmWq56oxQav8knpxYeYPgpEmIZnrHnJ1Ko
UoXcc8Hy4NKtaBmDcaF8TCobNsRZTxO/htqpdyNsOrBSsnX2kP5D/O1l1vuVYi1/
RYfUqL9dvGzvfsFuuDDjDlQ/fIA6pFzJV3fy4KJHlF1r33qaE/lNMdpKljBwvUII
Vog4cGmzxssqK5q9kuogcuyeOuFODjBNW4qt0WylSi9bwwy3ZwaZLRqhngz6+tCV
Jp45Gk881XiVe3aVU0l+4DmJJ9/5vwqjH5Vo/GJqFU6gzB+Zv/0plYeNkuE0Xo2z
ecdxnGKVPl42q44lvczjDw2KX0ahxQrfrbcl48//zR295u9POzCL97d6zpioI2NR
-----END RSA PRIVATE KEY-----

View file

@ -16,16 +16,6 @@ begin
rescue Gem::LoadError
end
begin
require 'simplecov'
SimpleCov.start do
add_filter "/test/"
add_filter "/bundler/"
add_filter "/lib/rubygems/resolver/molinillo"
end
rescue LoadError
end
if File.exist?(bundler_gemspec)
require_relative '../../bundler/lib/bundler'
else
@ -409,6 +399,14 @@ class Gem::TestCase < Test::Unit::TestCase
@orig_bindir = RbConfig::CONFIG["bindir"]
RbConfig::CONFIG["bindir"] = File.join @gemhome, "bin"
@orig_sitelibdir = RbConfig::CONFIG["sitelibdir"]
new_sitelibdir = @orig_sitelibdir.sub(RbConfig::CONFIG["prefix"], @gemhome)
$LOAD_PATH.insert(Gem.load_path_insert_index, new_sitelibdir)
RbConfig::CONFIG["sitelibdir"] = new_sitelibdir
@orig_mandir = RbConfig::CONFIG["mandir"]
RbConfig::CONFIG["mandir"] = File.join @gemhome, "share", "man"
Gem::Specification.unresolved_deps.clear
Gem.use_paths(@gemhome)
@ -480,6 +478,8 @@ class Gem::TestCase < Test::Unit::TestCase
Gem.ruby = @orig_ruby if @orig_ruby
RbConfig::CONFIG['mandir'] = @orig_mandir
RbConfig::CONFIG['sitelibdir'] = @orig_sitelibdir
RbConfig::CONFIG['bindir'] = @orig_bindir
Gem.instance_variable_set :@default_specifications_dir, nil
@ -1084,19 +1084,23 @@ Also, a list:
@fetcher.data["#{@gem_repo}latest_specs.#{v}.gz"] = l_zip
@fetcher.data["#{@gem_repo}prerelease_specs.#{v}.gz"] = p_zip
v = Gem.marshal_version
all_specs.each do |spec|
path = "#{@gem_repo}quick/Marshal.#{v}/#{spec.original_name}.gemspec.rz"
data = Marshal.dump spec
data_deflate = Zlib::Deflate.deflate data
@fetcher.data[path] = data_deflate
end
write_marshalled_gemspecs(*all_specs)
end
nil # force errors
end
def write_marshalled_gemspecs(*all_specs)
v = Gem.marshal_version
all_specs.each do |spec|
path = "#{@gem_repo}quick/Marshal.#{v}/#{spec.original_name}.gemspec.rz"
data = Marshal.dump spec
data_deflate = Zlib::Deflate.deflate data
@fetcher.data[path] = data_deflate
end
end
##
# Deflates +data+

View file

@ -118,7 +118,7 @@ class TestGemCommand < Gem::TestCase
use_ui @ui do
@cmd.when_invoked { true }
ex = assert_raise OptionParser::InvalidOption do
ex = assert_raise Gem::OptionParser::InvalidOption do
@cmd.invoke('-zzz')
end

View file

@ -745,7 +745,7 @@ ERROR: --private-key not specified and ~/.gem/gem-private_key.pem does not exis
def test_handle_options_add_bad
nonexistent = File.join @tempdir, 'nonexistent'
e = assert_raise OptionParser::InvalidArgument do
e = assert_raise Gem::OptionParser::InvalidArgument do
@cmd.handle_options %W[--add #{nonexistent}]
end
@ -755,7 +755,7 @@ ERROR: --private-key not specified and ~/.gem/gem-private_key.pem does not exis
bad = File.join @tempdir, 'bad'
FileUtils.touch bad
e = assert_raise OptionParser::InvalidArgument do
e = assert_raise Gem::OptionParser::InvalidArgument do
@cmd.handle_options %W[--add #{bad}]
end
@ -765,7 +765,7 @@ ERROR: --private-key not specified and ~/.gem/gem-private_key.pem does not exis
def test_handle_options_certificate
nonexistent = File.join @tempdir, 'nonexistent'
e = assert_raise OptionParser::InvalidArgument do
e = assert_raise Gem::OptionParser::InvalidArgument do
@cmd.handle_options %W[--certificate #{nonexistent}]
end
@ -775,7 +775,7 @@ ERROR: --private-key not specified and ~/.gem/gem-private_key.pem does not exis
bad = File.join @tempdir, 'bad'
FileUtils.touch bad
e = assert_raise OptionParser::InvalidArgument do
e = assert_raise Gem::OptionParser::InvalidArgument do
@cmd.handle_options %W[--certificate #{bad}]
end
@ -786,7 +786,7 @@ ERROR: --private-key not specified and ~/.gem/gem-private_key.pem does not exis
def test_handle_options_key_bad
nonexistent = File.join @tempdir, 'nonexistent'
e = assert_raise OptionParser::InvalidArgument do
e = assert_raise Gem::OptionParser::InvalidArgument do
@cmd.handle_options %W[--private-key #{nonexistent}]
end
@ -797,14 +797,14 @@ ERROR: --private-key not specified and ~/.gem/gem-private_key.pem does not exis
bad = File.join @tempdir, 'bad'
FileUtils.touch bad
e = assert_raise OptionParser::InvalidArgument do
e = assert_raise Gem::OptionParser::InvalidArgument do
@cmd.handle_options %W[--private-key #{bad}]
end
assert_equal "invalid argument: --private-key #{bad}: invalid RSA, DSA, or EC key",
e.message
e = assert_raise OptionParser::InvalidArgument do
e = assert_raise Gem::OptionParser::InvalidArgument do
@cmd.handle_options %W[--private-key #{PUBLIC_KEY_FILE}]
end
@ -851,7 +851,7 @@ ERROR: --private-key not specified and ~/.gem/gem-private_key.pem does not exis
def test_handle_options_sign_nonexistent
nonexistent = File.join @tempdir, 'nonexistent'
e = assert_raise OptionParser::InvalidArgument do
e = assert_raise Gem::OptionParser::InvalidArgument do
@cmd.handle_options %W[
--private-key #{ALTERNATE_KEY_FILE}

View file

@ -79,6 +79,42 @@ class TestGemCommandsFetchCommand < Gem::TestCase
"#{a2.full_name} not fetched")
end
def test_execute_platform
a2_spec, a2 = util_gem("a", "2")
a2_universal_darwin_spec, a2_universal_darwin = util_gem("a", "2") do |s|
s.platform = 'universal-darwin'
end
Gem::RemoteFetcher.fetcher = @fetcher = Gem::FakeFetcher.new
write_marshalled_gemspecs(a2_spec, a2_universal_darwin_spec)
@cmd.options[:args] = %w[a]
@fetcher.data["#{@gem_repo}latest_specs.#{Gem.marshal_version}.gz"] = util_gzip(Marshal.dump([
Gem::NameTuple.new(a2_spec.name, a2_spec.version, a2_spec.platform),
Gem::NameTuple.new(a2_universal_darwin_spec.name, a2_universal_darwin_spec.version, a2_universal_darwin_spec.platform),
]))
@fetcher.data["#{@gem_repo}gems/#{a2_spec.file_name}"] = Gem.read_binary(a2)
FileUtils.cp a2, a2_spec.cache_file
@fetcher.data["#{@gem_repo}gems/#{a2_universal_darwin_spec.file_name}"] = Gem.read_binary(a2_universal_darwin)
FileUtils.cp a2_universal_darwin, a2_universal_darwin_spec.cache_file
util_set_arch 'arm64-darwin20' do
use_ui @ui do
Dir.chdir @tempdir do
@cmd.execute
end
end
end
assert_path_exist(File.join(@tempdir, a2_universal_darwin_spec.file_name),
"#{a2_universal_darwin_spec.full_name} not fetched")
end
def test_execute_specific_prerelease
specs = spec_fetcher do |fetcher|
fetcher.gem 'a', 2

View file

@ -40,18 +40,18 @@ class TestGemCommandsServerCommand < Gem::TestCase
begin
@cmd.send :handle_options, %w[-p discard]
assert_equal 9, @cmd.options[:port]
rescue OptionParser::InvalidArgument
rescue Gem::OptionParser::InvalidArgument
# for container environment on GitHub Actions
end
e = assert_raise OptionParser::InvalidArgument do
e = assert_raise Gem::OptionParser::InvalidArgument do
@cmd.send :handle_options, %w[-p nonexistent]
end
assert_equal 'invalid argument: -p nonexistent: no such named service',
e.message
e = assert_raise OptionParser::InvalidArgument do
e = assert_raise Gem::OptionParser::InvalidArgument do
@cmd.send :handle_options, %w[-p 65536]
end

Some files were not shown because too many files have changed in this diff Show more