summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHiroshi SHIBATA <hsbt@ruby-lang.org>2022-12-13 11:24:14 +0900
committerHiroshi SHIBATA <hsbt@ruby-lang.org>2022-12-13 12:41:08 +0900
commit3e00cb8256cfe0640cb1d744d07d496128edb7e9 (patch)
tree0f6da75956922b2558815ef8a67a85a7d5dec4cc
parent6d00053c741cc7a369a1967e0631e32ddf3d1f82 (diff)
Merge RubyGems/Bundler master
from https://github.com/rubygems/rubygems/commit/1fdbeeabedd3cc4fffb0bb527b7c789afa44fb51
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/6914
-rw-r--r--lib/bundler/rubygems_gem_installer.rb6
-rw-r--r--lib/bundler/vendor/connection_pool/lib/connection_pool.rb4
-rw-r--r--lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb6
-rw-r--r--lib/bundler/vendor/connection_pool/lib/connection_pool/wrapper.rb1
-rw-r--r--lib/bundler/vendor/fileutils/lib/fileutils.rb1758
-rw-r--r--lib/bundler/vendor/uri/lib/uri.rb5
-rw-r--r--lib/bundler/vendor/uri/lib/uri/common.rb80
-rw-r--r--lib/bundler/vendor/uri/lib/uri/file.rb8
-rw-r--r--lib/bundler/vendor/uri/lib/uri/ftp.rb3
-rw-r--r--lib/bundler/vendor/uri/lib/uri/generic.rb34
-rw-r--r--lib/bundler/vendor/uri/lib/uri/http.rb42
-rw-r--r--lib/bundler/vendor/uri/lib/uri/https.rb3
-rw-r--r--lib/bundler/vendor/uri/lib/uri/ldap.rb2
-rw-r--r--lib/bundler/vendor/uri/lib/uri/ldaps.rb3
-rw-r--r--lib/bundler/vendor/uri/lib/uri/mailto.rb4
-rw-r--r--lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb20
-rw-r--r--lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb15
-rw-r--r--lib/bundler/vendor/uri/lib/uri/version.rb2
-rw-r--r--lib/bundler/vendor/uri/lib/uri/ws.rb3
-rw-r--r--lib/bundler/vendor/uri/lib/uri/wss.rb3
20 files changed, 1537 insertions, 465 deletions
diff --git a/lib/bundler/rubygems_gem_installer.rb b/lib/bundler/rubygems_gem_installer.rb
index 13c2d25882..38035a00ac 100644
--- a/lib/bundler/rubygems_gem_installer.rb
+++ b/lib/bundler/rubygems_gem_installer.rb
@@ -109,8 +109,10 @@ module Bundler
def strict_rm_rf(dir)
Bundler.rm_rf dir
- rescue Errno::ENOTEMPTY => e
- raise DirectoryRemovalError.new(e.cause, "Could not delete previous installation of `#{dir}`")
+ rescue StandardError => e
+ raise unless File.exist?(dir)
+
+ raise DirectoryRemovalError.new(e, "Could not delete previous installation of `#{dir}`")
end
def validate_bundler_checksum(checksum)
diff --git a/lib/bundler/vendor/connection_pool/lib/connection_pool.rb b/lib/bundler/vendor/connection_pool/lib/connection_pool.rb
index 984c1c3dcb..455319efe3 100644
--- a/lib/bundler/vendor/connection_pool/lib/connection_pool.rb
+++ b/lib/bundler/vendor/connection_pool/lib/connection_pool.rb
@@ -3,7 +3,9 @@ require_relative "connection_pool/version"
class Bundler::ConnectionPool
class Error < ::RuntimeError; end
+
class PoolShuttingDownError < ::Bundler::ConnectionPool::Error; end
+
class TimeoutError < ::Timeout::Error; end
end
@@ -67,7 +69,7 @@ class Bundler::ConnectionPool
end
end
end
- alias then with
+ alias_method :then, :with
def checkout(options = {})
if ::Thread.current[@key]
diff --git a/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb b/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb
index a7b1cf06a8..35d1d7cc35 100644
--- a/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb
+++ b/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb
@@ -49,7 +49,7 @@ class Bundler::ConnectionPool::TimedStack
@resource.broadcast
end
end
- alias << push
+ alias_method :<<, :push
##
# Retrieves a connection from the stack. If a connection is available it is
@@ -74,7 +74,7 @@ class Bundler::ConnectionPool::TimedStack
return connection if connection
to_wait = deadline - current_time
- raise Bundler::ConnectionPool::TimeoutError, "Waited #{timeout} sec" if to_wait <= 0
+ raise Bundler::ConnectionPool::TimeoutError, "Waited #{timeout} sec, #{length}/#{@max} available" if to_wait <= 0
@resource.wait(@mutex, to_wait)
end
end
@@ -87,7 +87,7 @@ class Bundler::ConnectionPool::TimedStack
# +:reload+ is +true+.
def shutdown(reload: false, &block)
- raise ArgumentError, "shutdown must receive a block" unless block_given?
+ raise ArgumentError, "shutdown must receive a block" unless block
@mutex.synchronize do
@shutdown_block = block
diff --git a/lib/bundler/vendor/connection_pool/lib/connection_pool/wrapper.rb b/lib/bundler/vendor/connection_pool/lib/connection_pool/wrapper.rb
index 880170c06b..dd796d1021 100644
--- a/lib/bundler/vendor/connection_pool/lib/connection_pool/wrapper.rb
+++ b/lib/bundler/vendor/connection_pool/lib/connection_pool/wrapper.rb
@@ -30,7 +30,6 @@ class Bundler::ConnectionPool
METHODS.include?(id) || with { |c| c.respond_to?(id, *args) }
end
- # rubocop:disable Style/MethodMissingSuper
# rubocop:disable Style/MissingRespondToMissing
if ::RUBY_VERSION >= "3.0.0"
def method_missing(name, *args, **kwargs, &block)
diff --git a/lib/bundler/vendor/fileutils/lib/fileutils.rb b/lib/bundler/vendor/fileutils/lib/fileutils.rb
index 8f8faf30c8..04ac537a28 100644
--- a/lib/bundler/vendor/fileutils/lib/fileutils.rb
+++ b/lib/bundler/vendor/fileutils/lib/fileutils.rb
@@ -6,103 +6,181 @@ rescue LoadError
# for make mjit-headers
end
+# Namespace for file utility methods for copying, moving, removing, etc.
#
-# = fileutils.rb
+# == What's Here
#
-# Copyright (c) 2000-2007 Minero Aoki
+# First, what’s elsewhere. \Module \Bundler::FileUtils:
#
-# This program is free software.
-# You can distribute/modify this program under the same terms of ruby.
+# - Inherits from {class Object}[rdoc-ref:Object].
+# - Supplements {class File}[rdoc-ref:File]
+# (but is not included or extended there).
#
-# == module Bundler::FileUtils
+# Here, module \Bundler::FileUtils provides methods that are useful for:
#
-# Namespace for several file utility methods for copying, moving, removing, etc.
+# - {Creating}[rdoc-ref:FileUtils@Creating].
+# - {Deleting}[rdoc-ref:FileUtils@Deleting].
+# - {Querying}[rdoc-ref:FileUtils@Querying].
+# - {Setting}[rdoc-ref:FileUtils@Setting].
+# - {Comparing}[rdoc-ref:FileUtils@Comparing].
+# - {Copying}[rdoc-ref:FileUtils@Copying].
+# - {Moving}[rdoc-ref:FileUtils@Moving].
+# - {Options}[rdoc-ref:FileUtils@Options].
#
-# === Module Functions
+# === Creating
#
-# require 'bundler/vendor/fileutils/lib/fileutils'
+# - ::mkdir: Creates directories.
+# - ::mkdir_p, ::makedirs, ::mkpath: Creates directories,
+# also creating ancestor directories as needed.
+# - ::link_entry: Creates a hard link.
+# - ::ln, ::link: Creates hard links.
+# - ::ln_s, ::symlink: Creates symbolic links.
+# - ::ln_sf: Creates symbolic links, overwriting if necessary.
+# - ::ln_sr: Creates symbolic links relative to targets
#
-# Bundler::FileUtils.cd(dir, **options)
-# Bundler::FileUtils.cd(dir, **options) {|dir| block }
-# Bundler::FileUtils.pwd()
-# Bundler::FileUtils.mkdir(dir, **options)
-# Bundler::FileUtils.mkdir(list, **options)
-# Bundler::FileUtils.mkdir_p(dir, **options)
-# Bundler::FileUtils.mkdir_p(list, **options)
-# Bundler::FileUtils.rmdir(dir, **options)
-# Bundler::FileUtils.rmdir(list, **options)
-# Bundler::FileUtils.ln(target, link, **options)
-# Bundler::FileUtils.ln(targets, dir, **options)
-# Bundler::FileUtils.ln_s(target, link, **options)
-# Bundler::FileUtils.ln_s(targets, dir, **options)
-# Bundler::FileUtils.ln_sf(target, link, **options)
-# Bundler::FileUtils.cp(src, dest, **options)
-# Bundler::FileUtils.cp(list, dir, **options)
-# Bundler::FileUtils.cp_r(src, dest, **options)
-# Bundler::FileUtils.cp_r(list, dir, **options)
-# Bundler::FileUtils.mv(src, dest, **options)
-# Bundler::FileUtils.mv(list, dir, **options)
-# Bundler::FileUtils.rm(list, **options)
-# Bundler::FileUtils.rm_r(list, **options)
-# Bundler::FileUtils.rm_rf(list, **options)
-# Bundler::FileUtils.install(src, dest, **options)
-# Bundler::FileUtils.chmod(mode, list, **options)
-# Bundler::FileUtils.chmod_R(mode, list, **options)
-# Bundler::FileUtils.chown(user, group, list, **options)
-# Bundler::FileUtils.chown_R(user, group, list, **options)
-# Bundler::FileUtils.touch(list, **options)
+# === Deleting
#
-# Possible <tt>options</tt> are:
+# - ::remove_dir: Removes a directory and its descendants.
+# - ::remove_entry: Removes an entry, including its descendants if it is a directory.
+# - ::remove_entry_secure: Like ::remove_entry, but removes securely.
+# - ::remove_file: Removes a file entry.
+# - ::rm, ::remove: Removes entries.
+# - ::rm_f, ::safe_unlink: Like ::rm, but removes forcibly.
+# - ::rm_r: Removes entries and their descendants.
+# - ::rm_rf, ::rmtree: Like ::rm_r, but removes forcibly.
+# - ::rmdir: Removes directories.
#
-# <tt>:force</tt> :: forced operation (rewrite files if exist, remove
-# directories if not empty, etc.);
-# <tt>:verbose</tt> :: print command to be run, in bash syntax, before
-# performing it;
-# <tt>:preserve</tt> :: preserve object's group, user and modification
-# time on copying;
-# <tt>:noop</tt> :: no changes are made (usable in combination with
-# <tt>:verbose</tt> which will print the command to run)
+# === Querying
#
-# Each method documents the options that it honours. See also ::commands,
-# ::options and ::options_of methods to introspect which command have which
-# options.
+# - ::pwd, ::getwd: Returns the path to the working directory.
+# - ::uptodate?: Returns whether a given entry is newer than given other entries.
#
-# All methods that have the concept of a "source" file or directory can take
-# either one file or a list of files in that argument. See the method
-# documentation for examples.
+# === Setting
#
-# There are some `low level' methods, which do not accept keyword arguments:
+# - ::cd, ::chdir: Sets the working directory.
+# - ::chmod: Sets permissions for an entry.
+# - ::chmod_R: Sets permissions for an entry and its descendants.
+# - ::chown: Sets the owner and group for entries.
+# - ::chown_R: Sets the owner and group for entries and their descendants.
+# - ::touch: Sets modification and access times for entries,
+# creating if necessary.
#
-# Bundler::FileUtils.copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false)
-# Bundler::FileUtils.copy_file(src, dest, preserve = false, dereference = true)
-# Bundler::FileUtils.copy_stream(srcstream, deststream)
-# Bundler::FileUtils.remove_entry(path, force = false)
-# Bundler::FileUtils.remove_entry_secure(path, force = false)
-# Bundler::FileUtils.remove_file(path, force = false)
-# Bundler::FileUtils.compare_file(path_a, path_b)
-# Bundler::FileUtils.compare_stream(stream_a, stream_b)
-# Bundler::FileUtils.uptodate?(file, cmp_list)
+# === Comparing
#
-# == module Bundler::FileUtils::Verbose
+# - ::compare_file, ::cmp, ::identical?: Returns whether two entries are identical.
+# - ::compare_stream: Returns whether two streams are identical.
#
-# This module has all methods of Bundler::FileUtils module, but it outputs messages
-# before acting. This equates to passing the <tt>:verbose</tt> flag to methods
-# in Bundler::FileUtils.
+# === Copying
#
-# == module Bundler::FileUtils::NoWrite
+# - ::copy_entry: Recursively copies an entry.
+# - ::copy_file: Copies an entry.
+# - ::copy_stream: Copies a stream.
+# - ::cp, ::copy: Copies files.
+# - ::cp_lr: Recursively creates hard links.
+# - ::cp_r: Recursively copies files, retaining mode, owner, and group.
+# - ::install: Recursively copies files, optionally setting mode,
+# owner, and group.
#
-# This module has all methods of Bundler::FileUtils module, but never changes
-# files/directories. This equates to passing the <tt>:noop</tt> flag to methods
-# in Bundler::FileUtils.
+# === Moving
#
-# == module Bundler::FileUtils::DryRun
+# - ::mv, ::move: Moves entries.
#
-# This module has all methods of Bundler::FileUtils module, but never changes
-# files/directories. This equates to passing the <tt>:noop</tt> and
-# <tt>:verbose</tt> flags to methods in Bundler::FileUtils.
+# === Options
+#
+# - ::collect_method: Returns the names of methods that accept a given option.
+# - ::commands: Returns the names of methods that accept options.
+# - ::have_option?: Returns whether a given method accepts a given option.
+# - ::options: Returns all option names.
+# - ::options_of: Returns the names of the options for a given method.
+#
+# == Path Arguments
+#
+# Some methods in \Bundler::FileUtils accept _path_ arguments,
+# which are interpreted as paths to filesystem entries:
+#
+# - If the argument is a string, that value is the path.
+# - If the argument has method +:to_path+, it is converted via that method.
+# - If the argument has method +:to_str+, it is converted via that method.
+#
+# == About the Examples
+#
+# Some examples here involve trees of file entries.
+# For these, we sometimes display trees using the
+# {tree command-line utility}[https://en.wikipedia.org/wiki/Tree_(command)],
+# which is a recursive directory-listing utility that produces
+# a depth-indented listing of files and directories.
+#
+# We use a helper method to launch the command and control the format:
+#
+# def tree(dirpath = '.')
+# command = "tree --noreport --charset=ascii #{dirpath}"
+# system(command)
+# end
+#
+# To illustrate:
+#
+# tree('src0')
+# # => src0
+# # |-- sub0
+# # | |-- src0.txt
+# # | `-- src1.txt
+# # `-- sub1
+# # |-- src2.txt
+# # `-- src3.txt
+#
+# == Avoiding the TOCTTOU Vulnerability
+#
+# For certain methods that recursively remove entries,
+# there is a potential vulnerability called the
+# {Time-of-check to time-of-use}[https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use],
+# or TOCTTOU, vulnerability that can exist when:
+#
+# - An ancestor directory of the entry at the target path is world writable;
+# such directories include <tt>/tmp</tt>.
+# - The directory tree at the target path includes:
+#
+# - A world-writable descendant directory.
+# - A symbolic link.
+#
+# To avoid that vulnerability, you can use this method to remove entries:
+#
+# - Bundler::FileUtils.remove_entry_secure: removes recursively
+# if the target path points to a directory.
+#
+# Also available are these methods,
+# each of which calls \Bundler::FileUtils.remove_entry_secure:
+#
+# - Bundler::FileUtils.rm_r with keyword argument <tt>secure: true</tt>.
+# - Bundler::FileUtils.rm_rf with keyword argument <tt>secure: true</tt>.
+#
+# Finally, this method for moving entries calls \Bundler::FileUtils.remove_entry_secure
+# if the source and destination are on different file systems
+# (which means that the "move" is really a copy and remove):
+#
+# - Bundler::FileUtils.mv with keyword argument <tt>secure: true</tt>.
+#
+# \Method \Bundler::FileUtils.remove_entry_secure removes securely
+# by applying a special pre-process:
+#
+# - If the target path points to a directory, this method uses methods
+# {File#chown}[rdoc-ref:File#chown]
+# and {File#chmod}[rdoc-ref:File#chmod]
+# in removing directories.
+# - The owner of the target directory should be either the current process
+# or the super user (root).
+#
+# WARNING: You must ensure that *ALL* parent directories cannot be
+# moved by other untrusted users. For example, parent directories
+# should not be owned by untrusted users, and should not be world
+# writable except when the sticky bit is set.
+#
+# For details of this security vulnerability, see Perl cases:
+#
+# - {CVE-2005-0448}[https://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0448].
+# - {CVE-2004-0452}[https://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0452].
#
module Bundler::FileUtils
- VERSION = "1.4.1"
+ VERSION = "1.7.0"
def self.private_module_function(name) #:nodoc:
module_function name
@@ -110,7 +188,13 @@ module Bundler::FileUtils
end
#
- # Returns the name of the current directory.
+ # Returns a string containing the path to the current directory:
+ #
+ # Bundler::FileUtils.pwd # => "/rdoc/fileutils"
+ #
+ # Bundler::FileUtils.getwd is an alias for Bundler::FileUtils.pwd.
+ #
+ # Related: Bundler::FileUtils.cd.
#
def pwd
Dir.pwd
@@ -120,19 +204,40 @@ module Bundler::FileUtils
alias getwd pwd
module_function :getwd
+ # Changes the working directory to the given +dir+, which
+ # should be {interpretable as a path}[rdoc-ref:FileUtils@Path+Arguments]:
+ #
+ # With no block given,
+ # changes the current directory to the directory at +dir+; returns zero:
+ #
+ # Bundler::FileUtils.pwd # => "/rdoc/fileutils"
+ # Bundler::FileUtils.cd('..')
+ # Bundler::FileUtils.pwd # => "/rdoc"
+ # Bundler::FileUtils.cd('fileutils')
+ #
+ # With a block given, changes the current directory to the directory
+ # at +dir+, calls the block with argument +dir+,
+ # and restores the original current directory; returns the block's value:
#
- # Changes the current directory to the directory +dir+.
+ # Bundler::FileUtils.pwd # => "/rdoc/fileutils"
+ # Bundler::FileUtils.cd('..') { |arg| [arg, Bundler::FileUtils.pwd] } # => ["..", "/rdoc"]
+ # Bundler::FileUtils.pwd # => "/rdoc/fileutils"
#
- # If this method is called with block, resumes to the previous
- # working directory after the block execution has finished.
+ # Keyword arguments:
#
- # Bundler::FileUtils.cd('/') # change directory
+ # - <tt>verbose: true</tt> - prints an equivalent command:
#
- # Bundler::FileUtils.cd('/', verbose: true) # change directory and report it
+ # Bundler::FileUtils.cd('..')
+ # Bundler::FileUtils.cd('fileutils')
#
- # Bundler::FileUtils.cd('/') do # change directory
- # # ... # do something
- # end # return to original directory
+ # Output:
+ #
+ # cd ..
+ # cd fileutils
+ #
+ # Bundler::FileUtils.chdir is an alias for Bundler::FileUtils.cd.
+ #
+ # Related: Bundler::FileUtils.pwd.
#
def cd(dir, verbose: nil, &block) # :yield: dir
fu_output_message "cd #{dir}" if verbose
@@ -146,11 +251,19 @@ module Bundler::FileUtils
module_function :chdir
#
- # Returns true if +new+ is newer than all +old_list+.
- # Non-existent files are older than any file.
+ # Returns +true+ if the file at path +new+
+ # is newer than all the files at paths in array +old_list+;
+ # +false+ otherwise.
+ #
+ # Argument +new+ and the elements of +old_list+
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments]:
#
- # Bundler::FileUtils.uptodate?('hello.o', %w(hello.c hello.h)) or \
- # system 'make hello.o'
+ # Bundler::FileUtils.uptodate?('Rakefile', ['Gemfile', 'README.md']) # => true
+ # Bundler::FileUtils.uptodate?('Gemfile', ['Rakefile', 'README.md']) # => false
+ #
+ # A non-existent file is considered to be infinitely old.
+ #
+ # Related: Bundler::FileUtils.touch.
#
def uptodate?(new, old_list)
return false unless File.exist?(new)
@@ -170,12 +283,39 @@ module Bundler::FileUtils
private_module_function :remove_trailing_slash
#
- # Creates one or more directories.
+ # Creates directories at the paths in the given +list+
+ # (a single path or an array of paths);
+ # returns +list+ if it is an array, <tt>[list]</tt> otherwise.
+ #
+ # Argument +list+ or its elements
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
+ #
+ # With no keyword arguments, creates a directory at each +path+ in +list+
+ # by calling: <tt>Dir.mkdir(path, mode)</tt>;
+ # see {Dir.mkdir}[rdoc-ref:Dir.mkdir]:
+ #
+ # Bundler::FileUtils.mkdir(%w[tmp0 tmp1]) # => ["tmp0", "tmp1"]
+ # Bundler::FileUtils.mkdir('tmp4') # => ["tmp4"]
+ #
+ # Keyword arguments:
+ #
+ # - <tt>mode: <i>mode</i></tt> - also calls <tt>File.chmod(mode, path)</tt>;
+ # see {File.chmod}[rdoc-ref:File.chmod].
+ # - <tt>noop: true</tt> - does not create directories.
+ # - <tt>verbose: true</tt> - prints an equivalent command:
+ #
+ # Bundler::FileUtils.mkdir(%w[tmp0 tmp1], verbose: true)
+ # Bundler::FileUtils.mkdir(%w[tmp2 tmp3], mode: 0700, verbose: true)
+ #
+ # Output:
#
- # Bundler::FileUtils.mkdir 'test'
- # Bundler::FileUtils.mkdir %w(tmp data)
- # Bundler::FileUtils.mkdir 'notexist', noop: true # Does not really create.
- # Bundler::FileUtils.mkdir 'tmp', mode: 0700
+ # mkdir tmp0 tmp1
+ # mkdir -m 700 tmp2 tmp3
+ #
+ # Raises an exception if any path points to an existing
+ # file or directory, or if for any reason a directory cannot be created.
+ #
+ # Related: Bundler::FileUtils.mkdir_p.
#
def mkdir(list, mode: nil, noop: nil, verbose: nil)
list = fu_list(list)
@@ -189,40 +329,56 @@ module Bundler::FileUtils
module_function :mkdir
#
- # Creates a directory and all its parent directories.
- # For example,
+ # Creates directories at the paths in the given +list+
+ # (a single path or an array of paths),
+ # also creating ancestor directories as needed;
+ # returns +list+ if it is an array, <tt>[list]</tt> otherwise.
+ #
+ # Argument +list+ or its elements
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
+ #
+ # With no keyword arguments, creates a directory at each +path+ in +list+,
+ # along with any needed ancestor directories,
+ # by calling: <tt>Dir.mkdir(path, mode)</tt>;
+ # see {Dir.mkdir}[rdoc-ref:Dir.mkdir]:
+ #
+ # Bundler::FileUtils.mkdir_p(%w[tmp0/tmp1 tmp2/tmp3]) # => ["tmp0/tmp1", "tmp2/tmp3"]
+ # Bundler::FileUtils.mkdir_p('tmp4/tmp5') # => ["tmp4/tmp5"]
+ #
+ # Keyword arguments:
+ #
+ # - <tt>mode: <i>mode</i></tt> - also calls <tt>File.chmod(mode, path)</tt>;
+ # see {File.chmod}[rdoc-ref:File.chmod].
+ # - <tt>noop: true</tt> - does not create directories.
+ # - <tt>verbose: true</tt> - prints an equivalent command:
+ #
+ # Bundler::FileUtils.mkdir_p(%w[tmp0 tmp1], verbose: true)
+ # Bundler::FileUtils.mkdir_p(%w[tmp2 tmp3], mode: 0700, verbose: true)
#
- # Bundler::FileUtils.mkdir_p '/usr/local/lib/ruby'
+ # Output:
#
- # causes to make following directories, if they do not exist.
+ # mkdir -p tmp0 tmp1
+ # mkdir -p -m 700 tmp2 tmp3
#
- # * /usr
- # * /usr/local
- # * /usr/local/lib
- # * /usr/local/lib/ruby
+ # Raises an exception if for any reason a directory cannot be created.
#
- # You can pass several directories at a time in a list.
+ # Bundler::FileUtils.mkpath and Bundler::FileUtils.makedirs are aliases for Bundler::FileUtils.mkdir_p.
+ #
+ # Related: Bundler::FileUtils.mkdir.
#
def mkdir_p(list, mode: nil, noop: nil, verbose: nil)
list = fu_list(list)
fu_output_message "mkdir -p #{mode ? ('-m %03o ' % mode) : ''}#{list.join ' '}" if verbose
return *list if noop
- list.map {|path| remove_trailing_slash(path)}.each do |path|
- # optimize for the most common case
- begin
- fu_mkdir path, mode
- next
- rescue SystemCallError
- next if File.directory?(path)
- end
+ list.each do |item|
+ path = remove_trailing_slash(item)
stack = []
- until path == stack.last # dirname("/")=="/", dirname("C:/")=="C:/"
+ until File.directory?(path) || File.dirname(path) == path
stack.push path
path = File.dirname(path)
end
- stack.pop # root directory should exist
stack.reverse_each do |dir|
begin
fu_mkdir dir, mode
@@ -253,12 +409,39 @@ module Bundler::FileUtils
private_module_function :fu_mkdir
#
- # Removes one or more directories.
+ # Removes directories at the paths in the given +list+
+ # (a single path or an array of paths);
+ # returns +list+, if it is an array, <tt>[list]</tt> otherwise.
+ #
+ # Argument +list+ or its elements
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
+ #
+ # With no keyword arguments, removes the directory at each +path+ in +list+,
+ # by calling: <tt>Dir.rmdir(path)</tt>;
+ # see {Dir.rmdir}[rdoc-ref:Dir.rmdir]:
+ #
+ # Bundler::FileUtils.rmdir(%w[tmp0/tmp1 tmp2/tmp3]) # => ["tmp0/tmp1", "tmp2/tmp3"]
+ # Bundler::FileUtils.rmdir('tmp4/tmp5') # => ["tmp4/tmp5"]
+ #
+ # Keyword arguments:
+ #
+ # - <tt>parents: true</tt> - removes successive ancestor directories
+ # if empty.
+ # - <tt>noop: true</tt> - does not remove directories.
+ # - <tt>verbose: true</tt> - prints an equivalent command:
#
- # Bundler::FileUtils.rmdir 'somedir'
- # Bundler::FileUtils.rmdir %w(somedir anydir otherdir)
- # # Does not really remove directory; outputs message.
- # Bundler::FileUtils.rmdir 'somedir', verbose: true, noop: true
+ # Bundler::FileUtils.rmdir(%w[tmp0/tmp1 tmp2/tmp3], parents: true, verbose: true)
+ # Bundler::FileUtils.rmdir('tmp4/tmp5', parents: true, verbose: true)
+ #
+ # Output:
+ #
+ # rmdir -p tmp0/tmp1 tmp2/tmp3
+ # rmdir -p tmp4/tmp5
+ #
+ # Raises an exception if a directory does not exist
+ # or if for any reason a directory cannot be removed.
+ #
+ # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
#
def rmdir(list, parents: nil, noop: nil, verbose: nil)
list = fu_list(list)
@@ -279,26 +462,62 @@ module Bundler::FileUtils
end
module_function :rmdir
+ # Creates {hard links}[https://en.wikipedia.org/wiki/Hard_link].
+ #
+ # Arguments +src+ (a single path or an array of paths)
+ # and +dest+ (a single path)
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
+ #
+ # When +src+ is the path to an existing file
+ # and +dest+ is the path to a non-existent file,
+ # creates a hard link at +dest+ pointing to +src+; returns zero:
+ #
+ # Dir.children('tmp0/') # => ["t.txt"]
+ # Dir.children('tmp1/') # => []
+ # Bundler::FileUtils.ln('tmp0/t.txt', 'tmp1/t.lnk') # => 0
+ # Dir.children('tmp1/') # => ["t.lnk"]
+ #
+ # When +src+ is the path to an existing file
+ # and +dest+ is the path to an existing directory,
+ # creates a hard link at <tt>dest/src</tt> pointing to +src+; returns zero:
#
- # :call-seq:
- # Bundler::FileUtils.ln(target, link, force: nil, noop: nil, verbose: nil)
- # Bundler::FileUtils.ln(target, dir, force: nil, noop: nil, verbose: nil)
- # Bundler::FileUtils.ln(targets, dir, force: nil, noop: nil, verbose: nil)
+ # Dir.children('tmp2') # => ["t.dat"]
+ # Dir.children('tmp3') # => []
+ # Bundler::FileUtils.ln('tmp2/t.dat', 'tmp3') # => 0
+ # Dir.children('tmp3') # => ["t.dat"]
#
- # In the first form, creates a hard link +link+ which points to +target+.
- # If +link+ already exists, raises Errno::EEXIST.
- # But if the +force+ option is set, overwrites +link+.
+ # When +src+ is an array of paths to existing files
+ # and +dest+ is the path to an existing directory,
+ # then for each path +target+ in +src+,
+ # creates a hard link at <tt>dest/target</tt> pointing to +target+;
+ # returns +src+:
#
- # Bundler::FileUtils.ln 'gcc', 'cc', verbose: true
- # Bundler::FileUtils.ln '/usr/bin/emacs21', '/usr/bin/emacs'
+ # Dir.children('tmp4/') # => []
+ # Bundler::FileUtils.ln(['tmp0/t.txt', 'tmp2/t.dat'], 'tmp4/') # => ["tmp0/t.txt", "tmp2/t.dat"]
+ # Dir.children('tmp4/') # => ["t.dat", "t.txt"]
#
- # In the second form, creates a link +dir/target+ pointing to +target+.
- # In the third form, creates several hard links in the directory +dir+,
- # pointing to each item in +targets+.
- # If +dir+ is not a directory, raises Errno::ENOTDIR.
+ # Keyword arguments:
#
- # Bundler::FileUtils.cd '/sbin'
- # Bundler::FileUtils.ln %w(cp mv mkdir), '/bin' # Now /sbin/cp and /bin/cp are linked.
+ # - <tt>force: true</tt> - overwrites +dest+ if it exists.
+ # - <tt>noop: true</tt> - does not create links.
+ # - <tt>verbose: true</tt> - prints an equivalent command:
+ #
+ # Bundler::FileUtils.ln('tmp0/t.txt', 'tmp1/t.lnk', verbose: true)
+ # Bundler::FileUtils.ln('tmp2/t.dat', 'tmp3', verbose: true)
+ # Bundler::FileUtils.ln(['tmp0/t.txt', 'tmp2/t.dat'], 'tmp4/', verbose: true)
+ #
+ # Output:
+ #
+ # ln tmp0/t.txt tmp1/t.lnk
+ # ln tmp2/t.dat tmp3
+ # ln tmp0/t.txt tmp2/t.dat tmp4/
+ #
+ # Raises an exception if +dest+ is the path to an existing file
+ # and keyword argument +force+ is not +true+.
+ #
+ # Bundler::FileUtils#link is an alias for Bundler::FileUtils#ln.
+ #
+ # Related: Bundler::FileUtils.link_entry (has different options).
#
def ln(src, dest, force: nil, noop: nil, verbose: nil)
fu_output_message "ln#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose
@@ -313,28 +532,103 @@ module Bundler::FileUtils
alias link ln
module_function :link
- #
- # Hard link +src+ to +dest+. If +src+ is a directory, this method links
- # all its contents recursively. If +dest+ is a directory, links
- # +src+ to +dest/src+.
- #
- # +src+ can be a list of files.
- #
- # If +dereference_root+ is true, this method dereference tree root.
- #
- # If +remove_destination+ is true, this method removes each destination file before copy.
- #
- # Bundler::FileUtils.rm_r site_ruby + '/mylib', force: true
- # Bundler::FileUtils.cp_lr 'lib/', site_ruby + '/mylib'
- #
- # # Examples of linking several files to target directory.
- # Bundler::FileUtils.cp_lr %w(mail.rb field.rb debug/), site_ruby + '/tmail'
- # Bundler::FileUtils.cp_lr Dir.glob('*.rb'), '/home/aamine/lib/ruby', noop: true, verbose: true
- #
- # # If you want to link all contents of a directory instead of the
- # # directory itself, c.f. src/x -> dest/x, src/y -> dest/y,
- # # use the following code.
- # Bundler::FileUtils.cp_lr 'src/.', 'dest' # cp_lr('src', 'dest') makes dest/src, but this doesn't.
+ # Creates {hard links}[https://en.wikipedia.org/wiki/Hard_link].
+ #
+ # Arguments +src+ (a single path or an array of paths)
+ # and +dest+ (a single path)
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
+ #
+ # If +src+ is the path to a directory and +dest+ does not exist,
+ # creates links +dest+ and descendents pointing to +src+ and its descendents:
+ #
+ # tree('src0')
+ # # => src0
+ # # |-- sub0
+ # # | |-- src0.txt
+ # # | `-- src1.txt
+ # # `-- sub1
+ # # |-- src2.txt
+ # # `-- src3.txt
+ # File.exist?('dest0') # => false
+ # Bundler::FileUtils.cp_lr('src0', 'dest0')
+ # tree('dest0')
+ # # => dest0
+ # # |-- sub0
+ # # | |-- src0.txt
+ # # | `-- src1.txt
+ # # `-- sub1
+ # # |-- src2.txt
+ # # `-- src3.txt
+ #
+ # If +src+ and +dest+ are both paths to directories,
+ # creates links <tt>dest/src</tt> and descendents
+ # pointing to +src+ and its descendents:
+ #
+ # tree('src1')
+ # # => src1
+ # # |-- sub0
+ # # | |-- src0.txt
+ # # | `-- src1.txt
+ # # `-- sub1
+ # # |-- src2.txt
+ # # `-- src3.txt
+ # Bundler::FileUtils.mkdir('dest1')
+ # Bundler::FileUtils.cp_lr('src1', 'dest1')
+ # tree('dest1')
+ # # => dest1
+ # # `-- src1
+ # # |-- sub0
+ # # | |-- src0.txt
+ # # | `-- src1.txt
+ # # `-- sub1
+ # # |-- src2.txt
+ # # `-- src3.txt
+ #
+ # If +src+ is an array of paths to entries and +dest+ is the path to a directory,
+ # for each path +filepath+ in +src+, creates a link at <tt>dest/filepath</tt>
+ # pointing to that path:
+ #
+ # tree('src2')
+ # # => src2
+ # # |-- sub0
+ # # | |-- src0.txt
+ # # | `-- src1.txt
+ # # `-- sub1
+ # # |-- src2.txt
+ # # `-- src3.txt
+ # Bundler::FileUtils.mkdir('dest2')
+ # Bundler::FileUtils.cp_lr(['src2/sub0', 'src2/sub1'], 'dest2')
+ # tree('dest2')
+ # # => dest2
+ # # |-- sub0
+ # # | |-- src0.txt
+ # # | `-- src1.txt
+ # # `-- sub1
+ # # |-- src2.txt
+ # # `-- src3.txt
+ #
+ # Keyword arguments:
+ #
+ # - <tt>dereference_root: false</tt> - if +src+ is a symbolic link,
+ # does not dereference it.
+ # - <tt>noop: true</tt> - does not create links.
+ # - <tt>remove_destination: true</tt> - removes +dest+ before creating links.
+ # - <tt>verbose: true</tt> - prints an equivalent command:
+ #
+ # Bundler::FileUtils.cp_lr('src0', 'dest0', noop: true, verbose: true)
+ # Bundler::FileUtils.cp_lr('src1', 'dest1', noop: true, verbose: true)
+ # Bundler::FileUtils.cp_lr(['src2/sub0', 'src2/sub1'], 'dest2', noop: true, verbose: true)
+ #
+ # Output:
+ #
+ # cp -lr src0 dest0
+ # cp -lr src1 dest1
+ # cp -lr src2/sub0 src2/sub1 dest2
+ #
+ # Raises an exception if +dest+ is the path to an existing file or directory
+ # and keyword argument <tt>remove_destination: true</tt> is not given.
+ #
+ # Related: {methods for copying}[rdoc-ref:FileUtils@Copying].
#
def cp_lr(src, dest, noop: nil, verbose: nil,
dereference_root: true, remove_destination: false)
@@ -346,27 +640,81 @@ module Bundler::FileUtils
end
module_function :cp_lr
+ # Creates {symbolic links}[https://en.wikipedia.org/wiki/Symbolic_link].
+ #
+ # Arguments +src+ (a single path or an array of paths)
+ # and +dest+ (a single path)
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
+ #
+ # If +src+ is the path to an existing file:
+ #
+ # - When +dest+ is the path to a non-existent file,
+ # creates a symbolic link at +dest+ pointing to +src+:
+ #
+ # Bundler::FileUtils.touch('src0.txt')
+ # File.exist?('dest0.txt') # => false
+ # Bundler::FileUtils.ln_s('src0.txt', 'dest0.txt')
+ # File.symlink?('dest0.txt') # => true
#
- # :call-seq:
- # Bundler::FileUtils.ln_s(target, link, force: nil, noop: nil, verbose: nil)
- # Bundler::FileUtils.ln_s(target, dir, force: nil, noop: nil, verbose: nil)
- # Bundler::FileUtils.ln_s(targets, dir, force: nil, noop: nil, verbose: nil)
+ # - When +dest+ is the path to an existing file,
+ # creates a symbolic link at +dest+ pointing to +src+
+ # if and only if keyword argument <tt>force: true</tt> is given
+ # (raises an exception otherwise):
#
- # In the first form, creates a symbolic link +link+ which points to +target+.
- # If +link+ already exists, raises Errno::EEXIST.
- # But if the <tt>force</tt> option is set, overwrites +link+.
+ # Bundler::FileUtils.touch('src1.txt')
+ # Bundler::FileUtils.touch('dest1.txt')
+ # Bundler::FileUtils.ln_s('src1.txt', 'dest1.txt', force: true)
+ # FileTest.symlink?('dest1.txt') # => true
#
- # Bundler::FileUtils.ln_s '/usr/bin/ruby', '/usr/local/bin/ruby'
- # Bundler::FileUtils.ln_s 'verylongsourcefilename.c', 'c', force: true
+ # Bundler::FileUtils.ln_s('src1.txt', 'dest1.txt') # Raises Errno::EEXIST.
#
- # In the second form, creates a link +dir/target+ pointing to +target+.
- # In the third form, creates several symbolic links in the directory +dir+,
- # pointing to each item in +targets+.
- # If +dir+ is not a directory, raises Errno::ENOTDIR.
+ # If +dest+ is the path to a directory,
+ # creates a symbolic link at <tt>dest/src</tt> pointing to +src+:
#
- # Bundler::FileUtils.ln_s Dir.glob('/bin/*.rb'), '/home/foo/bin'
+ # Bundler::FileUtils.touch('src2.txt')
+ # Bundler::FileUtils.mkdir('destdir2')
+ # Bundler::FileUtils.ln_s('src2.txt', 'destdir2')
+ # File.symlink?('destdir2/src2.txt') # => true
#
- def ln_s(src, dest, force: nil, noop: nil, verbose: nil)
+ # If +src+ is an array of paths to existing files and +dest+ is a directory,
+ # for each child +child+ in +src+ creates a symbolic link <tt>dest/child</tt>
+ # pointing to +child+:
+ #
+ # Bundler::FileUtils.mkdir('srcdir3')
+ # Bundler::FileUtils.touch('srcdir3/src0.txt')
+ # Bundler::FileUtils.touch('srcdir3/src1.txt')
+ # Bundler::FileUtils.mkdir('destdir3')
+ # Bundler::FileUtils.ln_s(['srcdir3/src0.txt', 'srcdir3/src1.txt'], 'destdir3')
+ # File.symlink?('destdir3/src0.txt') # => true
+ # File.symlink?('destdir3/src1.txt') # => true
+ #
+ # Keyword arguments:
+ #
+ # - <tt>force: true</tt> - overwrites +dest+ if it exists.
+ # - <tt>relative: false</tt> - create links relative to +dest+.
+ # - <tt>noop: true</tt> - does not create links.
+ # - <tt>verbose: true</tt> - prints an equivalent command:
+ #
+ # Bundler::FileUtils.ln_s('src0.txt', 'dest0.txt', noop: true, verbose: true)
+ # Bundler::FileUtils.ln_s('src1.txt', 'destdir1', noop: true, verbose: true)
+ # Bundler::FileUtils.ln_s('src2.txt', 'dest2.txt', force: true, noop: true, verbose: true)
+ # Bundler::FileUtils.ln_s(['srcdir3/src0.txt', 'srcdir3/src1.txt'], 'destdir3', noop: true, verbose: true)
+ #
+ # Output:
+ #
+ # ln -s src0.txt dest0.txt
+ # ln -s src1.txt destdir1
+ # ln -sf src2.txt dest2.txt
+ # ln -s srcdir3/src0.txt srcdir3/src1.txt destdir3
+ #
+ # Bundler::FileUtils.symlink is an alias for Bundler::FileUtils.ln_s.
+ #
+ # Related: Bundler::FileUtils.ln_sf.
+ #
+ def ln_s(src, dest, force: nil, relative: false, target_directory: true, noop: nil, verbose: nil)
+ if relative
+ return ln_sr(src, dest, force: force, noop: noop, verbose: verbose)
+ end
fu_output_message "ln -s#{force ? 'f' : ''} #{[src,dest].flatten.join ' '}" if verbose
return if noop
fu_each_src_dest0(src, dest) do |s,d|
@@ -379,29 +727,95 @@ module Bundler::FileUtils
alias symlink ln_s
module_function :symlink
- #
- # :call-seq:
- # Bundler::FileUtils.ln_sf(*args)
- #
- # Same as
- #
- # Bundler::FileUtils.ln_s(*args, force: true)
+ # Like Bundler::FileUtils.ln_s, but always with keyword argument <tt>force: true</tt> given.
#
def ln_sf(src, dest, noop: nil, verbose: nil)
ln_s src, dest, force: true, noop: noop, verbose: verbose
end
module_function :ln_sf
+ # Like Bundler::FileUtils.ln_s, but create links relative to +dest+.
+ #
+ def ln_sr(src, dest, target_directory: true, force: nil, noop: nil, verbose: nil)
+ options = "#{force ? 'f' : ''}#{target_directory ? '' : 'T'}"
+ dest = File.path(dest)
+ srcs = Array(src)
+ link = proc do |s, target_dir_p = true|
+ s = File.path(s)
+ if target_dir_p
+ d = File.join(destdirs = dest, File.basename(s))
+ else
+ destdirs = File.dirname(d = dest)
+ end
+ destdirs = fu_split_path(File.realpath(destdirs))
+ if fu_starting_path?(s)
+ srcdirs = fu_split_path((File.realdirpath(s) rescue File.expand_path(s)))
+ base = fu_relative_components_from(srcdirs, destdirs)
+ s = File.join(*base)
+ else
+ srcdirs = fu_clean_components(*fu_split_path(s))
+ base = fu_relative_components_from(fu_split_path(Dir.pwd), destdirs)
+ while srcdirs.first&. == ".." and base.last&.!=("..") and !fu_starting_path?(base.last)
+ srcdirs.shift
+ base.pop
+ end
+ s = File.join(*base, *srcdirs)
+ end
+ fu_output_message "ln -s#{options} #{s} #{d}" if verbose
+ next if noop
+ remove_file d, true if force
+ File.symlink s, d
+ end
+ case srcs.size
+ when 0
+ when 1
+ link[srcs[0], target_directory && File.directory?(dest)]
+ else
+ srcs.each(&link)
+ end
+ end
+ module_function :ln_sr
+
+ # Creates {hard links}[https://en.wikipedia.org/wiki/Hard_link]; returns +nil+.
#
- # Hard links a file system entry +src+ to +dest+.
- # If +src+ is a directory, this method links its contents recursively.
+ # Arguments +src+ and +dest+
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
#
- # Both of +src+ and +dest+ must be a path name.
- # +src+ must exist, +dest+ must not exist.
+ # If +src+ is the path to a file and +dest+ does not exist,
+ # creates a hard link at +dest+ pointing to +src+:
#
- # If +dereference_root+ is true, this method dereferences the tree root.
+ # Bundler::FileUtils.touch('src0.txt')
+ # File.exist?('dest0.txt') # => false
+ # Bundler::FileUtils.link_entry('src0.txt', 'dest0.txt')
+ # File.file?('dest0.txt') # => true
#
- # If +remove_destination+ is true, this method removes each destination file before copy.
+ # If +src+ is the path to a directory and +dest+ does not exist,
+ # recursively creates hard links at +dest+ pointing to paths in +src+:
+ #
+ # Bundler::FileUtils.mkdir_p(['src1/dir0', 'src1/dir1'])
+ # src_file_paths = [
+ # 'src1/dir0/t0.txt',
+ # 'src1/dir0/t1.txt',
+ # 'src1/dir1/t2.txt',
+ # 'src1/dir1/t3.txt',
+ # ]
+ # Bundler::FileUtils.touch(src_file_paths)
+ # File.directory?('dest1') # => true
+ # Bundler::FileUtils.link_entry('src1', 'dest1')
+ # File.file?('dest1/dir0/t0.txt') # => true
+ # File.file?('dest1/dir0/t1.txt') # => true
+ # File.file?('dest1/dir1/t2.txt') # => true
+ # File.file?('dest1/dir1/t3.txt') # => true
+ #
+ # Keyword arguments:
+ #
+ # - <tt>dereference_root: true</tt> - dereferences +src+ if it is a symbolic link.
+ # - <tt>remove_destination: true</tt> - removes +dest+ before creating links.
+ #
+ # Raises an exception if +dest+ is the path to an existing file or directory
+ # and keyword argument <tt>remove_destination: true</tt> is not given.
+ #
+ # Related: Bundler::FileUtils.ln (has different options).
#
def link_entry(src, dest, dereference_root = false, remove_destination = false)
Entry_.new(src, nil, dereference_root).traverse do |ent|
@@ -412,16 +826,59 @@ module Bundler::FileUtils
end
module_function :link_entry
+ # Copies files.
+ #
+ # Arguments +src+ (a single path or an array of paths)
+ # and +dest+ (a single path)
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
+ #
+ # If +src+ is the path to a file and +dest+ is not the path to a directory,
+ # copies +src+ to +dest+:
+ #
+ # Bundler::FileUtils.touch('src0.txt')
+ # File.exist?('dest0.txt') # => false
+ # Bundler::FileUtils.cp('src0.txt', 'dest0.txt')
+ # File.file?('dest0.txt') # => true
#
- # Copies a file content +src+ to +dest+. If +dest+ is a directory,
- # copies +src+ to +dest/src+.
+ # If +src+ is the path to a file and +dest+ is the path to a directory,
+ # copies +src+ to <tt>dest/src</tt>:
#
- # If +src+ is a list of files, then +dest+ must be a directory.
+ # Bundler::FileUtils.touch('src1.txt')
+ # Bundler::FileUtils.mkdir('dest1')
+ # Bundler::FileUtils.cp('src1.txt', 'dest1')
+ # File.file?('dest1/src1.txt') # => true
#
- # Bundler::FileUtils.cp 'eval.c', 'eval.c.org'
- # Bundler::FileUtils.cp %w(cgi.rb complex.rb date.rb), '/usr/lib/ruby/1.6'
- # Bundler::FileUtils.cp %w(cgi.rb complex.rb date.rb), '/usr/lib/ruby/1.6', verbose: true
- # Bundler::FileUtils.cp 'symlink', 'dest' # copy content, "dest" is not a symlink
+ # If +src+ is an array of paths to files and +dest+ is the path to a directory,
+ # copies from each +src+ to +dest+:
+ #
+ # src_file_paths = ['src2.txt', 'src2.dat']
+ # Bundler::FileUtils.touch(src_file_paths)
+ # Bundler::FileUtils.mkdir('dest2')
+ # Bundler::FileUtils.cp(src_file_paths, 'dest2')
+ # File.file?('dest2/src2.txt') # => true
+ # File.file?('dest2/src2.dat') # => true
+ #
+ # Keyword arguments:
+ #
+ # - <tt>preserve: true</tt> - preserves file times.
+ # - <tt>noop: true</tt> - does not copy files.
+ # - <tt>verbose: true</tt> - prints an equivalent command:
+ #
+ # Bundler::FileUtils.cp('src0.txt', 'dest0.txt', noop: true, verbose: true)
+ # Bundler::FileUtils.cp('src1.txt', 'dest1', noop: true, verbose: true)
+ # Bundler::FileUtils.cp(src_file_paths, 'dest2', noop: true, verbose: true)
+ #
+ # Output:
+ #
+ # cp src0.txt dest0.txt
+ # cp src1.txt dest1
+ # cp src2.txt src2.dat dest2
+ #
+ # Raises an exception if +src+ is a directory.
+ #
+ # Bundler::FileUtils.copy is an alias for Bundler::FileUtils.cp.
+ #
+ # Related: {methods for copying}[rdoc-ref:FileUtils@Copying].
#
def cp(src, dest, preserve: nil, noop: nil, verbose: nil)
fu_output_message "cp#{preserve ? ' -p' : ''} #{[src,dest].flatten.join ' '}" if verbose
@@ -435,30 +892,105 @@ module Bundler::FileUtils
alias copy cp
module_function :copy
- #
- # Copies +src+ to +dest+. If +src+ is a directory, this method copies
- # all its contents recursively. If +dest+ is a directory, copies
- # +src+ to +dest/src+.
- #
- # +src+ can be a list of files.
- #
- # If +dereference_root+ is true, this method dereference tree root.
- #
- # If +remove_destination+ is true, this method removes each destination file before copy.
- #
- # # Installing Ruby library "mylib" under the site_ruby
- # Bundler::FileUtils.rm_r site_ruby + '/mylib', force: true
- # Bundler::FileUtils.cp_r 'lib/', site_ruby + '/mylib'
- #
- # # Examples of copying several files to target directory.
- # Bundler::FileUtils.cp_r %w(mail.rb field.rb debug/), site_ruby + '/tmail'
- # Bundler::FileUtils.cp_r Dir.glob('*.rb'), '/home/foo/lib/ruby', noop: true, verbose: true
- #
- # # If you want to copy all contents of a directory instead of the
- # # directory itself, c.f. src/x -> dest/x, src/y -> dest/y,
- # # use following code.
- # Bundler::FileUtils.cp_r 'src/.', 'dest' # cp_r('src', 'dest') makes dest/src,
- # # but this doesn't.
+ # Recursively copies files.
+ #
+ # Arguments +src+ (a single path or an array of paths)
+ # and +dest+ (a single path)
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
+ #
+ # The mode, owner, and group are retained in the copy;
+ # to change those, use Bundler::FileUtils.install instead.
+ #
+ # If +src+ is the path to a file and +dest+ is not the path to a directory,
+ # copies +src+ to +dest+:
+ #
+ # Bundler::FileUtils.touch('src0.txt')
+ # File.exist?('dest0.txt') # => false
+ # Bundler::FileUtils.cp_r('src0.txt', 'dest0.txt')
+ # File.file?('dest0.txt') # => true
+ #
+ # If +src+ is the path to a file and +dest+ is the path to a directory,
+ # copies +src+ to <tt>dest/src</tt>:
+ #
+ # Bundler::FileUtils.touch('src1.txt')
+ # Bundler::FileUtils.mkdir('dest1')
+ # Bundler::FileUtils.cp_r('src1.txt', 'dest1')
+ # File.file?('dest1/src1.txt') # => true
+ #
+ # If +src+ is the path to a directory and +dest+ does not exist,
+ # recursively copies +src+ to +dest+:
+ #
+ # tree('src2')
+ # # => src2
+ # # |-- dir0
+ # # | |-- src0.txt
+ # # | `-- src1.txt
+ # # `-- dir1
+ # # |-- src2.txt
+ # # `-- src3.txt
+ # Bundler::FileUtils.exist?('dest2') # => false
+ # Bundler::FileUtils.cp_r('src2', 'dest2')
+ # tree('dest2')
+ # # => dest2
+ # # |-- dir0
+ # # | |-- src0.txt
+ # # | `-- src1.txt
+ # # `-- dir1
+ # # |-- src2.txt
+ # # `-- src3.txt
+ #
+ # If +src+ and +dest+ are paths to directories,
+ # recursively copies +src+ to <tt>dest/src</tt>:
+ #
+ # tree('src3')
+ # # => src3
+ # # |-- dir0
+ # # | |-- src0.txt
+ # # | `-- src1.txt
+ # # `-- dir1
+ # # |-- src2.txt
+ # # `-- src3.txt
+ # Bundler::FileUtils.mkdir('dest3')
+ # Bundler::FileUtils.cp_r('src3', 'dest3')
+ # tree('dest3')
+ # # => dest3
+ # # `-- src3
+ # # |-- dir0
+ # # | |-- src0.txt
+ # # | `-- src1.txt
+ # # `-- dir1
+ # # |-- src2.txt
+ # # `-- src3.txt
+ #
+ # If +src+ is an array of paths and +dest+ is a directory,
+ # recursively copies from each path in +src+ to +dest+;
+ # the paths in +src+ may point to files and/or directories.
+ #
+ # Keyword arguments:
+ #
+ # - <tt>dereference_root: false</tt> - if +src+ is a symbolic link,
+ # does not dereference it.
+ # - <tt>noop: true</tt> - does not copy files.
+ # - <tt>preserve: true</tt> - preserves file times.
+ # - <tt>remove_destination: true</tt> - removes +dest+ before copying files.
+ # - <tt>verbose: true</tt> - prints an equivalent command:
+ #
+ # Bundler::FileUtils.cp_r('src0.txt', 'dest0.txt', noop: true, verbose: true)
+ # Bundler::FileUtils.cp_r('src1.txt', 'dest1', noop: true, verbose: true)
+ # Bundler::FileUtils.cp_r('src2', 'dest2', noop: true, verbose: true)
+ # Bundler::FileUtils.cp_r('src3', 'dest3', noop: true, verbose: true)
+ #
+ # Output:
+ #
+ # cp -r src0.txt dest0.txt
+ # cp -r src1.txt dest1
+ # cp -r src2 dest2
+ # cp -r src3 dest3
+ #
+ # Raises an exception of +src+ is the path to a directory
+ # and +dest+ is the path to a file.
+ #
+ # Related: {methods for copying}[rdoc-ref:FileUtils@Copying].
#
def cp_r(src, dest, preserve: nil, noop: nil, verbose: nil,
dereference_root: true, remove_destination: nil)
@@ -470,21 +1002,50 @@ module Bundler::FileUtils
end
module_function :cp_r
+ # Recursively copies files from +src+ to +dest+.
+ #
+ # Arguments +src+ and +dest+
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
#
- # Copies a file system entry +src+ to +dest+.
- # If +src+ is a directory, this method copies its contents recursively.
- # This method preserves file types, c.f. symlink, directory...
- # (FIFO, device files and etc. are not supported yet)
+ # If +src+ is the path to a file, copies +src+ to +dest+:
#
- # Both of +src+ and +dest+ must be a path name.
- # +src+ must exist, +dest+ must not exist.
+ # Bundler::FileUtils.touch('src0.txt')
+ # File.exist?('dest0.txt') # => false
+ # Bundler::FileUtils.copy_entry('src0.txt', 'dest0.txt')
+ # File.file?('dest0.txt') # => true
#
- # If +preserve+ is true, this method preserves owner, group, and
- # modified time. Permissions are copied regardless +preserve+.
+ # If +src+ is a directory, recursively copies +src+ to +dest+:
#
- # If +dereference_root+ is true, this method dereference tree root.
+ # tree('src1')
+ # # => src1
+ # # |-- dir0
+ # # | |-- src0.txt
+ # # | `-- src1.txt
+ # # `-- dir1
+ # # |-- src2.txt
+ # # `-- src3.txt
+ # Bundler::FileUtils.copy_entry('src1', 'dest1')
+ # tree('dest1')
+ # # => dest1
+ # # |-- dir0
+ # # | |-- src0.txt
+ # # | `-- src1.txt
+ # # `-- dir1
+ # # |-- src2.txt
+ # # `-- src3.txt
#
- # If +remove_destination+ is true, this method removes each destination file before copy.
+ # The recursive copying preserves file types for regular files,
+ # directories, and symbolic links;
+ # other file types (FIFO streams, device files, etc.) are not supported.
+ #
+ # Keyword arguments:
+ #
+ # - <tt>dereference_root: true</tt> - if +src+ is a symbolic link,
+ # follows the link.
+ # - <tt>preserve: true</tt> - preserves file times.
+ # - <tt>remove_destination: true</tt> - removes +dest+ before copying files.
+ #
+ # Related: {methods for copying}[rdoc-ref:FileUtils@Copying].
#
def copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false)
if dereference_root
@@ -502,9 +1063,25 @@ module Bundler::FileUtils
end
module_function :copy_entry
+ # Copies file from +src+ to +dest+, which should not be directories.
+ #
+ # Arguments +src+ and +dest+
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
+ #
+ # Examples:
#
- # Copies file contents of +src+ to +dest+.
- # Both of +src+ and +dest+ must be a path name.
+ # Bundler::FileUtils.touch('src0.txt')
+ # Bundler::FileUtils.copy_file('src0.txt', 'dest0.txt')
+ # File.file?('dest0.txt') # => true
+ #
+ # Keyword arguments:
+ #
+ # - <tt>dereference: false</tt> - if +src+ is a symbolic link,
+ # does not follow the link.
+ # - <tt>preserve: true</tt> - preserves file times.
+ # - <tt>remove_destination: true</tt> - removes +dest+ before copying files.
+ #
+ # Related: {methods for copying}[rdoc-ref:FileUtils@Copying].
#
def copy_file(src, dest, preserve = false, dereference = true)
ent = Entry_.new(src, nil, dereference)
@@ -513,25 +1090,81 @@ module Bundler::FileUtils
end
module_function :copy_file
+ # Copies \IO stream +src+ to \IO stream +dest+ via
+ # {IO.copy_stream}[rdoc-ref:IO.copy_stream].
#
- # Copies stream +src+ to +dest+.
- # +src+ must respond to #read(n) and
- # +dest+ must respond to #write(str).
+ # Related: {methods for copying}[rdoc-ref:FileUtils@Copying].
#
def copy_stream(src, dest)
IO.copy_stream(src, dest)
end
module_function :copy_stream
- #
- # Moves file(s) +src+ to +dest+. If +file+ and +dest+ exist on the different
- # disk partition, the file is copied then the original file is removed.
- #
- # Bundler::FileUtils.mv 'badname.rb', 'goodname.rb'
- # Bundler::FileUtils.mv 'stuff.rb', '/notexist/lib/ruby', force: true # no error
- #
- # Bundler::FileUtils.mv %w(junk.txt dust.txt), '/home/foo/.trash/'
- # Bundler::FileUtils.mv Dir.glob('test*.rb'), 'test', noop: true, verbose: true
+ # Moves entries.
+ #
+ # Arguments +src+ (a single path or an array of paths)
+ # and +dest+ (a single path)
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
+ #
+ # If +src+ and +dest+ are on different file systems,
+ # first copies, then removes +src+.
+ #
+ # May cause a local vulnerability if not called with keyword argument
+ # <tt>secure: true</tt>;
+ # see {Avoiding the TOCTTOU Vulnerability}[rdoc-ref:FileUtils@Avoiding+the+TOCTTOU+Vulnerability].
+ #
+ # If +src+ is the path to a single file or directory and +dest+ does not exist,
+ # moves +src+ to +dest+:
+ #
+ # tree('src0')
+ # # => src0
+ # # |-- src0.txt
+ # # `-- src1.txt
+ # File.exist?('dest0') # => false
+ # Bundler::FileUtils.mv('src0', 'dest0')
+ # File.exist?('src0') # => false
+ # tree('dest0')
+ # # => dest0
+ # # |-- src0.txt
+ # # `-- src1.txt
+ #
+ # If +src+ is an array of paths to files and directories
+ # and +dest+ is the path to a directory,
+ # copies from each path in the array to +dest+:
+ #
+ # File.file?('src1.txt') # => true
+ # tree('src1')
+ # # => src1
+ # # |-- src.dat
+ # # `-- src.txt
+ # Dir.empty?('dest1') # => true
+ # Bundler::FileUtils.mv(['src1.txt', 'src1'], 'dest1')
+ # tree('dest1')
+ # # => dest1
+ # # |-- src1
+ # # | |-- src.dat
+ # # | `-- src.txt
+ # # `-- src1.txt
+ #
+ # Keyword arguments:
+ #
+ # - <tt>force: true</tt> - if the move includes removing +src+
+ # (that is, if +src+ and +dest+ are on different file systems),
+ # ignores raised exceptions of StandardError and its descendants.
+ # - <tt>noop: true</tt> - does not move files.
+ # - <tt>secure: true</tt> - removes +src+ securely;
+ # see details at Bundler::FileUtils.remove_entry_secure.
+ # - <tt>verbose: true</tt> - prints an equivalent command:
+ #
+ # Bundler::FileUtils.mv('src0', 'dest0', noop: true, verbose: true)
+ # Bundler::FileUtils.mv(['src1.txt', 'src1'], 'dest1', noop: true, verbose: true)
+ #
+ # Output:
+ #
+ # mv src0 dest0
+ # mv src1.txt src1 dest1
+ #
+ # Bundler::FileUtils.move is an alias for Bundler::FileUtils.mv.
#
def mv(src, dest, force: nil, noop: nil, verbose: nil, secure: nil)
fu_output_message "mv#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose
@@ -565,13 +1198,34 @@ module Bundler::FileUtils
alias move mv
module_function :move
+ # Removes entries at the paths in the given +list+
+ # (a single path or an array of paths)
+ # returns +list+, if it is an array, <tt>[list]</tt> otherwise.
+ #
+ # Argument +list+ or its elements
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
+ #
+ # With no keyword arguments, removes files at the paths given in +list+:
+ #
+ # Bundler::FileUtils.touch(['src0.txt', 'src0.dat'])
+ # Bundler::FileUtils.rm(['src0.dat', 'src0.txt']) # => ["src0.dat", "src0.txt"]
+ #
+ # Keyword arguments:
+ #
+ # - <tt>force: true</tt> - ignores raised exceptions of StandardError
+ # and its descendants.
+ # - <tt>noop: true</tt> - does not remove files; returns +nil+.
+ # - <tt>verbose: true</tt> - prints an equivalent command:
+ #
+ # Bundler::FileUtils.rm(['src0.dat', 'src0.txt'], noop: true, verbose: true)
#
- # Remove file(s) specified in +list+. This method cannot remove directories.
- # All StandardErrors are ignored when the :force option is set.
+ # Output:
#
- # Bundler::FileUtils.rm %w( junk.txt dust.txt )
- # Bundler::FileUtils.rm Dir.glob('*.so')
- # Bundler::FileUtils.rm 'NotExistFile', force: true # never raises exception
+ # rm src0.dat src0.txt
+ #
+ # Bundler::FileUtils.remove is an alias for Bundler::FileUtils.rm.
+ #
+ # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
#
def rm(list, force: nil, noop: nil, verbose: nil)
list = fu_list(list)
@@ -587,10 +1241,18 @@ module Bundler::FileUtils
alias remove rm
module_function :remove
+ # Equivalent to:
+ #
+ # Bundler::FileUtils.rm(list, force: true, **kwargs)
+ #
+ # Argument +list+ (a single path or an array of paths)
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
+ #
+ # See Bundler::FileUtils.rm for keyword arguments.
#
- # Equivalent to
+ # Bundler::FileUtils.safe_unlink is an alias for Bundler::FileUtils.rm_f.
#
- # Bundler::FileUtils.rm(list, force: true)
+ # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
#
def rm_f(list, noop: nil, verbose: nil)
rm list, force: true, noop: noop, verbose: verbose
@@ -600,24 +1262,55 @@ module Bundler::FileUtils
alias safe_unlink rm_f
module_function :safe_unlink
+ # Removes entries at the paths in the given +list+
+ # (a single path or an array of paths);
+ # returns +list+, if it is an array, <tt>[list]</tt> otherwise.
+ #
+ # Argument +list+ or its elements
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
+ #
+ # May cause a local vulnerability if not called with keyword argument
+ # <tt>secure: true</tt>;
+ # see {Avoiding the TOCTTOU Vulnerability}[rdoc-ref:FileUtils@Avoiding+the+TOCTTOU+Vulnerability].
+ #
+ # For each file path, removes the file at that path:
+ #
+ # Bundler::FileUtils.touch(['src0.txt', 'src0.dat'])
+ # Bundler::FileUtils.rm_r(['src0.dat', 'src0.txt'])
+ # File.exist?('src0.txt') # => false
+ # File.exist?('src0.dat') # => false
#
- # remove files +list+[0] +list+[1]... If +list+[n] is a directory,
- # removes its all contents recursively. This method ignores
- # StandardError when :force option is set.
+ # For each directory path, recursively removes files and directories:
#
- # Bundler::FileUtils.rm_r Dir.glob('/tmp/*')
- # Bundler::FileUtils.rm_r 'some_dir', force: true
+ # tree('src1')
+ # # => src1
+ # # |-- dir0
+ # # | |-- src0.txt
+ # # | `-- src1.txt
+ # # `-- dir1
+ # # |-- src2.txt
+ # # `-- src3.txt
+ # Bundler::FileUtils.rm_r('src1')
+ # File.exist?('src1') # => false
#
- # WARNING: This method causes local vulnerability
- # if one of parent directories or removing directory tree are world
- # writable (including /tmp, whose permission is 1777), and the current
- # process has strong privilege such as Unix super user (root), and the
- # system has symbolic link. For secure removing, read the documentation
- # of remove_entry_secure carefully, and set :secure option to true.
- # Default is <tt>secure: false</tt>.
+ # Keyword arguments:
#
- # NOTE: This method calls remove_entry_secure if :secure option is set.
- # See also remove_entry_secure.
+ # - <tt>force: true</tt> - ignores raised exceptions of StandardError
+ # and its descendants.
+ # - <tt>noop: true</tt> - does not remove entries; returns +nil+.
+ # - <tt>secure: true</tt> - removes +src+ securely;
+ # see details at Bundler::FileUtils.remove_entry_secure.
+ # - <tt>verbose: true</tt> - prints an equivalent command:
+ #
+ # Bundler::FileUtils.rm_r(['src0.dat', 'src0.txt'], noop: true, verbose: true)
+ # Bundler::FileUtils.rm_r('src1', noop: true, verbose: true)
+ #
+ # Output:
+ #
+ # rm -r src0.dat src0.txt
+ # rm -r src1
+ #
+ # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
#
def rm_r(list, force: nil, noop: nil, verbose: nil, secure: nil)
list = fu_list(list)
@@ -633,13 +1326,22 @@ module Bundler::FileUtils
end
module_function :rm_r
+ # Equivalent to:
#
- # Equivalent to
+ # Bundler::FileUtils.rm_r(list, force: true, **kwargs)
#
- # Bundler::FileUtils.rm_r(list, force: true)
+ # Argument +list+ or its elements
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
#
- # WARNING: This method causes local vulnerability.
- # Read the documentation of rm_r first.
+ # May cause a local vulnerability if not called with keyword argument
+ # <tt>secure: true</tt>;
+ # see {Avoiding the TOCTTOU Vulnerability}[rdoc-ref:FileUtils@Avoiding+the+TOCTTOU+Vulnerability].
+ #
+ # See Bundler::FileUtils.rm_r for keyword arguments.
+ #
+ # Bundler::FileUtils.rmtree is an alias for Bundler::FileUtils.rm_rf.
+ #
+ # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
#
def rm_rf(list, noop: nil, verbose: nil, secure: nil)
rm_r list, force: true, noop: noop, verbose: verbose, secure: secure
@@ -649,37 +1351,20 @@ module Bundler::FileUtils
alias rmtree rm_rf
module_function :rmtree
+ # Securely removes the entry given by +path+,
+ # which should be the entry for a regular file, a symbolic link,
+ # or a directory.
#
- # This method removes a file system entry +path+. +path+ shall be a
- # regular file, a directory, or something. If +path+ is a directory,
- # remove it recursively. This method is required to avoid TOCTTOU
- # (time-of-check-to-time-of-use) local security vulnerability of rm_r.
- # #rm_r causes security hole when:
- #
- # * Parent directory is world writable (including /tmp).
- # * Removing directory tree includes world writable directory.
- # * The system has symbolic link.
+ # Argument +path+
+ # should be {interpretable as a path}[rdoc-ref:FileUtils@Path+Arguments].
#
- # To avoid this security hole, this method applies special preprocess.
- # If +path+ is a directory, this method chown(2) and chmod(2) all
- # removing directories. This requires the current process is the
- # owner of the removing whole directory tree, or is the super user (root).
+ # Avoids a local vulnerability that can exist in certain circumstances;
+ # see {Avoiding the TOCTTOU Vulnerability}[rdoc-ref:FileUtils@Avoiding+the+TOCTTOU+Vulnerability].
#
- # WARNING: You must ensure that *ALL* parent directories cannot be
- # moved by other untrusted users. For example, parent directories
- # should not be owned by untrusted users, and should not be world
- # writable except when the sticky bit set.
+ # Optional argument +force+ specifies whether to ignore
+ # raised exceptions of StandardError and its descendants.
#
- # WARNING: Only the owner of the removing directory tree, or Unix super
- # user (root) should invoke this method. Otherwise this method does not
- # work.
- #
- # For details of this security vulnerability, see Perl's case:
- #
- # * https://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0448
- # * https://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0452
- #
- # For fileutils.rb, this vulnerability is reported in [ruby-dev:26100].
+ # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
#
def remove_entry_secure(path, force = false)
unless fu_have_symlink?
@@ -767,12 +1452,17 @@ module Bundler::FileUtils
end
private_module_function :fu_stat_identical_entry?
+ # Removes the entry given by +path+,
+ # which should be the entry for a regular file, a symbolic link,
+ # or a directory.
#
- # This method removes a file system entry +path+.
- # +path+ might be a regular file, a directory, or something.
- # If +path+ is a directory, remove it recursively.
+ # Argument +path+
+ # should be {interpretable as a path}[rdoc-ref:FileUtils@Path+Arguments].
#
- # See also remove_entry_secure.
+ # Optional argument +force+ specifies whether to ignore
+ # raised exceptions of StandardError and its descendants.
+ #
+ # Related: Bundler::FileUtils.remove_entry_secure.
#
def remove_entry(path, force = false)
Entry_.new(path).postorder_traverse do |ent|
@@ -787,9 +1477,16 @@ module Bundler::FileUtils
end
module_function :remove_entry
+ # Removes the file entry given by +path+,
+ # which should be the entry for a regular file or a symbolic link.
+ #
+ # Argument +path+
+ # should be {interpretable as a path}[rdoc-ref:FileUtils@Path+Arguments].
#
- # Removes a file +path+.
- # This method ignores StandardError if +force+ is true.
+ # Optional argument +force+ specifies whether to ignore
+ # raised exceptions of StandardError and its descendants.
+ #
+ # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
#
def remove_file(path, force = false)
Entry_.new(path).remove_file
@@ -798,20 +1495,32 @@ module Bundler::FileUtils
end
module_function :remove_file
+ # Recursively removes the directory entry given by +path+,
+ # which should be the entry for a regular file, a symbolic link,
+ # or a directory.
+ #
+ # Argument +path+
+ # should be {interpretable as a path}[rdoc-ref:FileUtils@Path+Arguments].
#
- # Removes a directory +dir+ and its contents recursively.
- # This method ignores StandardError if +force+ is true.
+ # Optional argument +force+ specifies whether to ignore
+ # raised exceptions of StandardError and its descendants.
+ #
+ # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
#
def remove_dir(path, force = false)
remove_entry path, force # FIXME?? check if it is a directory
end
module_function :remove_dir
+ # Returns +true+ if the contents of files +a+ and +b+ are identical,
+ # +false+ otherwise.
+ #
+ # Arguments +a+ and +b+
+ # should be {interpretable as a path}[rdoc-ref:FileUtils@Path+Arguments].
#
- # Returns true if the contents of a file +a+ and a file +b+ are identical.
+ # Bundler::FileUtils.identical? and Bundler::FileUtils.cmp are aliases for Bundler::FileUtils.compare_file.
#
- # Bundler::FileUtils.compare_file('somefile', 'somefile') #=> true
- # Bundler::FileUtils.compare_file('/dev/null', '/dev/urandom') #=> false
+ # Related: Bundler::FileUtils.compare_stream.
#
def compare_file(a, b)
return false unless File.size(a) == File.size(b)
@@ -828,19 +1537,19 @@ module Bundler::FileUtils
module_function :identical?
module_function :cmp
+ # Returns +true+ if the contents of streams +a+ and +b+ are identical,
+ # +false+ otherwise.
#
- # Returns true if the contents of a stream +a+ and +b+ are identical.
+ # Arguments +a+ and +b+
+ # should be {interpretable as a path}[rdoc-ref:FileUtils@Path+Arguments].
+ #
+ # Related: Bundler::FileUtils.compare_file.
#
def compare_stream(a, b)
bsize = fu_stream_blksize(a, b)
- if RUBY_VERSION > "2.4"
- sa = String.new(capacity: bsize)
- sb = String.new(capacity: bsize)
- else
- sa = String.new
- sb = String.new
- end
+ sa = String.new(capacity: bsize)
+ sb = String.new(capacity: bsize)
begin
a.read(bsize, sa)
@@ -851,13 +1560,69 @@ module Bundler::FileUtils
end
module_function :compare_stream
+ # Copies a file entry.
+ # See {install(1)}[https://man7.org/linux/man-pages/man1/install.1.html].
+ #
+ # Arguments +src+ (a single path or an array of paths)
+ # and +dest+ (a single path)
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments];
+ #
+ # If the entry at +dest+ does not exist, copies from +src+ to +dest+:
+ #
+ # File.read('src0.txt') # => "aaa\n"
+ # File.exist?('dest0.txt') # => false
+ # Bundler::FileUtils.install('src0.txt', 'dest0.txt')
+ # File.read('dest0.txt') # => "aaa\n"
+ #
+ # If +dest+ is a file entry, copies from +src+ to +dest+, overwriting:
+ #
+ # File.read('src1.txt') # => "aaa\n"
+ # File.read('dest1.txt') # => "bbb\n"
+ # Bundler::FileUtils.install('src1.txt', 'dest1.txt')
+ # File.read('dest1.txt') # => "aaa\n"
#
- # If +src+ is not same as +dest+, copies it and changes the permission
- # mode to +mode+. If +dest+ is a directory, destination is +dest+/+src+.
- # This method removes destination before copy.
+ # If +dest+ is a directory entry, copies from +src+ to <tt>dest/src</tt>,
+ # overwriting if necessary:
#
- # Bundler::FileUtils.install 'ruby', '/usr/local/bin/ruby', mode: 0755, verbose: true
- # Bundler::FileUtils.install 'lib.rb', '/usr/local/lib/ruby/site_ruby', verbose: true
+ # File.read('src2.txt') # => "aaa\n"
+ # File.read('dest2/src2.txt') # => "bbb\n"
+ # Bundler::FileUtils.install('src2.txt', 'dest2')
+ # File.read('dest2/src2.txt') # => "aaa\n"
+ #
+ # If +src+ is an array of paths and +dest+ points to a directory,
+ # copies each path +path+ in +src+ to <tt>dest/path</tt>:
+ #
+ # File.file?('src3.txt') # => true
+ # File.file?('src3.dat') # => true
+ # Bundler::FileUtils.mkdir('dest3')
+ # Bundler::FileUtils.install(['src3.txt', 'src3.dat'], 'dest3')
+ # File.file?('dest3/src3.txt') # => true
+ # File.file?('dest3/src3.dat') # => true
+ #
+ # Keyword arguments:
+ #
+ # - <tt>group: <i>group</i></tt> - changes the group if not +nil+,
+ # using {File.chown}[rdoc-ref:File.chown].
+ # - <tt>mode: <i>permissions</i></tt> - changes the permissions.
+ # using {File.chmod}[rdoc-ref:File.chmod].
+ # - <tt>noop: true</tt> - does not copy entries; returns +nil+.
+ # - <tt>owner: <i>owner</i></tt> - changes the owner if not +nil+,
+ # using {File.chown}[rdoc-ref:File.chown].
+ # - <tt>preserve: true</tt> - preserve timestamps
+ # using {File.utime}[rdoc-ref:File.utime].
+ # - <tt>verbose: true</tt> - prints an equivalent command:
+ #
+ # Bundler::FileUtils.install('src0.txt', 'dest0.txt', noop: true, verbose: true)
+ # Bundler::FileUtils.install('src1.txt', 'dest1.txt', noop: true, verbose: true)
+ # Bundler::FileUtils.install('src2.txt', 'dest2', noop: true, verbose: true)
+ #
+ # Output:
+ #
+ # install -c src0.txt dest0.txt
+ # install -c src1.txt dest1.txt
+ # install -c src2.txt dest2
+ #
+ # Related: {methods for copying}[rdoc-ref:FileUtils@Copying].
#
def install(src, dest, mode: nil, owner: nil, group: nil, preserve: nil,
noop: nil, verbose: nil)
@@ -917,11 +1682,8 @@ module Bundler::FileUtils
private_module_function :apply_mask
def symbolic_modes_to_i(mode_sym, path) #:nodoc:
- mode = if File::Stat === path
- path.mode
- else
- File.stat(path).mode
- end
+ path = File.stat(path) unless File::Stat === path
+ mode = path.mode
mode_sym.split(/,/).inject(mode & 07777) do |current_mode, clause|
target, *actions = clause.split(/([=+-])/)
raise ArgumentError, "invalid file mode: #{mode_sym}" if actions.empty?
@@ -938,7 +1700,7 @@ module Bundler::FileUtils
when "x"
mask | 0111
when "X"
- if FileTest.directory? path
+ if path.directory?
mask | 0111
else
mask
@@ -978,37 +1740,78 @@ module Bundler::FileUtils
end
private_module_function :mode_to_s
+ # Changes permissions on the entries at the paths given in +list+
+ # (a single path or an array of paths)
+ # to the permissions given by +mode+;
+ # returns +list+ if it is an array, <tt>[list]</tt> otherwise:
+ #
+ # - Modifies each entry that is a regular file using
+ # {File.chmod}[rdoc-ref:File.chmod].
+ # - Modifies each entry that is a symbolic link using
+ # {File.lchmod}[rdoc-ref:File.lchmod].
+ #
+ # Argument +list+ or its elements
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
+ #
+ # Argument +mode+ may be either an integer or a string:
+ #
+ # - \Integer +mode+: represents the permission bits to be set:
+ #
+ # Bundler::FileUtils.chmod(0755, 'src0.txt')
+ # Bundler::FileUtils.chmod(0644, ['src0.txt', 'src0.dat'])
+ #
+ # - \String +mode+: represents the permissions to be set:
+ #
+ # The string is of the form <tt>[targets][[operator][perms[,perms]]</tt>, where:
+ #
+ # - +targets+ may be any combination of these letters:
+ #
+ # - <tt>'u'</tt>: permissions apply to the file's owner.
+ # - <tt>'g'</tt>: permissions apply to users in the file's group.
+ # - <tt>'o'</tt>: permissions apply to other users not in the file's group.
+ # - <tt>'a'</tt> (the default): permissions apply to all users.
+ #
+ # - +operator+ may be one of these letters:
+ #
+ # - <tt>'+'</tt>: adds permissions.
+ # - <tt>'-'</tt>: removes permissions.
+ # - <tt>'='</tt>: sets (replaces) permissions.
+ #
+ # - +perms+ (may be repeated, with separating commas)
+ # may be any combination of these letters:
+ #
+ # - <tt>'r'</tt>: Read.
+ # - <tt>'w'</tt>: Write.
+ # - <tt>'x'</tt>: Execute (search, for a directory).
+ # - <tt>'X'</tt>: Search (for a directories only;
+ # must be used with <tt>'+'</tt>)
+ # - <tt>'s'</tt>: Uid or gid.
+ # - <tt>'t'</tt>: Sticky bit.
+ #
+ # Examples:
+ #
+ # Bundler::FileUtils.chmod('u=wrx,go=rx', 'src1.txt')
+ # Bundler::FileUtils.chmod('u=wrx,go=rx', '/usr/bin/ruby')
+ #
+ # Keyword arguments:
+ #
+ # - <tt>noop: true</tt> - does not change permissions; returns +nil+.
+ # - <tt>verbose: true</tt> - prints an equivalent command:
+ #
+ # Bundler::FileUtils.chmod(0755, 'src0.txt', noop: true, verbose: true)
+ # Bundler::FileUtils.chmod(0644, ['src0.txt', 'src0.dat'], noop: true, verbose: true)
+ # Bundler::FileUtils.chmod('u=wrx,go=rx', 'src1.txt', noop: true, verbose: true)
+ # Bundler::FileUtils.chmod('u=wrx,go=rx', '/usr/bin/ruby', noop: true, verbose: true)
+ #
+ # Output:
+ #
+ # chmod 755 src0.txt
+ # chmod 644 src0.txt src0.dat
+ # chmod u=wrx,go=rx src1.txt
+ # chmod u=wrx,go=rx /usr/bin/ruby
+ #
+ # Related: Bundler::FileUtils.chmod_R.
#
- # Changes permission bits on the named files (in +list+) to the bit pattern
- # represented by +mode+.
- #
- # +mode+ is the symbolic and absolute mode can be used.
- #
- # Absolute mode is
- # Bundler::FileUtils.chmod 0755, 'somecommand'
- # Bundler::FileUtils.chmod 0644, %w(my.rb your.rb his.rb her.rb)
- # Bundler::FileUtils.chmod 0755, '/usr/bin/ruby', verbose: true
- #
- # Symbolic mode is
- # Bundler::FileUtils.chmod "u=wrx,go=rx", 'somecommand'
- # Bundler::FileUtils.chmod "u=wr,go=rr", %w(my.rb your.rb his.rb her.rb)
- # Bundler::FileUtils.chmod "u=wrx,go=rx", '/usr/bin/ruby', verbose: true
- #
- # "a" :: is user, group, other mask.
- # "u" :: is user's mask.
- # "g" :: is group's mask.
- # "o" :: is other's mask.
- # "w" :: is write permission.
- # "r" :: is read permission.
- # "x" :: is execute permission.
- # "X" ::
- # is execute permission for directories only, must be used in conjunction with "+"
- # "s" :: is uid, gid.
- # "t" :: is sticky bit.
- # "+" :: is added to a class given the specified mode.
- # "-" :: Is removed from a given class given mode.
- # "=" :: Is the exact nature of the class will be given a specified mode.
-
def chmod(mode, list, noop: nil, verbose: nil)
list = fu_list(list)
fu_output_message sprintf('chmod %s %s', mode_to_s(mode), list.join(' ')) if verbose
@@ -1019,12 +1822,7 @@ module Bundler::FileUtils
end
module_function :chmod
- #
- # Changes permission bits on the named files (in +list+)
- # to the bit pattern represented by +mode+.
- #
- # Bundler::FileUtils.chmod_R 0700, "/tmp/app.#{$$}"
- # Bundler::FileUtils.chmod_R "u=wrx", "/tmp/app.#{$$}"
+ # Like Bundler::FileUtils.chmod, but changes permissions recursively.
#
def chmod_R(mode, list, noop: nil, verbose: nil, force: nil)
list = fu_list(list)
@@ -1044,15 +1842,68 @@ module Bundler::FileUtils
end
module_function :chmod_R
+ # Changes the owner and group on the entries at the paths given in +list+
+ # (a single path or an array of paths)
+ # to the given +user+ and +group+;
+ # returns +list+ if it is an array, <tt>[list]</tt> otherwise:
+ #
+ # - Modifies each entry that is a regular file using
+ # {File.chown}[rdoc-ref:File.chown].
+ # - Modifies each entry that is a symbolic link using
+ # {File.lchown}[rdoc-ref:File.lchown].
+ #
+ # Argument +list+ or its elements
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
#
- # Changes owner and group on the named files (in +list+)
- # to the user +user+ and the group +group+. +user+ and +group+
- # may be an ID (Integer/String) or a name (String).
- # If +user+ or +group+ is nil, this method does not change
- # the attribute.
+ # User and group:
#
- # Bundler::FileUtils.chown 'root', 'staff', '/usr/local/bin/ruby'
- # Bundler::FileUtils.chown nil, 'bin', Dir.glob('/usr/bin/*'), verbose: true
+ # - Argument +user+ may be a user name or a user id;
+ # if +nil+ or +-1+, the user is not changed.
+ # - Argument +group+ may be a group name or a group id;
+ # if +nil+ or +-1+, the group is not changed.
+ # - The user must be a member of the group.
+ #
+ # Examples:
+ #
+ # # One path.
+ # # User and group as string names.
+ # File.stat('src0.txt').uid # => 1004
+ # File.stat('src0.txt').gid # => 1004
+ # Bundler::FileUtils.chown('user2', 'group1', 'src0.txt')
+ # File.stat('src0.txt').uid # => 1006
+ # File.stat('src0.txt').gid # => 1005
+ #
+ # # User and group as uid and gid.
+ # Bundler::FileUtils.chown(1004, 1004, 'src0.txt')
+ # File.stat('src0.txt').uid # => 1004
+ # File.stat('src0.txt').gid # => 1004
+ #
+ # # Array of paths.
+ # Bundler::FileUtils.chown(1006, 1005, ['src0.txt', 'src0.dat'])
+ #
+ # # Directory (not recursive).
+ # Bundler::FileUtils.chown('user2', 'group1', '.')
+ #
+ # Keyword arguments:
+ #
+ # - <tt>noop: true</tt> - does not change permissions; returns +nil+.
+ # - <tt>verbose: true</tt> - prints an equivalent command:
+ #
+ # Bundler::FileUtils.chown('user2', 'group1', 'src0.txt', noop: true, verbose: true)
+ # Bundler::FileUtils.chown(1004, 1004, 'src0.txt', noop: true, verbose: true)
+ # Bundler::FileUtils.chown(1006, 1005, ['src0.txt', 'src0.dat'], noop: true, verbose: true)
+ # Bundler::FileUtils.chown('user2', 'group1', path, noop: true, verbose: true)
+ # Bundler::FileUtils.chown('user2', 'group1', '.', noop: true, verbose: true)
+ #
+ # Output:
+ #
+ # chown user2:group1 src0.txt
+ # chown 1004:1004 src0.txt
+ # chown 1006:1005 src0.txt src0.dat
+ # chown user2:group1 src0.txt
+ # chown user2:group1 .
+ #
+ # Related: Bundler::FileUtils.chown_R.
#
def chown(user, group, list, noop: nil, verbose: nil)
list = fu_list(list)
@@ -1068,15 +1919,7 @@ module Bundler::FileUtils
end
module_function :chown
- #
- # Changes owner and group on the named files (in +list+)
- # to the user +user+ and the group +group+ recursively.
- # +user+ and +group+ may be an ID (Integer/String) or
- # a name (String). If +user+ or +group+ is nil, this
- # method does not change the attribute.
- #
- # Bundler::FileUtils.chown_R 'www', 'www', '/var/www/htdocs'
- # Bundler::FileUtils.chown_R 'cvs', 'cvs', '/var/cvs', verbose: true
+ # Like Bundler::FileUtils.chown, but changes owner and group recursively.
#
def chown_R(user, group, list, noop: nil, verbose: nil, force: nil)
list = fu_list(list)
@@ -1127,12 +1970,50 @@ module Bundler::FileUtils
end
private_module_function :fu_get_gid
+ # Updates modification times (mtime) and access times (atime)
+ # of the entries given by the paths in +list+
+ # (a single path or an array of paths);
+ # returns +list+ if it is an array, <tt>[list]</tt> otherwise.
+ #
+ # By default, creates an empty file for any path to a non-existent entry;
+ # use keyword argument +nocreate+ to raise an exception instead.
+ #
+ # Argument +list+ or its elements
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
+ #
+ # Examples:
+ #
+ # # Single path.
+ # f = File.new('src0.txt') # Existing file.
+ # f.atime # => 2022-06-10 11:11:21.200277 -0700
+ # f.mtime # => 2022-06-10 11:11:21.200277 -0700
+ # Bundler::FileUtils.touch('src0.txt')
+ # f = File.new('src0.txt')
+ # f.atime # => 2022-06-11 08:28:09.8185343 -0700
+ # f.mtime # => 2022-06-11 08:28:09.8185343 -0700
#
- # Updates modification time (mtime) and access time (atime) of file(s) in
- # +list+. Files are created if they don't exist.
+ # # Array of paths.
+ # Bundler::FileUtils.touch(['src0.txt', 'src0.dat'])
#
- # Bundler::FileUtils.touch 'timestamp'
- # Bundler::FileUtils.touch Dir.glob('*.c'); system 'make'
+ # Keyword arguments:
+ #
+ # - <tt>mtime: <i>time</i></tt> - sets the entry's mtime to the given time,
+ # instead of the current time.
+ # - <tt>nocreate: true</tt> - raises an exception if the entry does not exist.
+ # - <tt>noop: true</tt> - does not touch entries; returns +nil+.
+ # - <tt>verbose: true</tt> - prints an equivalent command:
+ #
+ # Bundler::FileUtils.touch('src0.txt', noop: true, verbose: true)
+ # Bundler::FileUtils.touch(['src0.txt', 'src0.dat'], noop: true, verbose: true)
+ # Bundler::FileUtils.touch(path, noop: true, verbose: true)
+ #
+ # Output:
+ #
+ # touch src0.txt
+ # touch src0.txt src0.dat
+ # touch src0.txt
+ #
+ # Related: Bundler::FileUtils.uptodate?.
#
def touch(list, noop: nil, verbose: nil, mtime: nil, nocreate: nil)
list = fu_list(list)
@@ -1290,14 +2171,9 @@ module Bundler::FileUtils
def entries
opts = {}
- opts[:encoding] = ::Encoding::UTF_8 if fu_windows?
+ opts[:encoding] = fu_windows? ? ::Encoding::UTF_8 : path.encoding
- files = if Dir.respond_to?(:children)
- Dir.children(path, **opts)
- else
- Dir.entries(path(), **opts)
- .reject {|n| n == '.' or n == '..' }
- end
+ files = Dir.children(path, **opts)
untaint = RUBY_VERSION < '2.7'
files.map {|n| Entry_.new(prefix(), join(rel(), untaint ? n.untaint : n)) }
@@ -1345,6 +2221,7 @@ module Bundler::FileUtils
else
File.chmod mode, path()
end
+ rescue Errno::EOPNOTSUPP
end
def chown(uid, gid)
@@ -1439,7 +2316,7 @@ module Bundler::FileUtils
if st.symlink?
begin
File.lchmod mode, path
- rescue NotImplementedError
+ rescue NotImplementedError, Errno::EOPNOTSUPP
end
else
File.chmod mode, path
@@ -1498,13 +2375,21 @@ module Bundler::FileUtils
def postorder_traverse
if directory?
- entries().each do |ent|
+ begin
+ children = entries()
+ rescue Errno::EACCES
+ # Failed to get the list of children.
+ # Assuming there is no children, try to process the parent directory.
+ yield self
+ return
+ end
+
+ children.each do |ent|
ent.postorder_traverse do |e|
yield e
end
end
end
- ensure
yield self
end
@@ -1559,7 +2444,15 @@ module Bundler::FileUtils
def join(dir, base)
return File.path(dir) if not base or base == '.'
return File.path(base) if not dir or dir == '.'
- File.join(dir, base)
+ begin
+ File.join(dir, base)
+ rescue EncodingError
+ if fu_windows?
+ File.join(dir.encode(::Encoding::UTF_8), base.encode(::Encoding::UTF_8))
+ else
+ raise
+ end
+ end
end
if File::ALT_SEPARATOR
@@ -1590,15 +2483,15 @@ module Bundler::FileUtils
end
private_module_function :fu_each_src_dest
- def fu_each_src_dest0(src, dest) #:nodoc:
+ def fu_each_src_dest0(src, dest, target_directory = true) #:nodoc:
if tmp = Array.try_convert(src)
tmp.each do |s|
s = File.path(s)
- yield s, File.join(dest, File.basename(s))
+ yield s, (target_directory ? File.join(dest, File.basename(s)) : dest)
end
else
src = File.path(src)
- if File.directory?(dest)
+ if target_directory and File.directory?(dest)
yield src, File.join(dest, File.basename(src))
else
yield src, File.path(dest)
@@ -1614,7 +2507,7 @@ module Bundler::FileUtils
def fu_output_message(msg) #:nodoc:
output = @fileutils_output if defined?(@fileutils_output)
- output ||= $stderr
+ output ||= $stdout
if defined?(@fileutils_label)
msg = @fileutils_label + msg
end
@@ -1622,6 +2515,56 @@ module Bundler::FileUtils
end
private_module_function :fu_output_message
+ def fu_split_path(path)
+ path = File.path(path)
+ list = []
+ until (parent, base = File.split(path); parent == path or parent == ".")
+ list << base
+ path = parent
+ end
+ list << path
+ list.reverse!
+ end
+ private_module_function :fu_split_path
+
+ def fu_relative_components_from(target, base) #:nodoc:
+ i = 0
+ while target[i]&.== base[i]
+ i += 1
+ end
+ Array.new(base.size-i, '..').concat(target[i..-1])
+ end
+ private_module_function :fu_relative_components_from
+
+ def fu_clean_components(*comp)
+ comp.shift while comp.first == "."
+ return comp if comp.empty?
+ clean = [comp.shift]
+ path = File.join(*clean, "") # ending with File::SEPARATOR
+ while c = comp.shift
+ if c == ".." and clean.last != ".." and !(fu_have_symlink? && File.symlink?(path))
+ clean.pop
+ path.chomp!(%r((?<=\A|/)[^/]+/\z), "")
+ else
+ clean << c
+ path << c << "/"
+ end
+ end
+ clean
+ end
+ private_module_function :fu_clean_components
+
+ if fu_windows?
+ def fu_starting_path?(path)
+ path&.start_with?(%r(\w:|/))
+ end
+ else
+ def fu_starting_path?(path)
+ path&.start_with?("/")
+ end
+ end
+ private_module_function :fu_starting_path?
+
# This hash table holds command options.
OPT_TABLE = {} #:nodoc: internal use only
(private_instance_methods & methods(false)).inject(OPT_TABLE) {|tbl, name|
@@ -1631,50 +2574,49 @@ module Bundler::FileUtils
public
+ # Returns an array of the string names of \Bundler::FileUtils methods
+ # that accept one or more keyword arguments:
#
- # Returns an Array of names of high-level methods that accept any keyword
- # arguments.
- #
- # p Bundler::FileUtils.commands #=> ["chmod", "cp", "cp_r", "install", ...]
+ # Bundler::FileUtils.commands.sort.take(3) # => ["cd", "chdir", "chmod"]
#
def self.commands
OPT_TABLE.keys
end
+ # Returns an array of the string keyword names:
#
- # Returns an Array of option names.
- #
- # p Bundler::FileUtils.options #=> ["noop", "force", "verbose", "preserve", "mode"]
+ # Bundler::FileUtils.options.take(3) # => ["noop", "verbose", "force"]
#
def self.options
OPT_TABLE.values.flatten.uniq.map {|sym| sym.to_s }
end
+ # Returns +true+ if method +mid+ accepts the given option +opt+, +false+ otherwise;
+ # the arguments may be strings or symbols:
#
- # Returns true if the method +mid+ have an option +opt+.
- #
- # p Bundler::FileUtils.have_option?(:cp, :noop) #=> true
- # p Bundler::FileUtils.have_option?(:rm, :force) #=> true
- # p Bundler::FileUtils.have_option?(:rm, :preserve) #=> false
+ # Bundler::FileUtils.have_option?(:chmod, :noop) # => true
+ # Bundler::FileUtils.have_option?('chmod', 'secure') # => false
#
def self.have_option?(mid, opt)
li = OPT_TABLE[mid.to_s] or raise ArgumentError, "no such method: #{mid}"
li.include?(opt)
end
+ # Returns an array of the string keyword name for method +mid+;
+ # the argument may be a string or a symbol:
#
- # Returns an Array of option names of the method +mid+.
- #
- # p Bundler::FileUtils.options_of(:rm) #=> ["noop", "verbose", "force"]
+ # Bundler::FileUtils.options_of(:rm) # => ["force", "noop", "verbose"]
+ # Bundler::FileUtils.options_of('mv') # => ["force", "noop", "verbose", "secure"]
#
def self.options_of(mid)
OPT_TABLE[mid.to_s].map {|sym| sym.to_s }
end
+ # Returns an array of the string method names of the methods
+ # that accept the given keyword option +opt+;
+ # the argument must be a symbol:
#
- # Returns an Array of methods names which have the option +opt+.
- #
- # p Bundler::FileUtils.collect_method(:preserve) #=> ["cp", "cp_r", "copy", "install"]
+ # Bundler::FileUtils.collect_method(:preserve) # => ["cp", "copy", "cp_r", "install"]
#
def self.collect_method(opt)
OPT_TABLE.keys.select {|m| OPT_TABLE[m].include?(opt) }
diff --git a/lib/bundler/vendor/uri/lib/uri.rb b/lib/bundler/vendor/uri/lib/uri.rb
index 0e574dd2b1..976320f6bd 100644
--- a/lib/bundler/vendor/uri/lib/uri.rb
+++ b/lib/bundler/vendor/uri/lib/uri.rb
@@ -30,7 +30,7 @@
# class RSYNC < Generic
# DEFAULT_PORT = 873
# end
-# @@schemes['RSYNC'] = RSYNC
+# register_scheme 'RSYNC', RSYNC
# end
# #=> Bundler::URI::RSYNC
#
@@ -70,7 +70,6 @@
# - Bundler::URI::REGEXP - (in uri/common.rb)
# - Bundler::URI::REGEXP::PATTERN - (in uri/common.rb)
# - Bundler::URI::Util - (in uri/common.rb)
-# - Bundler::URI::Escape - (in uri/common.rb)
# - Bundler::URI::Error - (in uri/common.rb)
# - Bundler::URI::InvalidURIError - (in uri/common.rb)
# - Bundler::URI::InvalidComponentError - (in uri/common.rb)
@@ -101,3 +100,5 @@ require_relative 'uri/https'
require_relative 'uri/ldap'
require_relative 'uri/ldaps'
require_relative 'uri/mailto'
+require_relative 'uri/ws'
+require_relative 'uri/wss'
diff --git a/lib/bundler/vendor/uri/lib/uri/common.rb b/lib/bundler/vendor/uri/lib/uri/common.rb
index 6539e1810f..914a4c7581 100644
--- a/lib/bundler/vendor/uri/lib/uri/common.rb
+++ b/lib/bundler/vendor/uri/lib/uri/common.rb
@@ -13,9 +13,12 @@ require_relative "rfc2396_parser"
require_relative "rfc3986_parser"
module Bundler::URI
+ include RFC2396_REGEXP
+
REGEXP = RFC2396_REGEXP
Parser = RFC2396_Parser
RFC3986_PARSER = RFC3986_Parser.new
+ Ractor.make_shareable(RFC3986_PARSER) if defined?(Ractor)
# Bundler::URI::Parser.new
DEFAULT_PARSER = Parser.new
@@ -27,6 +30,7 @@ module Bundler::URI
DEFAULT_PARSER.regexp.each_pair do |sym, str|
const_set(sym, str)
end
+ Ractor.make_shareable(DEFAULT_PARSER) if defined?(Ractor)
module Util # :nodoc:
def make_components_hash(klass, array_hash)
@@ -60,24 +64,42 @@ module Bundler::URI
module_function :make_components_hash
end
- include REGEXP
+ module Schemes
+ end
+ private_constant :Schemes
+
+ #
+ # Register the given +klass+ to be instantiated when parsing URLs with the given +scheme+.
+ # Note that currently only schemes which after .upcase are valid constant names
+ # can be registered (no -/+/. allowed).
+ #
+ def self.register_scheme(scheme, klass)
+ Schemes.const_set(scheme.to_s.upcase, klass)
+ end
- @@schemes = {}
# Returns a Hash of the defined schemes.
def self.scheme_list
- @@schemes
+ Schemes.constants.map { |name|
+ [name.to_s.upcase, Schemes.const_get(name)]
+ }.to_h
end
+ INITIAL_SCHEMES = scheme_list
+ private_constant :INITIAL_SCHEMES
+ Ractor.make_shareable(INITIAL_SCHEMES) if defined?(Ractor)
+
#
# Construct a Bundler::URI instance, using the scheme to detect the appropriate class
# from +Bundler::URI.scheme_list+.
#
def self.for(scheme, *arguments, default: Generic)
- if scheme
- uri_class = @@schemes[scheme.upcase] || default
- else
- uri_class = default
+ const_name = scheme.to_s.upcase
+
+ uri_class = INITIAL_SCHEMES[const_name]
+ uri_class ||= if /\A[A-Z]\w*\z/.match?(const_name) && Schemes.const_defined?(const_name, false)
+ Schemes.const_get(const_name, false)
end
+ uri_class ||= default
return uri_class.new(scheme, *arguments)
end
@@ -278,6 +300,7 @@ module Bundler::URI
256.times do |i|
TBLENCWWWCOMP_[-i.chr] = -('%%%02X' % i)
end
+ TBLENCURICOMP_ = TBLENCWWWCOMP_.dup.freeze
TBLENCWWWCOMP_[' '] = '+'
TBLENCWWWCOMP_.freeze
TBLDECWWWCOMP_ = {} # :nodoc:
@@ -303,6 +326,33 @@ module Bundler::URI
#
# See Bundler::URI.decode_www_form_component, Bundler::URI.encode_www_form.
def self.encode_www_form_component(str, enc=nil)
+ _encode_uri_component(/[^*\-.0-9A-Z_a-z]/, TBLENCWWWCOMP_, str, enc)
+ end
+
+ # Decodes given +str+ of URL-encoded form data.
+ #
+ # This decodes + to SP.
+ #
+ # See Bundler::URI.encode_www_form_component, Bundler::URI.decode_www_form.
+ def self.decode_www_form_component(str, enc=Encoding::UTF_8)
+ _decode_uri_component(/\+|%\h\h/, str, enc)
+ end
+
+ # Encodes +str+ using URL encoding
+ #
+ # This encodes SP to %20 instead of +.
+ def self.encode_uri_component(str, enc=nil)
+ _encode_uri_component(/[^*\-.0-9A-Z_a-z]/, TBLENCURICOMP_, str, enc)
+ end
+
+ # Decodes given +str+ of URL-encoded data.
+ #
+ # This does not decode + to SP.
+ def self.decode_uri_component(str, enc=Encoding::UTF_8)
+ _decode_uri_component(/%\h\h/, str, enc)
+ end
+
+ def self._encode_uri_component(regexp, table, str, enc)
str = str.to_s.dup
if str.encoding != Encoding::ASCII_8BIT
if enc && enc != Encoding::ASCII_8BIT
@@ -311,19 +361,16 @@ module Bundler::URI
end
str.force_encoding(Encoding::ASCII_8BIT)
end
- str.gsub!(/[^*\-.0-9A-Z_a-z]/, TBLENCWWWCOMP_)
+ str.gsub!(regexp, table)
str.force_encoding(Encoding::US_ASCII)
end
+ private_class_method :_encode_uri_component
- # Decodes given +str+ of URL-encoded form data.
- #
- # This decodes + to SP.
- #
- # See Bundler::URI.encode_www_form_component, Bundler::URI.decode_www_form.
- def self.decode_www_form_component(str, enc=Encoding::UTF_8)
- raise ArgumentError, "invalid %-encoding (#{str})" if /%(?!\h\h)/ =~ str
- str.b.gsub(/\+|%\h\h/, TBLDECWWWCOMP_).force_encoding(enc)
+ def self._decode_uri_component(regexp, str, enc)
+ raise ArgumentError, "invalid %-encoding (#{str})" if /%(?!\h\h)/.match?(str)
+ str.b.gsub(regexp, TBLDECWWWCOMP_).force_encoding(enc)
end
+ private_class_method :_decode_uri_component
# Generates URL-encoded form data from given +enum+.
#
@@ -653,6 +700,7 @@ module Bundler::URI
"utf-16"=>"utf-16le",
"utf-16le"=>"utf-16le",
} # :nodoc:
+ Ractor.make_shareable(WEB_ENCODINGS_) if defined?(Ractor)
# :nodoc:
# return encoding or nil
diff --git a/lib/bundler/vendor/uri/lib/uri/file.rb b/lib/bundler/vendor/uri/lib/uri/file.rb
index df42f8bcdd..8d75a9de7a 100644
--- a/lib/bundler/vendor/uri/lib/uri/file.rb
+++ b/lib/bundler/vendor/uri/lib/uri/file.rb
@@ -33,6 +33,9 @@ module Bundler::URI
# If an Array is used, the components must be passed in the
# order <code>[host, path]</code>.
#
+ # A path from e.g. the File class should be escaped before
+ # being passed.
+ #
# Examples:
#
# require 'bundler/vendor/uri/lib/uri'
@@ -44,6 +47,9 @@ module Bundler::URI
# :path => '/ruby/src'})
# uri2.to_s # => "file://host.example.com/ruby/src"
#
+ # uri3 = Bundler::URI::File.build({:path => Bundler::URI::escape('/path/my file.txt')})
+ # uri3.to_s # => "file:///path/my%20file.txt"
+ #
def self.build(args)
tmp = Util::make_components_hash(self, args)
super(tmp)
@@ -90,5 +96,5 @@ module Bundler::URI
end
end
- @@schemes['FILE'] = File
+ register_scheme 'FILE', File
end
diff --git a/lib/bundler/vendor/uri/lib/uri/ftp.rb b/lib/bundler/vendor/uri/lib/uri/ftp.rb
index 2252e405d5..48b4c6718d 100644
--- a/lib/bundler/vendor/uri/lib/uri/ftp.rb
+++ b/lib/bundler/vendor/uri/lib/uri/ftp.rb
@@ -262,5 +262,6 @@ module Bundler::URI
return str
end
end
- @@schemes['FTP'] = FTP
+
+ register_scheme 'FTP', FTP
end
diff --git a/lib/bundler/vendor/uri/lib/uri/generic.rb b/lib/bundler/vendor/uri/lib/uri/generic.rb
index f29ba6cf18..9ae6915826 100644
--- a/lib/bundler/vendor/uri/lib/uri/generic.rb
+++ b/lib/bundler/vendor/uri/lib/uri/generic.rb
@@ -564,16 +564,26 @@ module Bundler::URI
end
end
- # Returns the user component.
+ # Returns the user component (without Bundler::URI decoding).
def user
@user
end
- # Returns the password component.
+ # Returns the password component (without Bundler::URI decoding).
def password
@password
end
+ # Returns the user component after Bundler::URI decoding.
+ def decoded_user
+ Bundler::URI.decode_uri_component(@user) if @user
+ end
+
+ # Returns the password component after Bundler::URI decoding.
+ def decoded_password
+ Bundler::URI.decode_uri_component(@password) if @password
+ end
+
#
# Checks the host +v+ component for RFC2396 compliance
# and against the Bundler::URI::Parser Regexp for :HOST.
@@ -643,7 +653,7 @@ module Bundler::URI
#
def hostname
v = self.host
- /\A\[(.*)\]\z/ =~ v ? $1 : v
+ v&.start_with?('[') && v.end_with?(']') ? v[1..-2] : v
end
# Sets the host part of the Bundler::URI as the argument with brackets for IPv6 addresses.
@@ -659,7 +669,7 @@ module Bundler::URI
# it is wrapped with brackets.
#
def hostname=(v)
- v = "[#{v}]" if /\A\[.*\]\z/ !~ v && /:/ =~ v
+ v = "[#{v}]" if !(v&.start_with?('[') && v&.end_with?(']')) && v&.index(':')
self.host = v
end
@@ -1514,9 +1524,19 @@ module Bundler::URI
proxy_uri = env["CGI_#{name.upcase}"]
end
elsif name == 'http_proxy'
- unless proxy_uri = env[name]
- if proxy_uri = env[name.upcase]
- warn 'The environment variable HTTP_PROXY is discouraged. Use http_proxy.', uplevel: 1
+ if RUBY_ENGINE == 'jruby' && p_addr = ENV_JAVA['http.proxyHost']
+ p_port = ENV_JAVA['http.proxyPort']
+ if p_user = ENV_JAVA['http.proxyUser']
+ p_pass = ENV_JAVA['http.proxyPass']
+ proxy_uri = "http://#{p_user}:#{p_pass}@#{p_addr}:#{p_port}"
+ else
+ proxy_uri = "http://#{p_addr}:#{p_port}"
+ end
+ else
+ unless proxy_uri = env[name]
+ if proxy_uri = env[name.upcase]
+ warn 'The environment variable HTTP_PROXY is discouraged. Use http_proxy.', uplevel: 1
+ end
end
end
else
diff --git a/lib/bundler/vendor/uri/lib/uri/http.rb b/lib/bundler/vendor/uri/lib/uri/http.rb
index 50d7e427a5..2c44810644 100644
--- a/lib/bundler/vendor/uri/lib/uri/http.rb
+++ b/lib/bundler/vendor/uri/lib/uri/http.rb
@@ -80,8 +80,46 @@ module Bundler::URI
url = @query ? "#@path?#@query" : @path.dup
url.start_with?(?/.freeze) ? url : ?/ + url
end
- end
- @@schemes['HTTP'] = HTTP
+ #
+ # == Description
+ #
+ # Returns the authority for an HTTP uri, as defined in
+ # https://datatracker.ietf.org/doc/html/rfc3986/#section-3.2.
+ #
+ #
+ # Example:
+ #
+ # Bundler::URI::HTTP.build(host: 'www.example.com', path: '/foo/bar').authority #=> "www.example.com"
+ # Bundler::URI::HTTP.build(host: 'www.example.com', port: 8000, path: '/foo/bar').authority #=> "www.example.com:8000"
+ # Bundler::URI::HTTP.build(host: 'www.example.com', port: 80, path: '/foo/bar').authority #=> "www.example.com"
+ #
+ def authority
+ if port == default_port
+ host
+ else
+ "#{host}:#{port}"
+ end
+ end
+
+ #
+ # == Description
+ #
+ # Returns the origin for an HTTP uri, as defined in
+ # https://datatracker.ietf.org/doc/html/rfc6454.
+ #
+ #
+ # Example:
+ #
+ # Bundler::URI::HTTP.build(host: 'www.example.com', path: '/foo/bar').origin #=> "http://www.example.com"
+ # Bundler::URI::HTTP.build(host: 'www.example.com', port: 8000, path: '/foo/bar').origin #=> "http://www.example.com:8000"
+ # Bundler::URI::HTTP.build(host: 'www.example.com', port: 80, path: '/foo/bar').origin #=> "http://www.example.com"
+ # Bundler::URI::HTTPS.build(host: 'www.example.com', path: '/foo/bar').origin #=> "https://www.example.com"
+ #
+ def origin
+ "#{scheme}://#{authority}"
+ end
+ end
+ register_scheme 'HTTP', HTTP
end
diff --git a/lib/bundler/vendor/uri/lib/uri/https.rb b/lib/bundler/vendor/uri/lib/uri/https.rb
index 4fd4e9af7b..e4556e3ecb 100644
--- a/lib/bundler/vendor/uri/lib/uri/https.rb
+++ b/lib/bundler/vendor/uri/lib/uri/https.rb
@@ -18,5 +18,6 @@ module Bundler::URI
# A Default port of 443 for Bundler::URI::HTTPS
DEFAULT_PORT = 443
end
- @@schemes['HTTPS'] = HTTPS
+
+ register_scheme 'HTTPS', HTTPS
end
diff --git a/lib/bundler/vendor/uri/lib/uri/ldap.rb b/lib/bundler/vendor/uri/lib/uri/ldap.rb
index 6e9e1918f6..9811b6e2f5 100644
--- a/lib/bundler/vendor/uri/lib/uri/ldap.rb
+++ b/lib/bundler/vendor/uri/lib/uri/ldap.rb
@@ -257,5 +257,5 @@ module Bundler::URI
end
end
- @@schemes['LDAP'] = LDAP
+ register_scheme 'LDAP', LDAP
end
diff --git a/lib/bundler/vendor/uri/lib/uri/ldaps.rb b/lib/bundler/vendor/uri/lib/uri/ldaps.rb
index 0af35bb16b..c786168450 100644
--- a/lib/bundler/vendor/uri/lib/uri/ldaps.rb
+++ b/lib/bundler/vendor/uri/lib/uri/ldaps.rb
@@ -17,5 +17,6 @@ module Bundler::URI
# A Default port of 636 for Bundler::URI::LDAPS
DEFAULT_PORT = 636
end
- @@schemes['LDAPS'] = LDAPS
+
+ register_scheme 'LDAPS', LDAPS
end
diff --git a/lib/bundler/vendor/uri/lib/uri/mailto.rb b/lib/bundler/vendor/uri/lib/uri/mailto.rb
index ff7ab7e114..ff2e30be86 100644
--- a/lib/bundler/vendor/uri/lib/uri/mailto.rb
+++ b/lib/bundler/vendor/uri/lib/uri/mailto.rb
@@ -15,7 +15,7 @@ module Bundler::URI
# RFC6068, the mailto URL scheme.
#
class MailTo < Generic
- include REGEXP
+ include RFC2396_REGEXP
# A Default port of nil for Bundler::URI::MailTo.
DEFAULT_PORT = nil
@@ -289,5 +289,5 @@ module Bundler::URI
alias to_rfc822text to_mailtext
end
- @@schemes['MAILTO'] = MailTo
+ register_scheme 'MAILTO', MailTo
end
diff --git a/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb b/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb
index e48e164f4c..2f8d55353b 100644
--- a/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb
+++ b/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb
@@ -116,7 +116,7 @@ module Bundler::URI
# See also Bundler::URI::Parser.initialize_regexp.
attr_reader :regexp
- # Returns a split Bundler::URI against regexp[:ABS_URI].
+ # Returns a split Bundler::URI against +regexp[:ABS_URI]+.
def split(uri)
case uri
when ''
@@ -257,8 +257,8 @@ module Bundler::URI
end
end
- # Returns Regexp that is default self.regexp[:ABS_URI_REF],
- # unless +schemes+ is provided. Then it is a Regexp.union with self.pattern[:X_ABS_URI].
+ # Returns Regexp that is default +self.regexp[:ABS_URI_REF]+,
+ # unless +schemes+ is provided. Then it is a Regexp.union with +self.pattern[:X_ABS_URI]+.
def make_regexp(schemes = nil)
unless schemes
@regexp[:ABS_URI_REF]
@@ -277,7 +277,7 @@ module Bundler::URI
# +str+::
# String to make safe
# +unsafe+::
- # Regexp to apply. Defaults to self.regexp[:UNSAFE]
+ # Regexp to apply. Defaults to +self.regexp[:UNSAFE]+
#
# == Description
#
@@ -309,7 +309,7 @@ module Bundler::URI
# +str+::
# String to remove escapes from
# +escaped+::
- # Regexp to apply. Defaults to self.regexp[:ESCAPED]
+ # Regexp to apply. Defaults to +self.regexp[:ESCAPED]+
#
# == Description
#
@@ -322,8 +322,14 @@ module Bundler::URI
end
@@to_s = Kernel.instance_method(:to_s)
- def inspect
- @@to_s.bind_call(self)
+ if @@to_s.respond_to?(:bind_call)
+ def inspect
+ @@to_s.bind_call(self)
+ end
+ else
+ def inspect
+ @@to_s.bind(self).call
+ end
end
private
diff --git a/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb b/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb
index 2029cfd056..1307e8e474 100644
--- a/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb
+++ b/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb
@@ -2,9 +2,8 @@
module Bundler::URI
class RFC3986_Parser # :nodoc:
# Bundler::URI defined in RFC3986
- # this regexp is modified not to host is not empty string
- RFC3986_URI = /\A(?<Bundler::URI>(?<scheme>[A-Za-z][+\-.0-9A-Za-z]*):(?<hier-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*)@)?(?<host>(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h+\.[!$&-.0-;=A-Z_a-z~]+))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])+))?(?::(?<port>\d*))?)(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*))*)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+)(?:\/\g<segment>)*)?)|(?<path-rootless>\g<segment-nz>(?:\/\g<segment>)*)|(?<path-empty>))(?:\?(?<query>[^#]*))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*))?)\z/
- RFC3986_relative_ref = /\A(?<relative-ref>(?<relative-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*)@)?(?<host>(?<IP-literal>\[(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:){,1}\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h+\.[!$&-.0-;=A-Z_a-z~]+)\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])+))?(?::(?<port>\d*))?)(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*))*)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+)(?:\/\g<segment>)*)?)|(?<path-noscheme>(?<segment-nz-nc>(?:%\h\h|[!$&-.0-9;=@-Z_a-z~])+)(?:\/\g<segment>)*)|(?<path-empty>))(?:\?(?<query>[^#]*))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*))?)\z/
+ RFC3986_URI = /\A(?<Bundler::URI>(?<scheme>[A-Za-z][+\-.0-9A-Za-z]*):(?<hier-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*)@)?(?<host>(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h+\.[!$&-.0-;=A-Z_a-z~]+))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])*))(?::(?<port>\d*))?)(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*))*)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+)(?:\/\g<segment>)*)?)|(?<path-rootless>\g<segment-nz>(?:\/\g<segment>)*)|(?<path-empty>))(?:\?(?<query>[^#]*))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*))?)\z/
+ RFC3986_relative_ref = /\A(?<relative-ref>(?<relative-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*)@)?(?<host>(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:){,1}\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h+\.[!$&-.0-;=A-Z_a-z~]+))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])+))?(?::(?<port>\d*))?)(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*))*)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+)(?:\/\g<segment>)*)?)|(?<path-noscheme>(?<segment-nz-nc>(?:%\h\h|[!$&-.0-9;=@-Z_a-z~])+)(?:\/\g<segment>)*)|(?<path-empty>))(?:\?(?<query>[^#]*))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*))?)\z/
attr_reader :regexp
def initialize
@@ -79,8 +78,14 @@ module Bundler::URI
end
@@to_s = Kernel.instance_method(:to_s)
- def inspect
- @@to_s.bind_call(self)
+ if @@to_s.respond_to?(:bind_call)
+ def inspect
+ @@to_s.bind_call(self)
+ end
+ else
+ def inspect
+ @@to_s.bind(self).call
+ end
end
private
diff --git a/lib/bundler/vendor/uri/lib/uri/version.rb b/lib/bundler/vendor/uri/lib/uri/version.rb
index f2bb0ebad2..02fa367735 100644
--- a/lib/bundler/vendor/uri/lib/uri/version.rb
+++ b/lib/bundler/vendor/uri/lib/uri/version.rb
@@ -1,6 +1,6 @@
module Bundler::URI
# :stopdoc:
- VERSION_CODE = '001001'.freeze
+ VERSION_CODE = '001200'.freeze
VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze
# :startdoc:
end
diff --git a/lib/bundler/vendor/uri/lib/uri/ws.rb b/lib/bundler/vendor/uri/lib/uri/ws.rb
index 58e08bf98e..10ae6f5834 100644
--- a/lib/bundler/vendor/uri/lib/uri/ws.rb
+++ b/lib/bundler/vendor/uri/lib/uri/ws.rb
@@ -79,6 +79,5 @@ module Bundler::URI
end
end
- @@schemes['WS'] = WS
-
+ register_scheme 'WS', WS
end
diff --git a/lib/bundler/vendor/uri/lib/uri/wss.rb b/lib/bundler/vendor/uri/lib/uri/wss.rb
index 3827053c7b..e8db1ceabf 100644
--- a/lib/bundler/vendor/uri/lib/uri/wss.rb
+++ b/lib/bundler/vendor/uri/lib/uri/wss.rb
@@ -18,5 +18,6 @@ module Bundler::URI
# A Default port of 443 for Bundler::URI::WSS
DEFAULT_PORT = 443
end
- @@schemes['WSS'] = WSS
+
+ register_scheme 'WSS', WSS
end