Skip to content

Commit

Permalink
Merge Bundler 2.1.0.pre.3
Browse files Browse the repository at this point in the history
  Features:
    - Add caller information to some deprecation messages to make them easier to fix [#7361](rubygems/bundler#7361)
    - Reconcile `bundle cache` vs `bundle package` everywhere. Now in docs, CLI help and everywhere else `bundle cache` is the preferred version and `bundle package` remains as an alias [#7389](rubygems/bundler#7389)
    - Display some basic `bundler` documentation together with ruby's RDoc based documentation [#7394](rubygems/bundler#7394)

  Bugfixes:
    - Fix typos deprecation message and upgrading docs [#7374](rubygems/bundler#7374)
    - Deprecation warnings about `taint` usage on ruby 2.7 [#7385](rubygems/bundler#7385)
    - Fix `--help` flag not correctly delegating to `man` when used with command aliases [#7388](rubygems/bundler#7388)
    - `bundle add` should cache newly added gems if an application cache exists [#7393](rubygems/bundler#7393)
    - Stop using an insecure folder as a "fallback home" when user home is not defined [#7416](rubygems/bundler#7416)
    - Fix `bundler/inline` warning about `Bundler.root` redefinition [#7417](rubygems/bundler#7417)
  • Loading branch information
hsbt committed Nov 11, 2019
1 parent fd69f82 commit 7585bc3
Show file tree
Hide file tree
Showing 158 changed files with 1,894 additions and 1,495 deletions.
111 changes: 87 additions & 24 deletions lib/bundler.rb
Expand Up @@ -14,6 +14,25 @@
require_relative "bundler/current_ruby"
require_relative "bundler/build_metadata"

# Bundler provides a consistent environment for Ruby projects by
# tracking and installing the exact gems and versions that are needed.
#
# Since Ruby 2.6, Bundler is a part of Ruby's standard library.
#
# Bunder is used by creating _gemfiles_ listing all the project dependencies
# and (optionally) their versions and then using
#
# require 'bundler/setup'
#
# or Bundler.setup to setup environment where only specified gems and their
# specified versions could be used.
#
# See {Bundler website}[https://bundler.io/docs.html] for extensive documentation
# on gemfiles creation and Bundler usage.
#
# As a standard library inside project, Bundler could be used for introspection
# of loaded and required modules.
#
module Bundler
environment_preserver = EnvironmentPreserver.new(ENV, EnvironmentPreserver::BUNDLER_KEYS)
ORIGINAL_ENV = environment_preserver.restore
Expand Down Expand Up @@ -64,11 +83,11 @@ def configure
end

def ui
(defined?(@ui) && @ui) || (self.ui = UI::Silent.new)
(defined?(@ui) && @ui) || (self.ui = UI::Shell.new)
end

def ui=(ui)
Bundler.rubygems.ui = ui ? UI::RGProxy.new(ui) : nil
Bundler.rubygems.ui = UI::RGProxy.new(ui)
@ui = ui
end

Expand All @@ -91,6 +110,33 @@ def bin_path
end
end

# Turns on the Bundler runtime. After +Bundler.setup+ call, all +load+ or
# +require+ of the gems would be allowed only if they are part of
# the Gemfile or Ruby's standard library. If the versions specified
# in Gemfile, only those versions would be loaded.
#
# Assuming Gemfile
#
# gem 'first_gem', '= 1.0'
# group :test do
# gem 'second_gem', '= 1.0'
# end
#
# The code using Bundler.setup works as follows:
#
# require 'third_gem' # allowed, required from global gems
# require 'first_gem' # allowed, loads the last installed version
# Bundler.setup
# require 'fourth_gem' # fails with LoadError
# require 'second_gem' # loads exactly version 1.0
#
# +Bundler.setup+ can be called only once, all subsequent calls are no-op.
#
# If _groups_ list is provided, only gems from specified groups would
# be allowed (gems specified outside groups belong to special +:default+ group).
#
# To require all gems from Gemfile (or only some groups), see Bundler.require.
#
def setup(*groups)
# Return if all groups are already loaded
return @setup if defined?(@setup) && @setup
Expand All @@ -107,6 +153,24 @@ def setup(*groups)
end
end

# Setups Bundler environment (see Bundler.setup) if it is not already set,
# and loads all gems from groups specified. Unlike ::setup, can be called
# multiple times with different groups (if they were allowed by setup).
#
# Assuming Gemfile
#
# gem 'first_gem', '= 1.0'
# group :test do
# gem 'second_gem', '= 1.0'
# end
#
# The code will work as follows:
#
# Bundler.setup # allow all groups
# Bundler.require(:default) # requires only first_gem
# # ...later
# Bundler.require(:test) # requires second_gem
#
def require(*groups)
setup(*groups).require(*groups)
end
Expand All @@ -116,7 +180,7 @@ def load
end

def environment
SharedHelpers.major_deprecation 2, "Bundler.environment has been removed in favor of Bundler.load"
SharedHelpers.major_deprecation 2, "Bundler.environment has been removed in favor of Bundler.load", :print_caller_location => true
load
end

Expand Down Expand Up @@ -167,8 +231,7 @@ def user_home
end

if warning
Kernel.send(:require, "etc")
user_home = tmp_home_path(Etc.getlogin, warning)
user_home = tmp_home_path(warning)
Bundler.ui.warn "#{warning}\nBundler will use `#{user_home}' as your home directory temporarily.\n"
user_home
else
Expand All @@ -177,21 +240,6 @@ def user_home
end
end

def tmp_home_path(login, warning)
login ||= "unknown"
Kernel.send(:require, "tmpdir")
path = Pathname.new(Dir.tmpdir).join("bundler", "home")
SharedHelpers.filesystem_access(path) do |tmp_home_path|
unless tmp_home_path.exist?
tmp_home_path.mkpath
tmp_home_path.chmod(0o777)
end
tmp_home_path.join(login).tap(&:mkpath)
end
rescue RuntimeError => e
raise e.exception("#{warning}\nBundler also failed to create a temporary home directory at `#{path}':\n#{e}")
end

def user_bundle_path(dir = "home")
env_var, fallback = case dir
when "home"
Expand Down Expand Up @@ -282,7 +330,8 @@ def clean_env
Bundler::SharedHelpers.major_deprecation(
2,
"`Bundler.clean_env` has been deprecated in favor of `Bundler.unbundled_env`. " \
"If you instead want the environment before bundler was originally loaded, use `Bundler.original_env`"
"If you instead want the environment before bundler was originally loaded, use `Bundler.original_env`",
:print_caller_location => true
)

unbundled_env
Expand Down Expand Up @@ -321,7 +370,8 @@ def with_clean_env
Bundler::SharedHelpers.major_deprecation(
2,
"`Bundler.with_clean_env` has been deprecated in favor of `Bundler.with_unbundled_env`. " \
"If you instead want the environment before bundler was originally loaded, use `Bundler.with_original_env`"
"If you instead want the environment before bundler was originally loaded, use `Bundler.with_original_env`",
:print_caller_location => true
)

with_env(unbundled_env) { yield }
Expand All @@ -342,7 +392,8 @@ def clean_system(*args)
Bundler::SharedHelpers.major_deprecation(
2,
"`Bundler.clean_system` has been deprecated in favor of `Bundler.unbundled_system`. " \
"If you instead want to run the command in the environment before bundler was originally loaded, use `Bundler.original_system`"
"If you instead want to run the command in the environment before bundler was originally loaded, use `Bundler.original_system`",
:print_caller_location => true
)

with_env(unbundled_env) { Kernel.system(*args) }
Expand All @@ -363,7 +414,8 @@ def clean_exec(*args)
Bundler::SharedHelpers.major_deprecation(
2,
"`Bundler.clean_exec` has been deprecated in favor of `Bundler.unbundled_exec`. " \
"If you instead want to exec to a command in the environment before bundler was originally loaded, use `Bundler.original_exec`"
"If you instead want to exec to a command in the environment before bundler was originally loaded, use `Bundler.original_exec`",
:print_caller_location => true
)

with_env(unbundled_env) { Kernel.exec(*args) }
Expand Down Expand Up @@ -608,6 +660,17 @@ def configure_gem_home
Bundler.rubygems.clear_paths
end

def tmp_home_path(warning)
Kernel.send(:require, "tmpdir")
SharedHelpers.filesystem_access(Dir.tmpdir) do
path = Bundler.tmp
at_exit { Bundler.rm_rf(path) }
path
end
rescue RuntimeError => e
raise e.exception("#{warning}\nBundler also failed to create a temporary home directory':\n#{e}")
end

# @param env [Hash]
def with_env(env)
backup = ENV.to_hash
Expand Down
80 changes: 55 additions & 25 deletions lib/bundler/cli.rb
Expand Up @@ -9,15 +9,19 @@ class CLI < Thor
package_name "Bundler"

AUTO_INSTALL_CMDS = %w[show binstubs outdated exec open console licenses clean].freeze
PARSEABLE_COMMANDS = %w[
check config help exec platform show version
].freeze
PARSEABLE_COMMANDS = %w[check config help exec platform show version].freeze

COMMAND_ALIASES = {
"check" => "c",
"install" => "i",
"list" => "ls",
"exec" => ["e", "ex", "exe"],
"cache" => ["package", "pack"],
"version" => ["-v", "--version"],
}.freeze

def self.start(*)
super
rescue Exception => e # rubocop:disable Lint/RescueException
Bundler.ui = UI::Shell.new
raise e
ensure
Bundler::SharedHelpers.print_major_deprecations!
end
Expand All @@ -29,6 +33,24 @@ def self.dispatch(*)
end
end

def self.all_aliases
@all_aliases ||= begin
command_aliases = {}

COMMAND_ALIASES.each do |name, aliases|
Array(aliases).each do |one_alias|
command_aliases[one_alias] = name
end
end

command_aliases
end
end

def self.aliases_for(command_name)
COMMAND_ALIASES.select {|k, _| k == command_name }.invert
end

def initialize(*args)
super

Expand Down Expand Up @@ -68,9 +90,7 @@ def cli_help
version
Bundler.ui.info "\n"

primary_commands = ["install", "update",
Bundler.feature_flag.bundler_3_mode? ? "cache" : "package",
"exec", "config", "help"]
primary_commands = ["install", "update", "cache", "exec", "config", "help"]

list = self.class.printable_commands(true)
by_name = list.group_by {|name, _message| name.match(/^bundle (\w+)/)[1] }
Expand Down Expand Up @@ -154,14 +174,15 @@ def init
"Use the specified gemfile instead of Gemfile"
method_option "path", :type => :string, :banner =>
"Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}"
map "c" => "check"
def check
remembered_flag_deprecation("path")

require_relative "cli/check"
Check.new(options).run
end

map aliases_for("check")

desc "remove [GEM [GEM ...]]", "Removes gems from the Gemfile"
long_desc <<-D
Removes the given gems from the Gemfile while ensuring that the resulting Gemfile is still valid. If the gem is not found, Bundler prints a error message and if gem could not be removed due to any reason Bundler will display a warning.
Expand Down Expand Up @@ -223,7 +244,6 @@ def remove(*gems)
"Exclude gems that are part of the specified named group."
method_option "with", :type => :array, :banner =>
"Include gems that are part of the specified named group."
map "i" => "install"
def install
SharedHelpers.major_deprecation(2, "The `--force` option has been renamed to `--redownload`") if ARGV.include?("--force")

Expand All @@ -237,6 +257,8 @@ def install
end
end

map aliases_for("install")

desc "update [OPTIONS]", "Update the current environment"
long_desc <<-D
Update will install the newest versions of the gems listed in the Gemfile. Use
Expand Down Expand Up @@ -328,7 +350,7 @@ def list
List.new(options).run
end

map %w[ls] => "list"
map aliases_for("list")

desc "info GEM [OPTIONS]", "Show information for the given gem"
method_option "path", :type => :boolean, :banner => "Print full path to gem"
Expand Down Expand Up @@ -412,7 +434,7 @@ def outdated(*gems)
Outdated.new(options, gems).run
end

desc "#{Bundler.feature_flag.bundler_3_mode? ? :cache : :package} [OPTIONS]", "Locks and then caches all of the gems into vendor/cache"
desc "cache [OPTIONS]", "Locks and then caches all of the gems into vendor/cache"
unless Bundler.feature_flag.cache_all?
method_option "all", :type => :boolean,
:banner => "Include all sources (including path and git)."
Expand All @@ -421,24 +443,25 @@ def outdated(*gems)
method_option "cache-path", :type => :string, :banner =>
"Specify a different cache path than the default (vendor/cache)."
method_option "gemfile", :type => :string, :banner => "Use the specified gemfile instead of Gemfile"
method_option "no-install", :type => :boolean, :banner => "Don't install the gems, only the package."
method_option "no-install", :type => :boolean, :banner => "Don't install the gems, only update the cache."
method_option "no-prune", :type => :boolean, :banner => "Don't remove stale gems from the cache."
method_option "path", :type => :string, :banner =>
"Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}"
method_option "quiet", :type => :boolean, :banner => "Only output warnings and errors."
method_option "frozen", :type => :boolean, :banner =>
"Do not allow the Gemfile.lock to be updated after this package operation's install"
"Do not allow the Gemfile.lock to be updated after this bundle cache operation's install"
long_desc <<-D
The package command will copy the .gem files for every gem in the bundle into the
The cache command will copy the .gem files for every gem in the bundle into the
directory ./vendor/cache. If you then check that directory into your source
control repository, others who check out your source will be able to install the
bundle without having to download any additional gems.
D
def package
require_relative "cli/package"
Package.new(options).run
def cache
require_relative "cli/cache"
Cache.new(options).run
end
map %w[cache pack] => :package

map aliases_for("cache")

desc "exec [OPTIONS]", "Run the command in context of the bundle"
method_option :keep_file_descriptors, :type => :boolean, :default => false
Expand All @@ -448,12 +471,13 @@ def package
bundle exec you can require and call the bundled gems as if they were installed
into the system wide RubyGems repository.
D
map "e" => "exec"
def exec(*args)
require_relative "cli/exec"
Exec.new(options, args).run
end

map aliases_for("exec")

desc "config NAME [VALUE]", "Retrieve or set a configuration value"
long_desc <<-D
Retrieves or sets a configuration value. If only one parameter is provided, retrieve the value. If two parameters are provided, replace the
Expand Down Expand Up @@ -496,7 +520,8 @@ def version
Bundler.ui.info "Bundler version #{Bundler::VERSION}#{build_info}"
end
end
map %w[-v --version] => :version

map aliases_for("version")

desc "licenses", "Prints the license of all gems in the bundle"
def licenses
Expand Down Expand Up @@ -680,12 +705,17 @@ def pristine(*gems)
# Reformat the arguments passed to bundle that include a --help flag
# into the corresponding `bundle help #{command}` call
def self.reformatted_help_args(args)
bundler_commands = all_commands.keys
bundler_commands = (COMMAND_ALIASES.keys + COMMAND_ALIASES.values).flatten

help_flags = %w[--help -h]
exec_commands = %w[e ex exe exec]
exec_commands = ["exec"] + COMMAND_ALIASES["exec"]

help_used = args.index {|a| help_flags.include? a }
exec_used = args.index {|a| exec_commands.include? a }

command = args.find {|a| bundler_commands.include? a }
command = all_aliases[command] if all_aliases[command]

if exec_used && help_used
if exec_used + help_used == 1
%w[help exec]
Expand Down Expand Up @@ -790,7 +820,7 @@ def remembered_flag_deprecation(name)

Bundler::SharedHelpers.major_deprecation 2,\
"The `#{flag_name}` flag is deprecated because it relies on being " \
"remembered across bundler invokations, which bundler will no longer " \
"remembered across bundler invocations, which bundler will no longer " \
"do in future versions. Instead please use `bundle config set #{name} " \
"'#{value}'`, and stop using this flag"
end
Expand Down

0 comments on commit 7585bc3

Please sign in to comment.