summaryrefslogtreecommitdiff
path: root/lib/bundler/vendor
diff options
context:
space:
mode:
authorhsbt <hsbt@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-11-02 23:07:56 +0000
committerhsbt <hsbt@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-11-02 23:07:56 +0000
commit59c8d50653480bef3f24517296e6ddf937fdf6bc (patch)
treedf10aaf4f3307837fe3d1d129d66f6c0c7586bc5 /lib/bundler/vendor
parent7deb37777a230837e865e0a11fb8d7c1dc6d03ce (diff)
Added bundler as default gems. Revisit [Feature #12733]
* bin/*, lib/bundler/*, lib/bundler.rb, spec/bundler, man/*: Merge from latest stable branch of bundler/bundler repository and added workaround patches. I will backport them into upstream. * common.mk, defs/gmake.mk: Added `test-bundler` task for test suite of bundler. * tool/sync_default_gems.rb: Added sync task for bundler. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@65509 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/bundler/vendor')
-rw-r--r--lib/bundler/vendor/fileutils/lib/fileutils.rb1638
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo.rb12
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/compatibility.rb26
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb57
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb81
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb223
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb36
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb66
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb62
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb63
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb61
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb126
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb46
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb36
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb136
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/errors.rb143
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb6
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb101
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rb67
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb837
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/resolver.rb46
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/state.rb58
-rw-r--r--lib/bundler/vendor/net-http-persistent/lib/net/http/faster.rb27
-rw-r--r--lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb1233
-rw-r--r--lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/ssl_reuse.rb129
-rw-r--r--lib/bundler/vendor/thor/lib/thor.rb509
-rw-r--r--lib/bundler/vendor/thor/lib/thor/actions.rb321
-rw-r--r--lib/bundler/vendor/thor/lib/thor/actions/create_file.rb104
-rw-r--r--lib/bundler/vendor/thor/lib/thor/actions/create_link.rb60
-rw-r--r--lib/bundler/vendor/thor/lib/thor/actions/directory.rb118
-rw-r--r--lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb143
-rw-r--r--lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb364
-rw-r--r--lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb109
-rw-r--r--lib/bundler/vendor/thor/lib/thor/base.rb679
-rw-r--r--lib/bundler/vendor/thor/lib/thor/command.rb135
-rw-r--r--lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb97
-rw-r--r--lib/bundler/vendor/thor/lib/thor/core_ext/io_binary_read.rb12
-rw-r--r--lib/bundler/vendor/thor/lib/thor/core_ext/ordered_hash.rb129
-rw-r--r--lib/bundler/vendor/thor/lib/thor/error.rb32
-rw-r--r--lib/bundler/vendor/thor/lib/thor/group.rb281
-rw-r--r--lib/bundler/vendor/thor/lib/thor/invocation.rb177
-rw-r--r--lib/bundler/vendor/thor/lib/thor/line_editor.rb17
-rw-r--r--lib/bundler/vendor/thor/lib/thor/line_editor/basic.rb37
-rw-r--r--lib/bundler/vendor/thor/lib/thor/line_editor/readline.rb88
-rw-r--r--lib/bundler/vendor/thor/lib/thor/parser.rb4
-rw-r--r--lib/bundler/vendor/thor/lib/thor/parser/argument.rb70
-rw-r--r--lib/bundler/vendor/thor/lib/thor/parser/arguments.rb175
-rw-r--r--lib/bundler/vendor/thor/lib/thor/parser/option.rb146
-rw-r--r--lib/bundler/vendor/thor/lib/thor/parser/options.rb221
-rw-r--r--lib/bundler/vendor/thor/lib/thor/rake_compat.rb71
-rw-r--r--lib/bundler/vendor/thor/lib/thor/runner.rb324
-rw-r--r--lib/bundler/vendor/thor/lib/thor/shell.rb81
-rw-r--r--lib/bundler/vendor/thor/lib/thor/shell/basic.rb437
-rw-r--r--lib/bundler/vendor/thor/lib/thor/shell/color.rb149
-rw-r--r--lib/bundler/vendor/thor/lib/thor/shell/html.rb126
-rw-r--r--lib/bundler/vendor/thor/lib/thor/util.rb268
-rw-r--r--lib/bundler/vendor/thor/lib/thor/version.rb3
57 files changed, 10803 insertions, 0 deletions
diff --git a/lib/bundler/vendor/fileutils/lib/fileutils.rb b/lib/bundler/vendor/fileutils/lib/fileutils.rb
new file mode 100644
index 0000000000..cc69740845
--- /dev/null
+++ b/lib/bundler/vendor/fileutils/lib/fileutils.rb
@@ -0,0 +1,1638 @@
+# frozen_string_literal: true
+#
+# = fileutils.rb
+#
+# Copyright (c) 2000-2007 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+#
+# == module Bundler::FileUtils
+#
+# Namespace for several file utility methods for copying, moving, removing, etc.
+#
+# === Module Functions
+#
+# require 'bundler/vendor/fileutils/lib/fileutils'
+#
+# 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)
+#
+# The <tt>options</tt> parameter is a hash of options, taken from the list
+# <tt>:force</tt>, <tt>:noop</tt>, <tt>:preserve</tt>, and <tt>:verbose</tt>.
+# <tt>:noop</tt> means that no changes are made. The other three are obvious.
+# Each method documents the options that it honours.
+#
+# 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.
+#
+# There are some `low level' methods, which do not accept any option:
+#
+# Bundler::FileUtils.copy_entry(src, dest, preserve = false, dereference = 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)
+#
+# == module Bundler::FileUtils::Verbose
+#
+# 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.
+#
+# == module Bundler::FileUtils::NoWrite
+#
+# 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.
+#
+# == module Bundler::FileUtils::DryRun
+#
+# 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.
+#
+
+module Bundler::FileUtils
+
+ def self.private_module_function(name) #:nodoc:
+ module_function name
+ private_class_method name
+ end
+
+ #
+ # Returns the name of the current directory.
+ #
+ def pwd
+ Dir.pwd
+ end
+ module_function :pwd
+
+ alias getwd pwd
+ module_function :getwd
+
+ #
+ # Changes the current directory to the directory +dir+.
+ #
+ # If this method is called with block, resumes to the old
+ # working directory after the block execution finished.
+ #
+ # Bundler::FileUtils.cd('/', :verbose => true) # chdir and report it
+ #
+ # Bundler::FileUtils.cd('/') do # chdir
+ # # ... # do something
+ # end # return to original directory
+ #
+ def cd(dir, verbose: nil, &block) # :yield: dir
+ fu_output_message "cd #{dir}" if verbose
+ Dir.chdir(dir, &block)
+ fu_output_message 'cd -' if verbose and block
+ end
+ module_function :cd
+
+ alias chdir cd
+ module_function :chdir
+
+ #
+ # Returns true if +new+ is newer than all +old_list+.
+ # Non-existent files are older than any file.
+ #
+ # Bundler::FileUtils.uptodate?('hello.o', %w(hello.c hello.h)) or \
+ # system 'make hello.o'
+ #
+ def uptodate?(new, old_list)
+ return false unless File.exist?(new)
+ new_time = File.mtime(new)
+ old_list.each do |old|
+ if File.exist?(old)
+ return false unless new_time > File.mtime(old)
+ end
+ end
+ true
+ end
+ module_function :uptodate?
+
+ def remove_trailing_slash(dir) #:nodoc:
+ dir == '/' ? dir : dir.chomp(?/)
+ end
+ private_module_function :remove_trailing_slash
+
+ #
+ # Creates one or more directories.
+ #
+ # 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
+ #
+ def mkdir(list, mode: nil, noop: nil, verbose: nil)
+ list = fu_list(list)
+ fu_output_message "mkdir #{mode ? ('-m %03o ' % mode) : ''}#{list.join ' '}" if verbose
+ return if noop
+
+ list.each do |dir|
+ fu_mkdir dir, mode
+ end
+ end
+ module_function :mkdir
+
+ #
+ # Creates a directory and all its parent directories.
+ # For example,
+ #
+ # Bundler::FileUtils.mkdir_p '/usr/local/lib/ruby'
+ #
+ # causes to make following directories, if it does not exist.
+ #
+ # * /usr
+ # * /usr/local
+ # * /usr/local/lib
+ # * /usr/local/lib/ruby
+ #
+ # You can pass several directories at a time in a list.
+ #
+ 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
+
+ stack = []
+ until path == stack.last # dirname("/")=="/", dirname("C:/")=="C:/"
+ stack.push path
+ path = File.dirname(path)
+ end
+ stack.pop # root directory should exist
+ stack.reverse_each do |dir|
+ begin
+ fu_mkdir dir, mode
+ rescue SystemCallError
+ raise unless File.directory?(dir)
+ end
+ end
+ end
+
+ return *list
+ end
+ module_function :mkdir_p
+
+ alias mkpath mkdir_p
+ alias makedirs mkdir_p
+ module_function :mkpath
+ module_function :makedirs
+
+ def fu_mkdir(path, mode) #:nodoc:
+ path = remove_trailing_slash(path)
+ if mode
+ Dir.mkdir path, mode
+ File.chmod mode, path
+ else
+ Dir.mkdir path
+ end
+ end
+ private_module_function :fu_mkdir
+
+ #
+ # Removes one or more directories.
+ #
+ # 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
+ #
+ def rmdir(list, parents: nil, noop: nil, verbose: nil)
+ list = fu_list(list)
+ fu_output_message "rmdir #{parents ? '-p ' : ''}#{list.join ' '}" if verbose
+ return if noop
+ list.each do |dir|
+ begin
+ Dir.rmdir(dir = remove_trailing_slash(dir))
+ if parents
+ until (parent = File.dirname(dir)) == '.' or parent == dir
+ dir = parent
+ Dir.rmdir(dir)
+ end
+ end
+ rescue Errno::ENOTEMPTY, Errno::EEXIST, Errno::ENOENT
+ end
+ end
+ end
+ module_function :rmdir
+
+ #
+ # :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)
+ #
+ # 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+.
+ #
+ # Bundler::FileUtils.ln 'gcc', 'cc', verbose: true
+ # Bundler::FileUtils.ln '/usr/bin/emacs21', '/usr/bin/emacs'
+ #
+ # 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.
+ #
+ # Bundler::FileUtils.cd '/sbin'
+ # Bundler::FileUtils.ln %w(cp mv mkdir), '/bin' # Now /sbin/cp and /bin/cp are linked.
+ #
+ def ln(src, dest, force: nil, noop: nil, verbose: nil)
+ fu_output_message "ln#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose
+ return if noop
+ fu_each_src_dest0(src, dest) do |s,d|
+ remove_file d, true if force
+ File.link s, d
+ end
+ end
+ module_function :ln
+
+ alias link ln
+ module_function :link
+
+ #
+ # :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)
+ #
+ # In the first form, creates a symbolic link +link+ which points to +target+.
+ # If +link+ already exists, raises Errno::EEXIST.
+ # But if the :force option is set, overwrites +link+.
+ #
+ # Bundler::FileUtils.ln_s '/usr/bin/ruby', '/usr/local/bin/ruby'
+ # Bundler::FileUtils.ln_s 'verylongsourcefilename.c', 'c', force: true
+ #
+ # 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.
+ #
+ # Bundler::FileUtils.ln_s Dir.glob('/bin/*.rb'), '/home/foo/bin'
+ #
+ def ln_s(src, dest, force: nil, noop: nil, verbose: nil)
+ 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|
+ remove_file d, true if force
+ File.symlink s, d
+ end
+ end
+ module_function :ln_s
+
+ alias symlink ln_s
+ module_function :symlink
+
+ #
+ # :call-seq:
+ # Bundler::FileUtils.ln_sf(*args)
+ #
+ # Same as
+ #
+ # Bundler::FileUtils.ln_s(*args, force: true)
+ #
+ def ln_sf(src, dest, noop: nil, verbose: nil)
+ ln_s src, dest, force: true, noop: noop, verbose: verbose
+ end
+ module_function :ln_sf
+
+ #
+ # Copies a file content +src+ to +dest+. If +dest+ is a directory,
+ # copies +src+ to +dest/src+.
+ #
+ # If +src+ is a list of files, then +dest+ must be a directory.
+ #
+ # 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
+ #
+ def cp(src, dest, preserve: nil, noop: nil, verbose: nil)
+ fu_output_message "cp#{preserve ? ' -p' : ''} #{[src,dest].flatten.join ' '}" if verbose
+ return if noop
+ fu_each_src_dest(src, dest) do |s, d|
+ copy_file s, d, preserve
+ end
+ end
+ module_function :cp
+
+ 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.
+ #
+ # # Installing Ruby library "mylib" under the site_ruby
+ # Bundler::FileUtils.rm_r site_ruby + '/mylib', :force
+ # 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.
+ #
+ def cp_r(src, dest, preserve: nil, noop: nil, verbose: nil,
+ dereference_root: true, remove_destination: nil)
+ fu_output_message "cp -r#{preserve ? 'p' : ''}#{remove_destination ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if verbose
+ return if noop
+ fu_each_src_dest(src, dest) do |s, d|
+ copy_entry s, d, preserve, dereference_root, remove_destination
+ end
+ end
+ module_function :cp_r
+
+ #
+ # 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)
+ #
+ # Both of +src+ and +dest+ must be a path name.
+ # +src+ must exist, +dest+ must not exist.
+ #
+ # If +preserve+ is true, this method preserves owner, group, and
+ # modified time. Permissions are copied regardless +preserve+.
+ #
+ # If +dereference_root+ is true, this method dereference tree root.
+ #
+ # If +remove_destination+ is true, this method removes each destination file before copy.
+ #
+ def copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false)
+ Entry_.new(src, nil, dereference_root).wrap_traverse(proc do |ent|
+ destent = Entry_.new(dest, ent.rel, false)
+ File.unlink destent.path if remove_destination && File.file?(destent.path)
+ ent.copy destent.path
+ end, proc do |ent|
+ destent = Entry_.new(dest, ent.rel, false)
+ ent.copy_metadata destent.path if preserve
+ end)
+ end
+ module_function :copy_entry
+
+ #
+ # Copies file contents of +src+ to +dest+.
+ # Both of +src+ and +dest+ must be a path name.
+ #
+ def copy_file(src, dest, preserve = false, dereference = true)
+ ent = Entry_.new(src, nil, dereference)
+ ent.copy_file dest
+ ent.copy_metadata dest if preserve
+ end
+ module_function :copy_file
+
+ #
+ # Copies stream +src+ to +dest+.
+ # +src+ must respond to #read(n) and
+ # +dest+ must respond to #write(str).
+ #
+ 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
+ #
+ def mv(src, dest, force: nil, noop: nil, verbose: nil, secure: nil)
+ fu_output_message "mv#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose
+ return if noop
+ fu_each_src_dest(src, dest) do |s, d|
+ destent = Entry_.new(d, nil, true)
+ begin
+ if destent.exist?
+ if destent.directory?
+ raise Errno::EEXIST, d
+ else
+ destent.remove_file if rename_cannot_overwrite_file?
+ end
+ end
+ begin
+ File.rename s, d
+ rescue Errno::EXDEV
+ copy_entry s, d, true
+ if secure
+ remove_entry_secure s, force
+ else
+ remove_entry s, force
+ end
+ end
+ rescue SystemCallError
+ raise unless force
+ end
+ end
+ end
+ module_function :mv
+
+ alias move mv
+ module_function :move
+
+ def rename_cannot_overwrite_file? #:nodoc:
+ /emx/ =~ RUBY_PLATFORM
+ end
+ private_module_function :rename_cannot_overwrite_file?
+
+ #
+ # Remove file(s) specified in +list+. This method cannot remove directories.
+ # All StandardErrors are ignored when the :force option is set.
+ #
+ # Bundler::FileUtils.rm %w( junk.txt dust.txt )
+ # Bundler::FileUtils.rm Dir.glob('*.so')
+ # Bundler::FileUtils.rm 'NotExistFile', :force => true # never raises exception
+ #
+ def rm(list, force: nil, noop: nil, verbose: nil)
+ list = fu_list(list)
+ fu_output_message "rm#{force ? ' -f' : ''} #{list.join ' '}" if verbose
+ return if noop
+
+ list.each do |path|
+ remove_file path, force
+ end
+ end
+ module_function :rm
+
+ alias remove rm
+ module_function :remove
+
+ #
+ # Equivalent to
+ #
+ # Bundler::FileUtils.rm(list, :force => true)
+ #
+ def rm_f(list, noop: nil, verbose: nil)
+ rm list, force: true, noop: noop, verbose: verbose
+ end
+ module_function :rm_f
+
+ alias safe_unlink rm_f
+ module_function :safe_unlink
+
+ #
+ # 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.
+ #
+ # Bundler::FileUtils.rm_r Dir.glob('/tmp/*')
+ # Bundler::FileUtils.rm_r 'some_dir', :force => true
+ #
+ # 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 :secure=>false.
+ #
+ # NOTE: This method calls #remove_entry_secure if :secure option is set.
+ # See also #remove_entry_secure.
+ #
+ def rm_r(list, force: nil, noop: nil, verbose: nil, secure: nil)
+ list = fu_list(list)
+ fu_output_message "rm -r#{force ? 'f' : ''} #{list.join ' '}" if verbose
+ return if noop
+ list.each do |path|
+ if secure
+ remove_entry_secure path, force
+ else
+ remove_entry path, force
+ end
+ end
+ end
+ module_function :rm_r
+
+ #
+ # Equivalent to
+ #
+ # Bundler::FileUtils.rm_r(list, :force => true)
+ #
+ # WARNING: This method causes local vulnerability.
+ # Read the documentation of #rm_r first.
+ #
+ def rm_rf(list, noop: nil, verbose: nil, secure: nil)
+ rm_r list, force: true, noop: noop, verbose: verbose, secure: secure
+ end
+ module_function :rm_rf
+
+ alias rmtree rm_rf
+ module_function :rmtree
+
+ #
+ # 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.
+ #
+ # 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).
+ #
+ # 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.
+ #
+ # 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:
+ #
+ # * http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0448
+ # * http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0452
+ #
+ # For fileutils.rb, this vulnerability is reported in [ruby-dev:26100].
+ #
+ def remove_entry_secure(path, force = false)
+ unless fu_have_symlink?
+ remove_entry path, force
+ return
+ end
+ fullpath = File.expand_path(path)
+ st = File.lstat(fullpath)
+ unless st.directory?
+ File.unlink fullpath
+ return
+ end
+ # is a directory.
+ parent_st = File.stat(File.dirname(fullpath))
+ unless parent_st.world_writable?
+ remove_entry path, force
+ return
+ end
+ unless parent_st.sticky?
+ raise ArgumentError, "parent directory is world writable, Bundler::FileUtils#remove_entry_secure does not work; abort: #{path.inspect} (parent directory mode #{'%o' % parent_st.mode})"
+ end
+ # freeze tree root
+ euid = Process.euid
+ File.open(fullpath + '/.') {|f|
+ unless fu_stat_identical_entry?(st, f.stat)
+ # symlink (TOC-to-TOU attack?)
+ File.unlink fullpath
+ return
+ end
+ f.chown euid, -1
+ f.chmod 0700
+ unless fu_stat_identical_entry?(st, File.lstat(fullpath))
+ # TOC-to-TOU attack?
+ File.unlink fullpath
+ return
+ end
+ }
+ # ---- tree root is frozen ----
+ root = Entry_.new(path)
+ root.preorder_traverse do |ent|
+ if ent.directory?
+ ent.chown euid, -1
+ ent.chmod 0700
+ end
+ end
+ root.postorder_traverse do |ent|
+ begin
+ ent.remove
+ rescue
+ raise unless force
+ end
+ end
+ rescue
+ raise unless force
+ end
+ module_function :remove_entry_secure
+
+ def fu_have_symlink? #:nodoc:
+ File.symlink nil, nil
+ rescue NotImplementedError
+ return false
+ rescue TypeError
+ return true
+ end
+ private_module_function :fu_have_symlink?
+
+ def fu_stat_identical_entry?(a, b) #:nodoc:
+ a.dev == b.dev and a.ino == b.ino
+ end
+ private_module_function :fu_stat_identical_entry?
+
+ #
+ # 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.
+ #
+ # See also #remove_entry_secure.
+ #
+ def remove_entry(path, force = false)
+ Entry_.new(path).postorder_traverse do |ent|
+ begin
+ ent.remove
+ rescue
+ raise unless force
+ end
+ end
+ rescue
+ raise unless force
+ end
+ module_function :remove_entry
+
+ #
+ # Removes a file +path+.
+ # This method ignores StandardError if +force+ is true.
+ #
+ def remove_file(path, force = false)
+ Entry_.new(path).remove_file
+ rescue
+ raise unless force
+ end
+ module_function :remove_file
+
+ #
+ # Removes a directory +dir+ and its contents recursively.
+ # This method ignores StandardError if +force+ is true.
+ #
+ 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 a file +a+ and a file +b+ are identical.
+ #
+ # Bundler::FileUtils.compare_file('somefile', 'somefile') #=> true
+ # Bundler::FileUtils.compare_file('/dev/null', '/dev/urandom') #=> false
+ #
+ def compare_file(a, b)
+ return false unless File.size(a) == File.size(b)
+ File.open(a, 'rb') {|fa|
+ File.open(b, 'rb') {|fb|
+ return compare_stream(fa, fb)
+ }
+ }
+ end
+ module_function :compare_file
+
+ alias identical? compare_file
+ alias cmp compare_file
+ module_function :identical?
+ module_function :cmp
+
+ #
+ # Returns true if the contents of a stream +a+ and +b+ are identical.
+ #
+ def compare_stream(a, b)
+ bsize = fu_stream_blksize(a, b)
+ sa = String.new(capacity: bsize)
+ sb = String.new(capacity: bsize)
+ begin
+ a.read(bsize, sa)
+ b.read(bsize, sb)
+ return true if sa.empty? && sb.empty?
+ end while sa == sb
+ false
+ end
+ module_function :compare_stream
+
+ #
+ # 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.
+ #
+ # 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
+ #
+ def install(src, dest, mode: nil, owner: nil, group: nil, preserve: nil,
+ noop: nil, verbose: nil)
+ if verbose
+ msg = +"install -c"
+ msg << ' -p' if preserve
+ msg << ' -m ' << mode_to_s(mode) if mode
+ msg << " -o #{owner}" if owner
+ msg << " -g #{group}" if group
+ msg << ' ' << [src,dest].flatten.join(' ')
+ fu_output_message msg
+ end
+ return if noop
+ uid = fu_get_uid(owner)
+ gid = fu_get_gid(group)
+ fu_each_src_dest(src, dest) do |s, d|
+ st = File.stat(s)
+ unless File.exist?(d) and compare_file(s, d)
+ remove_file d, true
+ copy_file s, d
+ File.utime st.atime, st.mtime, d if preserve
+ File.chmod fu_mode(mode, st), d if mode
+ File.chown uid, gid, d if uid or gid
+ end
+ end
+ end
+ module_function :install
+
+ def user_mask(target) #:nodoc:
+ target.each_char.inject(0) do |mask, chr|
+ case chr
+ when "u"
+ mask | 04700
+ when "g"
+ mask | 02070
+ when "o"
+ mask | 01007
+ when "a"
+ mask | 07777
+ else
+ raise ArgumentError, "invalid `who' symbol in file mode: #{chr}"
+ end
+ end
+ end
+ private_module_function :user_mask
+
+ def apply_mask(mode, user_mask, op, mode_mask) #:nodoc:
+ case op
+ when '='
+ (mode & ~user_mask) | (user_mask & mode_mask)
+ when '+'
+ mode | (user_mask & mode_mask)
+ when '-'
+ mode & ~(user_mask & mode_mask)
+ end
+ end
+ 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
+ mode_sym.split(/,/).inject(mode & 07777) do |current_mode, clause|
+ target, *actions = clause.split(/([=+-])/)
+ raise ArgumentError, "invalid file mode: #{mode_sym}" if actions.empty?
+ target = 'a' if target.empty?
+ user_mask = user_mask(target)
+ actions.each_slice(2) do |op, perm|
+ need_apply = op == '='
+ mode_mask = (perm || '').each_char.inject(0) do |mask, chr|
+ case chr
+ when "r"
+ mask | 0444
+ when "w"
+ mask | 0222
+ when "x"
+ mask | 0111
+ when "X"
+ if FileTest.directory? path
+ mask | 0111
+ else
+ mask
+ end
+ when "s"
+ mask | 06000
+ when "t"
+ mask | 01000
+ when "u", "g", "o"
+ if mask.nonzero?
+ current_mode = apply_mask(current_mode, user_mask, op, mask)
+ end
+ need_apply = false
+ copy_mask = user_mask(chr)
+ (current_mode & copy_mask) / (copy_mask & 0111) * (user_mask & 0111)
+ else
+ raise ArgumentError, "invalid `perm' symbol in file mode: #{chr}"
+ end
+ end
+
+ if mode_mask.nonzero? || need_apply
+ current_mode = apply_mask(current_mode, user_mask, op, mode_mask)
+ end
+ end
+ current_mode
+ end
+ end
+ private_module_function :symbolic_modes_to_i
+
+ def fu_mode(mode, path) #:nodoc:
+ mode.is_a?(String) ? symbolic_modes_to_i(mode, path) : mode
+ end
+ private_module_function :fu_mode
+
+ def mode_to_s(mode) #:nodoc:
+ mode.is_a?(String) ? mode : "%o" % mode
+ end
+ private_module_function :mode_to_s
+
+ #
+ # 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
+ return if noop
+ list.each do |path|
+ Entry_.new(path).chmod(fu_mode(mode, path))
+ end
+ 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.#{$$}"
+ #
+ def chmod_R(mode, list, noop: nil, verbose: nil, force: nil)
+ list = fu_list(list)
+ fu_output_message sprintf('chmod -R%s %s %s',
+ (force ? 'f' : ''),
+ mode_to_s(mode), list.join(' ')) if verbose
+ return if noop
+ list.each do |root|
+ Entry_.new(root).traverse do |ent|
+ begin
+ ent.chmod(fu_mode(mode, ent.path))
+ rescue
+ raise unless force
+ end
+ end
+ end
+ end
+ module_function :chmod_R
+
+ #
+ # 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.
+ #
+ # Bundler::FileUtils.chown 'root', 'staff', '/usr/local/bin/ruby'
+ # Bundler::FileUtils.chown nil, 'bin', Dir.glob('/usr/bin/*'), :verbose => true
+ #
+ def chown(user, group, list, noop: nil, verbose: nil)
+ list = fu_list(list)
+ fu_output_message sprintf('chown %s %s',
+ (group ? "#{user}:#{group}" : user || ':'),
+ list.join(' ')) if verbose
+ return if noop
+ uid = fu_get_uid(user)
+ gid = fu_get_gid(group)
+ list.each do |path|
+ Entry_.new(path).chown uid, gid
+ end
+ 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
+ #
+ def chown_R(user, group, list, noop: nil, verbose: nil, force: nil)
+ list = fu_list(list)
+ fu_output_message sprintf('chown -R%s %s %s',
+ (force ? 'f' : ''),
+ (group ? "#{user}:#{group}" : user || ':'),
+ list.join(' ')) if verbose
+ return if noop
+ uid = fu_get_uid(user)
+ gid = fu_get_gid(group)
+ list.each do |root|
+ Entry_.new(root).traverse do |ent|
+ begin
+ ent.chown uid, gid
+ rescue
+ raise unless force
+ end
+ end
+ end
+ end
+ module_function :chown_R
+
+ begin
+ require 'etc'
+ rescue LoadError # rescue LoadError for miniruby
+ end
+
+ def fu_get_uid(user) #:nodoc:
+ return nil unless user
+ case user
+ when Integer
+ user
+ when /\A\d+\z/
+ user.to_i
+ else
+ Etc.getpwnam(user) ? Etc.getpwnam(user).uid : nil
+ end
+ end
+ private_module_function :fu_get_uid
+
+ def fu_get_gid(group) #:nodoc:
+ return nil unless group
+ case group
+ when Integer
+ group
+ when /\A\d+\z/
+ group.to_i
+ else
+ Etc.getgrnam(group) ? Etc.getgrnam(group).gid : nil
+ end
+ end
+ private_module_function :fu_get_gid
+
+ #
+ # Updates modification time (mtime) and access time (atime) of file(s) in
+ # +list+. Files are created if they don't exist.
+ #
+ # Bundler::FileUtils.touch 'timestamp'
+ # Bundler::FileUtils.touch Dir.glob('*.c'); system 'make'
+ #
+ def touch(list, noop: nil, verbose: nil, mtime: nil, nocreate: nil)
+ list = fu_list(list)
+ t = mtime
+ if verbose
+ fu_output_message "touch #{nocreate ? '-c ' : ''}#{t ? t.strftime('-t %Y%m%d%H%M.%S ') : ''}#{list.join ' '}"
+ end
+ return if noop
+ list.each do |path|
+ created = nocreate
+ begin
+ File.utime(t, t, path)
+ rescue Errno::ENOENT
+ raise if created
+ File.open(path, 'a') {
+ ;
+ }
+ created = true
+ retry if t
+ end
+ end
+ end
+ module_function :touch
+
+ private
+
+ module StreamUtils_
+ private
+
+ def fu_windows?
+ /mswin|mingw|bccwin|emx/ =~ RUBY_PLATFORM
+ end
+
+ def fu_copy_stream0(src, dest, blksize = nil) #:nodoc:
+ IO.copy_stream(src, dest)
+ end
+
+ def fu_stream_blksize(*streams)
+ streams.each do |s|
+ next unless s.respond_to?(:stat)
+ size = fu_blksize(s.stat)
+ return size if size
+ end
+ fu_default_blksize()
+ end
+
+ def fu_blksize(st)
+ s = st.blksize
+ return nil unless s
+ return nil if s == 0
+ s
+ end
+
+ def fu_default_blksize
+ 1024
+ end
+ end
+
+ include StreamUtils_
+ extend StreamUtils_
+
+ class Entry_ #:nodoc: internal use only
+ include StreamUtils_
+
+ def initialize(a, b = nil, deref = false)
+ @prefix = @rel = @path = nil
+ if b
+ @prefix = a
+ @rel = b
+ else
+ @path = a
+ end
+ @deref = deref
+ @stat = nil
+ @lstat = nil
+ end
+
+ def inspect
+ "\#<#{self.class} #{path()}>"
+ end
+
+ def path
+ if @path
+ File.path(@path)
+ else
+ join(@prefix, @rel)
+ end
+ end
+
+ def prefix
+ @prefix || @path
+ end
+
+ def rel
+ @rel
+ end
+
+ def dereference?
+ @deref
+ end
+
+ def exist?
+ begin
+ lstat
+ true
+ rescue Errno::ENOENT
+ false
+ end
+ end
+
+ def file?
+ s = lstat!
+ s and s.file?
+ end
+
+ def directory?
+ s = lstat!
+ s and s.directory?
+ end
+
+ def symlink?
+ s = lstat!
+ s and s.symlink?
+ end
+
+ def chardev?
+ s = lstat!
+ s and s.chardev?
+ end
+
+ def blockdev?
+ s = lstat!
+ s and s.blockdev?
+ end
+
+ def socket?
+ s = lstat!
+ s and s.socket?
+ end
+
+ def pipe?
+ s = lstat!
+ s and s.pipe?
+ end
+
+ S_IF_DOOR = 0xD000
+
+ def door?
+ s = lstat!
+ s and (s.mode & 0xF000 == S_IF_DOOR)
+ end
+
+ def entries
+ opts = {}
+ opts[:encoding] = ::Encoding::UTF_8 if fu_windows?
+ Dir.entries(path(), opts)\
+ .reject {|n| n == '.' or n == '..' }\
+ .map {|n| Entry_.new(prefix(), join(rel(), n.untaint)) }
+ end
+
+ def stat
+ return @stat if @stat
+ if lstat() and lstat().symlink?
+ @stat = File.stat(path())
+ else
+ @stat = lstat()
+ end
+ @stat
+ end
+
+ def stat!
+ return @stat if @stat
+ if lstat! and lstat!.symlink?
+ @stat = File.stat(path())
+ else
+ @stat = lstat!
+ end
+ @stat
+ rescue SystemCallError
+ nil
+ end
+
+ def lstat
+ if dereference?
+ @lstat ||= File.stat(path())
+ else
+ @lstat ||= File.lstat(path())
+ end
+ end
+
+ def lstat!
+ lstat()
+ rescue SystemCallError
+ nil
+ end
+
+ def chmod(mode)
+ if symlink?
+ File.lchmod mode, path() if have_lchmod?
+ else
+ File.chmod mode, path()
+ end
+ end
+
+ def chown(uid, gid)
+ if symlink?
+ File.lchown uid, gid, path() if have_lchown?
+ else
+ File.chown uid, gid, path()
+ end
+ end
+
+ def copy(dest)
+ lstat
+ case
+ when file?
+ copy_file dest
+ when directory?
+ if !File.exist?(dest) and descendant_directory?(dest, path)
+ raise ArgumentError, "cannot copy directory %s to itself %s" % [path, dest]
+ end
+ begin
+ Dir.mkdir dest
+ rescue
+ raise unless File.directory?(dest)
+ end
+ when symlink?
+ File.symlink File.readlink(path()), dest
+ when chardev?
+ raise "cannot handle device file" unless File.respond_to?(:mknod)
+ mknod dest, ?c, 0666, lstat().rdev
+ when blockdev?
+ raise "cannot handle device file" unless File.respond_to?(:mknod)
+ mknod dest, ?b, 0666, lstat().rdev
+ when socket?
+ raise "cannot handle socket" unless File.respond_to?(:mknod)
+ mknod dest, nil, lstat().mode, 0
+ when pipe?
+ raise "cannot handle FIFO" unless File.respond_to?(:mkfifo)
+ mkfifo dest, 0666
+ when door?
+ raise "cannot handle door: #{path()}"
+ else
+ raise "unknown file type: #{path()}"
+ end
+ end
+
+ def copy_file(dest)
+ File.open(path()) do |s|
+ File.open(dest, 'wb', s.stat.mode) do |f|
+ IO.copy_stream(s, f)
+ end
+ end
+ end
+
+ def copy_metadata(path)
+ st = lstat()
+ if !st.symlink?
+ File.utime st.atime, st.mtime, path
+ end
+ mode = st.mode
+ begin
+ if st.symlink?
+ begin
+ File.lchown st.uid, st.gid, path
+ rescue NotImplementedError
+ end
+ else
+ File.chown st.uid, st.gid, path
+ end
+ rescue Errno::EPERM, Errno::EACCES
+ # clear setuid/setgid
+ mode &= 01777
+ end
+ if st.symlink?
+ begin
+ File.lchmod mode, path
+ rescue NotImplementedError
+ end
+ else
+ File.chmod mode, path
+ end
+ end
+
+ def remove
+ if directory?
+ remove_dir1
+ else
+ remove_file
+ end
+ end
+
+ def remove_dir1
+ platform_support {
+ Dir.rmdir path().chomp(?/)
+ }
+ end
+
+ def remove_file
+ platform_support {
+ File.unlink path
+ }
+ end
+
+ def platform_support
+ return yield unless fu_windows?
+ first_time_p = true
+ begin
+ yield
+ rescue Errno::ENOENT
+ raise
+ rescue => err
+ if first_time_p
+ first_time_p = false
+ begin
+ File.chmod 0700, path() # Windows does not have symlink
+ retry
+ rescue SystemCallError
+ end
+ end
+ raise err
+ end
+ end
+
+ def preorder_traverse
+ stack = [self]
+ while ent = stack.pop
+ yield ent
+ stack.concat ent.entries.reverse if ent.directory?
+ end
+ end
+
+ alias traverse preorder_traverse
+
+ def postorder_traverse
+ if directory?
+ entries().each do |ent|
+ ent.postorder_traverse do |e|
+ yield e
+ end
+ end
+ end
+ ensure
+ yield self
+ end
+
+ def wrap_traverse(pre, post)
+ pre.call self
+ if directory?
+ entries.each do |ent|
+ ent.wrap_traverse pre, post
+ end
+ end
+ post.call self
+ end
+
+ private
+
+ $fileutils_rb_have_lchmod = nil
+
+ def have_lchmod?
+ # This is not MT-safe, but it does not matter.
+ if $fileutils_rb_have_lchmod == nil
+ $fileutils_rb_have_lchmod = check_have_lchmod?
+ end
+ $fileutils_rb_have_lchmod
+ end
+
+ def check_have_lchmod?
+ return false unless File.respond_to?(:lchmod)
+ File.lchmod 0
+ return true
+ rescue NotImplementedError
+ return false
+ end
+
+ $fileutils_rb_have_lchown = nil
+
+ def have_lchown?
+ # This is not MT-safe, but it does not matter.
+ if $fileutils_rb_have_lchown == nil
+ $fileutils_rb_have_lchown = check_have_lchown?
+ end
+ $fileutils_rb_have_lchown
+ end
+
+ def check_have_lchown?
+ return false unless File.respond_to?(:lchown)
+ File.lchown nil, nil
+ return true
+ rescue NotImplementedError
+ return false
+ end
+
+ 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)
+ end
+
+ if File::ALT_SEPARATOR
+ DIRECTORY_TERM = "(?=[/#{Regexp.quote(File::ALT_SEPARATOR)}]|\\z)"
+ else
+ DIRECTORY_TERM = "(?=/|\\z)"
+ end
+ SYSCASE = File::FNM_SYSCASE.nonzero? ? "-i" : ""
+
+ def descendant_directory?(descendant, ascendant)
+ /\A(?#{SYSCASE}:#{Regexp.quote(ascendant)})#{DIRECTORY_TERM}/ =~ File.dirname(descendant)
+ end
+ end # class Entry_
+
+ def fu_list(arg) #:nodoc:
+ [arg].flatten.map {|path| File.path(path) }
+ end
+ private_module_function :fu_list
+
+ def fu_each_src_dest(src, dest) #:nodoc:
+ fu_each_src_dest0(src, dest) do |s, d|
+ raise ArgumentError, "same file: #{s} and #{d}" if fu_same?(s, d)
+ yield s, d
+ end
+ end
+ private_module_function :fu_each_src_dest
+
+ def fu_each_src_dest0(src, dest) #:nodoc:
+ if tmp = Array.try_convert(src)
+ tmp.each do |s|
+ s = File.path(s)
+ yield s, File.join(dest, File.basename(s))
+ end
+ else
+ src = File.path(src)
+ if File.directory?(dest)
+ yield src, File.join(dest, File.basename(src))
+ else
+ yield src, File.path(dest)
+ end
+ end
+ end
+ private_module_function :fu_each_src_dest0
+
+ def fu_same?(a, b) #:nodoc:
+ File.identical?(a, b)
+ end
+ private_module_function :fu_same?
+
+ @fileutils_output = $stderr
+ @fileutils_label = ''
+
+ def fu_output_message(msg) #:nodoc:
+ @fileutils_output ||= $stderr
+ @fileutils_label ||= ''
+ @fileutils_output.puts @fileutils_label + msg
+ end
+ private_module_function :fu_output_message
+
+ # This hash table holds command options.
+ OPT_TABLE = {} #:nodoc: internal use only
+ (private_instance_methods & methods(false)).inject(OPT_TABLE) {|tbl, name|
+ (tbl[name.to_s] = instance_method(name).parameters).map! {|t, n| n if t == :key}.compact!
+ tbl
+ }
+
+ #
+ # Returns an Array of method names which have any options.
+ #
+ # p Bundler::FileUtils.commands #=> ["chmod", "cp", "cp_r", "install", ...]
+ #
+ def self.commands
+ OPT_TABLE.keys
+ end
+
+ #
+ # Returns an Array of option names.
+ #
+ # p Bundler::FileUtils.options #=> ["noop", "force", "verbose", "preserve", "mode"]
+ #
+ def self.options
+ OPT_TABLE.values.flatten.uniq.map {|sym| sym.to_s }
+ end
+
+ #
+ # 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
+ #
+ 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 option names of the method +mid+.
+ #
+ # p Bundler::FileUtils.options_of(:rm) #=> ["noop", "verbose", "force"]
+ #
+ def self.options_of(mid)
+ OPT_TABLE[mid.to_s].map {|sym| sym.to_s }
+ end
+
+ #
+ # Returns an Array of method names which have the option +opt+.
+ #
+ # p Bundler::FileUtils.collect_method(:preserve) #=> ["cp", "cp_r", "copy", "install"]
+ #
+ def self.collect_method(opt)
+ OPT_TABLE.keys.select {|m| OPT_TABLE[m].include?(opt) }
+ end
+
+ LOW_METHODS = singleton_methods(false) - collect_method(:noop).map(&:intern)
+ module LowMethods
+ private
+ def _do_nothing(*)end
+ ::Bundler::FileUtils::LOW_METHODS.map {|name| alias_method name, :_do_nothing}
+ end
+
+ METHODS = singleton_methods() - [:private_module_function,
+ :commands, :options, :have_option?, :options_of, :collect_method]
+
+ #
+ # 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.
+ #
+ module Verbose
+ include Bundler::FileUtils
+ @fileutils_output = $stderr
+ @fileutils_label = ''
+ names = ::Bundler::FileUtils.collect_method(:verbose)
+ names.each do |name|
+ module_eval(<<-EOS, __FILE__, __LINE__ + 1)
+ def #{name}(*args, **options)
+ super(*args, **options, verbose: true)
+ end
+ EOS
+ end
+ private(*names)
+ extend self
+ class << self
+ public(*::Bundler::FileUtils::METHODS)
+ end
+ end
+
+ #
+ # 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.
+ #
+ module NoWrite
+ include Bundler::FileUtils
+ include LowMethods
+ @fileutils_output = $stderr
+ @fileutils_label = ''
+ names = ::Bundler::FileUtils.collect_method(:noop)
+ names.each do |name|
+ module_eval(<<-EOS, __FILE__, __LINE__ + 1)
+ def #{name}(*args, **options)
+ super(*args, **options, noop: true)
+ end
+ EOS
+ end
+ private(*names)
+ extend self
+ class << self
+ public(*::Bundler::FileUtils::METHODS)
+ end
+ end
+
+ #
+ # This module has all methods of Bundler::FileUtils module, but never changes
+ # files/directories, with printing message before acting.
+ # This equates to passing the <tt>:noop</tt> and <tt>:verbose</tt> flag
+ # to methods in Bundler::FileUtils.
+ #
+ module DryRun
+ include Bundler::FileUtils
+ include LowMethods
+ @fileutils_output = $stderr
+ @fileutils_label = ''
+ names = ::Bundler::FileUtils.collect_method(:noop)
+ names.each do |name|
+ module_eval(<<-EOS, __FILE__, __LINE__ + 1)
+ def #{name}(*args, **options)
+ super(*args, **options, noop: true, verbose: true)
+ end
+ EOS
+ end
+ private(*names)
+ extend self
+ class << self
+ public(*::Bundler::FileUtils::METHODS)
+ end
+ end
+
+end
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo.rb b/lib/bundler/vendor/molinillo/lib/molinillo.rb
new file mode 100644
index 0000000000..9e2867144f
--- /dev/null
+++ b/lib/bundler/vendor/molinillo/lib/molinillo.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+require 'bundler/vendor/molinillo/lib/molinillo/compatibility'
+require 'bundler/vendor/molinillo/lib/molinillo/gem_metadata'
+require 'bundler/vendor/molinillo/lib/molinillo/errors'
+require 'bundler/vendor/molinillo/lib/molinillo/resolver'
+require 'bundler/vendor/molinillo/lib/molinillo/modules/ui'
+require 'bundler/vendor/molinillo/lib/molinillo/modules/specification_provider'
+
+# Bundler::Molinillo is a generic dependency resolution algorithm.
+module Bundler::Molinillo
+end
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/compatibility.rb b/lib/bundler/vendor/molinillo/lib/molinillo/compatibility.rb
new file mode 100644
index 0000000000..3eba8e4083
--- /dev/null
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/compatibility.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module Bundler::Molinillo
+ # Hacks needed for old Ruby versions.
+ module Compatibility
+ module_function
+
+ if [].respond_to?(:flat_map)
+ # Flat map
+ # @param [Enumerable] enum an enumerable object
+ # @block the block to flat-map with
+ # @return The enum, flat-mapped
+ def flat_map(enum, &blk)
+ enum.flat_map(&blk)
+ end
+ else
+ # Flat map
+ # @param [Enumerable] enum an enumerable object
+ # @block the block to flat-map with
+ # @return The enum, flat-mapped
+ def flat_map(enum, &blk)
+ enum.map(&blk).flatten(1)
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb b/lib/bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb
new file mode 100644
index 0000000000..bcacf35243
--- /dev/null
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+module Bundler::Molinillo
+ # @!visibility private
+ module Delegates
+ # Delegates all {Bundler::Molinillo::ResolutionState} methods to a `#state` property.
+ module ResolutionState
+ # (see Bundler::Molinillo::ResolutionState#name)
+ def name
+ current_state = state || Bundler::Molinillo::ResolutionState.empty
+ current_state.name
+ end
+
+ # (see Bundler::Molinillo::ResolutionState#requirements)
+ def requirements
+ current_state = state || Bundler::Molinillo::ResolutionState.empty
+ current_state.requirements
+ end
+
+ # (see Bundler::Molinillo::ResolutionState#activated)
+ def activated
+ current_state = state || Bundler::Molinillo::ResolutionState.empty
+ current_state.activated
+ end
+
+ # (see Bundler::Molinillo::ResolutionState#requirement)
+ def requirement
+ current_state = state || Bundler::Molinillo::ResolutionState.empty
+ current_state.requirement
+ end
+
+ # (see Bundler::Molinillo::ResolutionState#possibilities)
+ def possibilities
+ current_state = state || Bundler::Molinillo::ResolutionState.empty
+ current_state.possibilities
+ end
+
+ # (see Bundler::Molinillo::ResolutionState#depth)
+ def depth
+ current_state = state || Bundler::Molinillo::ResolutionState.empty
+ current_state.depth
+ end
+
+ # (see Bundler::Molinillo::ResolutionState#conflicts)
+ def conflicts
+ current_state = state || Bundler::Molinillo::ResolutionState.empty
+ current_state.conflicts
+ end
+
+ # (see Bundler::Molinillo::ResolutionState#unused_unwind_options)
+ def unused_unwind_options
+ current_state = state || Bundler::Molinillo::ResolutionState.empty
+ current_state.unused_unwind_options
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb b/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb
new file mode 100644
index 0000000000..ec9c770a28
--- /dev/null
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb
@@ -0,0 +1,81 @@
+# frozen_string_literal: true
+
+module Bundler::Molinillo
+ module Delegates
+ # Delegates all {Bundler::Molinillo::SpecificationProvider} methods to a
+ # `#specification_provider` property.
+ module SpecificationProvider
+ # (see Bundler::Molinillo::SpecificationProvider#search_for)
+ def search_for(dependency)
+ with_no_such_dependency_error_handling do
+ specification_provider.search_for(dependency)
+ end
+ end
+
+ # (see Bundler::Molinillo::SpecificationProvider#dependencies_for)
+ def dependencies_for(specification)
+ with_no_such_dependency_error_handling do
+ specification_provider.dependencies_for(specification)
+ end
+ end
+
+ # (see Bundler::Molinillo::SpecificationProvider#requirement_satisfied_by?)
+ def requirement_satisfied_by?(requirement, activated, spec)
+ with_no_such_dependency_error_handling do
+ specification_provider.requirement_satisfied_by?(requirement, activated, spec)
+ end
+ end
+
+ # (see Bundler::Molinillo::SpecificationProvider#name_for)
+ def name_for(dependency)
+ with_no_such_dependency_error_handling do
+ specification_provider.name_for(dependency)
+ end
+ end
+
+ # (see Bundler::Molinillo::SpecificationProvider#name_for_explicit_dependency_source)
+ def name_for_explicit_dependency_source
+ with_no_such_dependency_error_handling do
+ specification_provider.name_for_explicit_dependency_source
+ end
+ end
+
+ # (see Bundler::Molinillo::SpecificationProvider#name_for_locking_dependency_source)
+ def name_for_locking_dependency_source
+ with_no_such_dependency_error_handling do
+ specification_provider.name_for_locking_dependency_source
+ end
+ end
+
+ # (see Bundler::Molinillo::SpecificationProvider#sort_dependencies)
+ def sort_dependencies(dependencies, activated, conflicts)
+ with_no_such_dependency_error_handling do
+ specification_provider.sort_dependencies(dependencies, activated, conflicts)
+ end
+ end
+
+ # (see Bundler::Molinillo::SpecificationProvider#allow_missing?)
+ def allow_missing?(dependency)
+ with_no_such_dependency_error_handling do
+ specification_provider.allow_missing?(dependency)
+ end
+ end
+
+ private
+
+ # Ensures any raised {NoSuchDependencyError} has its
+ # {NoSuchDependencyError#required_by} set.
+ # @yield
+ def with_no_such_dependency_error_handling
+ yield
+ rescue NoSuchDependencyError => error
+ if state
+ vertex = activated.vertex_named(name_for(error.dependency))
+ error.required_by += vertex.incoming_edges.map { |e| e.origin.name }
+ error.required_by << name_for_explicit_dependency_source unless vertex.explicit_requirements.empty?
+ end
+ raise
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb
new file mode 100644
index 0000000000..677a8bd916
--- /dev/null
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb
@@ -0,0 +1,223 @@
+# frozen_string_literal: true
+
+require 'set'
+require 'tsort'
+
+require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/log'
+require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex'
+
+module Bundler::Molinillo
+ # A directed acyclic graph that is tuned to hold named dependencies
+ class DependencyGraph
+ include Enumerable
+
+ # Enumerates through the vertices of the graph.
+ # @return [Array<Vertex>] The graph's vertices.
+ def each
+ return vertices.values.each unless block_given?
+ vertices.values.each { |v| yield v }
+ end
+
+ include TSort
+
+ # @!visibility private
+ alias tsort_each_node each
+
+ # @!visibility private
+ def tsort_each_child(vertex, &block)
+ vertex.successors.each(&block)
+ end
+
+ # Topologically sorts the given vertices.
+ # @param [Enumerable<Vertex>] vertices the vertices to be sorted, which must
+ # all belong to the same graph.
+ # @return [Array<Vertex>] The sorted vertices.
+ def self.tsort(vertices)
+ TSort.tsort(
+ lambda { |b| vertices.each(&b) },
+ lambda { |v, &b| (v.successors & vertices).each(&b) }
+ )
+ end
+
+ # A directed edge of a {DependencyGraph}
+ # @attr [Vertex] origin The origin of the directed edge
+ # @attr [Vertex] destination The destination of the directed edge
+ # @attr [Object] requirement The requirement the directed edge represents
+ Edge = Struct.new(:origin, :destination, :requirement)
+
+ # @return [{String => Vertex}] the vertices of the dependency graph, keyed
+ # by {Vertex#name}
+ attr_reader :vertices
+
+ # @return [Log] the op log for this graph
+ attr_reader :log
+
+ # Initializes an empty dependency graph
+ def initialize
+ @vertices = {}
+ @log = Log.new
+ end
+
+ # Tags the current state of the dependency as the given tag
+ # @param [Object] tag an opaque tag for the current state of the graph
+ # @return [Void]
+ def tag(tag)
+ log.tag(self, tag)
+ end
+
+ # Rewinds the graph to the state tagged as `tag`
+ # @param [Object] tag the tag to rewind to
+ # @return [Void]
+ def rewind_to(tag)
+ log.rewind_to(self, tag)
+ end
+
+ # Initializes a copy of a {DependencyGraph}, ensuring that all {#vertices}
+ # are properly copied.
+ # @param [DependencyGraph] other the graph to copy.
+ def initialize_copy(other)
+ super
+ @vertices = {}
+ @log = other.log.dup
+ traverse = lambda do |new_v, old_v|
+ return if new_v.outgoing_edges.size == old_v.outgoing_edges.size
+ old_v.outgoing_edges.each do |edge|
+ destination = add_vertex(edge.destination.name, edge.destination.payload)
+ add_edge_no_circular(new_v, destination, edge.requirement)
+ traverse.call(destination, edge.destination)
+ end
+ end
+ other.vertices.each do |name, vertex|
+ new_vertex = add_vertex(name, vertex.payload, vertex.root?)
+ new_vertex.explicit_requirements.replace(vertex.explicit_requirements)
+ traverse.call(new_vertex, vertex)
+ end
+ end
+
+ # @return [String] a string suitable for debugging
+ def inspect
+ "#{self.class}:#{vertices.values.inspect}"
+ end
+
+ # @param [Hash] options options for dot output.
+ # @return [String] Returns a dot format representation of the graph
+ def to_dot(options = {})
+ edge_label = options.delete(:edge_label)
+ raise ArgumentError, "Unknown options: #{options.keys}" unless options.empty?
+
+ dot_vertices = []
+ dot_edges = []
+ vertices.each do |n, v|
+ dot_vertices << " #{n} [label=\"{#{n}|#{v.payload}}\"]"
+ v.outgoing_edges.each do |e|
+ label = edge_label ? edge_label.call(e) : e.requirement
+ dot_edges << " #{e.origin.name} -> #{e.destination.name} [label=#{label.to_s.dump}]"
+ end
+ end
+
+ dot_vertices.uniq!
+ dot_vertices.sort!
+ dot_edges.uniq!
+ dot_edges.sort!
+
+ dot = dot_vertices.unshift('digraph G {').push('') + dot_edges.push('}')
+ dot.join("\n")
+ end
+
+ # @return [Boolean] whether the two dependency graphs are equal, determined
+ # by a recursive traversal of each {#root_vertices} and its
+ # {Vertex#successors}
+ def ==(other)
+ return false unless other
+ return true if equal?(other)
+ vertices.each do |name, vertex|
+ other_vertex = other.vertex_named(name)
+ return false unless other_vertex
+ return false unless vertex.payload == other_vertex.payload
+ return false unless other_vertex.successors.to_set == vertex.successors.to_set
+ end
+ end
+
+ # @param [String] name
+ # @param [Object] payload
+ # @param [Array<String>] parent_names
+ # @param [Object] requirement the requirement that is requiring the child
+ # @return [void]
+ def add_child_vertex(name, payload, parent_names, requirement)
+ root = !parent_names.delete(nil) { true }
+ vertex = add_vertex(name, payload, root)
+ vertex.explicit_requirements << requirement if root
+ parent_names.each do |parent_name|
+ parent_vertex = vertex_named(parent_name)
+ add_edge(parent_vertex, vertex, requirement)
+ end
+ vertex
+ end
+
+ # Adds a vertex with the given name, or updates the existing one.
+ # @param [String] name
+ # @param [Object] payload
+ # @return [Vertex] the vertex that was added to `self`
+ def add_vertex(name, payload, root = false)
+ log.add_vertex(self, name, payload, root)
+ end
+
+ # Detaches the {#vertex_named} `name` {Vertex} from the graph, recursively
+ # removing any non-root vertices that were orphaned in the process
+ # @param [String] name
+ # @return [Array<Vertex>] the vertices which have been detached
+ def detach_vertex_named(name)
+ log.detach_vertex_named(self, name)
+ end
+
+ # @param [String] name
+ # @return [Vertex,nil] the vertex with the given name
+ def vertex_named(name)
+ vertices[name]
+ end
+
+ # @param [String] name
+ # @return [Vertex,nil] the root vertex with the given name
+ def root_vertex_named(name)
+ vertex = vertex_named(name)
+ vertex if vertex && vertex.root?
+ end
+
+ # Adds a new {Edge} to the dependency graph
+ # @param [Vertex] origin
+ # @param [Vertex] destination
+ # @param [Object] requirement the requirement that this edge represents
+ # @return [Edge] the added edge
+ def add_edge(origin, destination, requirement)
+ if destination.path_to?(origin)
+ raise CircularDependencyError.new([origin, destination])
+ end
+ add_edge_no_circular(origin, destination, requirement)
+ end
+
+ # Deletes an {Edge} from the dependency graph
+ # @param [Edge] edge
+ # @return [Void]
+ def delete_edge(edge)
+ log.delete_edge(self, edge.origin.name, edge.destination.name, edge.requirement)
+ end
+
+ # Sets the payload of the vertex with the given name
+ # @param [String] name the name of the vertex
+ # @param [Object] payload the payload
+ # @return [Void]
+ def set_payload(name, payload)
+ log.set_payload(self, name, payload)
+ end
+
+ private
+
+ # Adds a new {Edge} to the dependency graph without checking for
+ # circularity.
+ # @param (see #add_edge)
+ # @return (see #add_edge)
+ def add_edge_no_circular(origin, destination, requirement)
+ log.add_edge_no_circular(self, origin.name, destination.name, requirement)
+ end
+ end
+end
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb
new file mode 100644
index 0000000000..c04c7eec9c
--- /dev/null
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module Bundler::Molinillo
+ class DependencyGraph
+ # An action that modifies a {DependencyGraph} that is reversible.
+ # @abstract
+ class Action
+ # rubocop:disable Lint/UnusedMethodArgument
+
+ # @return [Symbol] The name of the action.
+ def self.action_name
+ raise 'Abstract'
+ end
+
+ # Performs the action on the given graph.
+ # @param [DependencyGraph] graph the graph to perform the action on.
+ # @return [Void]
+ def up(graph)
+ raise 'Abstract'
+ end
+
+ # Reverses the action on the given graph.
+ # @param [DependencyGraph] graph the graph to reverse the action on.
+ # @return [Void]
+ def down(graph)
+ raise 'Abstract'
+ end
+
+ # @return [Action,Nil] The previous action
+ attr_accessor :previous
+
+ # @return [Action,Nil] The next action
+ attr_accessor :next
+ end
+ end
+end
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb
new file mode 100644
index 0000000000..9849aea2fe
--- /dev/null
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/action'
+module Bundler::Molinillo
+ class DependencyGraph
+ # @!visibility private
+ # (see DependencyGraph#add_edge_no_circular)
+ class AddEdgeNoCircular < Action
+ # @!group Action
+
+ # (see Action.action_name)
+ def self.action_name
+ :add_vertex
+ end
+
+ # (see Action#up)
+ def up(graph)
+ edge = make_edge(graph)
+ edge.origin.outgoing_edges << edge
+ edge.destination.incoming_edges << edge
+ edge
+ end
+
+ # (see Action#down)
+ def down(graph)
+ edge = make_edge(graph)
+ delete_first(edge.origin.outgoing_edges, edge)
+ delete_first(edge.destination.incoming_edges, edge)
+ end
+
+ # @!group AddEdgeNoCircular
+
+ # @return [String] the name of the origin of the edge
+ attr_reader :origin
+
+ # @return [String] the name of the destination of the edge
+ attr_reader :destination
+
+ # @return [Object] the requirement that the edge represents
+ attr_reader :requirement
+
+ # @param [DependencyGraph] graph the graph to find vertices from
+ # @return [Edge] The edge this action adds
+ def make_edge(graph)
+ Edge.new(graph.vertex_named(origin), graph.vertex_named(destination), requirement)
+ end
+
+ # Initialize an action to add an edge to a dependency graph
+ # @param [String] origin the name of the origin of the edge
+ # @param [String] destination the name of the destination of the edge
+ # @param [Object] requirement the requirement that the edge represents
+ def initialize(origin, destination, requirement)
+ @origin = origin
+ @destination = destination
+ @requirement = requirement
+ end
+
+ private
+
+ def delete_first(array, item)
+ return unless index = array.index(item)
+ array.delete_at(index)
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb
new file mode 100644
index 0000000000..0a1e08255b
--- /dev/null
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/action'
+module Bundler::Molinillo
+ class DependencyGraph
+ # @!visibility private
+ # (see DependencyGraph#add_vertex)
+ class AddVertex < Action # :nodoc:
+ # @!group Action
+
+ # (see Action.action_name)
+ def self.action_name
+ :add_vertex
+ end
+
+ # (see Action#up)
+ def up(graph)
+ if existing = graph.vertices[name]
+ @existing_payload = existing.payload
+ @existing_root = existing.root
+ end
+ vertex = existing || Vertex.new(name, payload)
+ graph.vertices[vertex.name] = vertex
+ vertex.payload ||= payload
+ vertex.root ||= root
+ vertex
+ end
+
+ # (see Action#down)
+ def down(graph)
+ if defined?(@existing_payload)
+ vertex = graph.vertices[name]
+ vertex.payload = @existing_payload
+ vertex.root = @existing_root
+ else
+ graph.vertices.delete(name)
+ end
+ end
+
+ # @!group AddVertex
+
+ # @return [String] the name of the vertex
+ attr_reader :name
+
+ # @return [Object] the payload for the vertex
+ attr_reader :payload
+
+ # @return [Boolean] whether the vertex is root or not
+ attr_reader :root
+
+ # Initialize an action to add a vertex to a dependency graph
+ # @param [String] name the name of the vertex
+ # @param [Object] payload the payload for the vertex
+ # @param [Boolean] root whether the vertex is root or not
+ def initialize(name, payload, root)
+ @name = name
+ @payload = payload
+ @root = root
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb
new file mode 100644
index 0000000000..1d9f4b327d
--- /dev/null
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/action'
+module Bundler::Molinillo
+ class DependencyGraph
+ # @!visibility private
+ # (see DependencyGraph#delete_edge)
+ class DeleteEdge < Action
+ # @!group Action
+
+ # (see Action.action_name)
+ def self.action_name
+ :delete_edge
+ end
+
+ # (see Action#up)
+ def up(graph)
+ edge = make_edge(graph)
+ edge.origin.outgoing_edges.delete(edge)
+ edge.destination.incoming_edges.delete(edge)
+ end
+
+ # (see Action#down)
+ def down(graph)
+ edge = make_edge(graph)
+ edge.origin.outgoing_edges << edge
+ edge.destination.incoming_edges << edge
+ edge
+ end
+
+ # @!group DeleteEdge
+
+ # @return [String] the name of the origin of the edge
+ attr_reader :origin_name
+
+ # @return [String] the name of the destination of the edge
+ attr_reader :destination_name
+
+ # @return [Object] the requirement that the edge represents
+ attr_reader :requirement
+
+ # @param [DependencyGraph] graph the graph to find vertices from
+ # @return [Edge] The edge this action adds
+ def make_edge(graph)
+ Edge.new(
+ graph.vertex_named(origin_name),
+ graph.vertex_named(destination_name),
+ requirement
+ )
+ end
+
+ # Initialize an action to add an edge to a dependency graph
+ # @param [String] origin_name the name of the origin of the edge
+ # @param [String] destination_name the name of the destination of the edge
+ # @param [Object] requirement the requirement that the edge represents
+ def initialize(origin_name, destination_name, requirement)
+ @origin_name = origin_name
+ @destination_name = destination_name
+ @requirement = requirement
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb
new file mode 100644
index 0000000000..385dcbdd06
--- /dev/null
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/action'
+module Bundler::Molinillo
+ class DependencyGraph
+ # @!visibility private
+ # @see DependencyGraph#detach_vertex_named
+ class DetachVertexNamed < Action
+ # @!group Action
+
+ # (see Action#name)
+ def self.action_name
+ :add_vertex
+ end
+
+ # (see Action#up)
+ def up(graph)
+ return [] unless @vertex = graph.vertices.delete(name)
+
+ removed_vertices = [@vertex]
+ @vertex.outgoing_edges.each do |e|
+ v = e.destination
+ v.incoming_edges.delete(e)
+ if !v.root? && v.incoming_edges.empty?
+ removed_vertices.concat graph.detach_vertex_named(v.name)
+ end
+ end
+
+ @vertex.incoming_edges.each do |e|
+ v = e.origin
+ v.outgoing_edges.delete(e)
+ end
+
+ removed_vertices
+ end
+
+ # (see Action#down)
+ def down(graph)
+ return unless @vertex
+ graph.vertices[@vertex.name] = @vertex
+ @vertex.outgoing_edges.each do |e|
+ e.destination.incoming_edges << e
+ end
+ @vertex.incoming_edges.each do |e|
+ e.origin.outgoing_edges << e
+ end
+ end
+
+ # @!group DetachVertexNamed
+
+ # @return [String] the name of the vertex to detach
+ attr_reader :name
+
+ # Initialize an action to detach a vertex from a dependency graph
+ # @param [String] name the name of the vertex to detach
+ def initialize(name)
+ @name = name
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb
new file mode 100644
index 0000000000..8582dd19c1
--- /dev/null
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb
@@ -0,0 +1,126 @@
+# frozen_string_literal: true
+
+require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular'
+require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex'
+require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge'
+require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named'
+require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload'
+require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag'
+
+module Bundler::Molinillo
+ class DependencyGraph
+ # A log for dependency graph actions
+ class Log
+ # Initializes an empty log
+ def initialize
+ @current_action = @first_action = nil
+ end
+
+ # @!macro [new] action
+ # {include:DependencyGraph#$0}
+ # @param [Graph] graph the graph to perform the action on
+ # @param (see DependencyGraph#$0)
+ # @return (see DependencyGraph#$0)
+
+ # @macro action
+ def tag(graph, tag)
+ push_action(graph, Tag.new(tag))
+ end
+
+ # @macro action
+ def add_vertex(graph, name, payload, root)
+ push_action(graph, AddVertex.new(name, payload, root))
+ end
+
+ # @macro action
+ def detach_vertex_named(graph, name)
+ push_action(graph, DetachVertexNamed.new(name))
+ end
+
+ # @macro action
+ def add_edge_no_circular(graph, origin, destination, requirement)
+ push_action(graph, AddEdgeNoCircular.new(origin, destination, requirement))
+ end
+
+ # {include:DependencyGraph#delete_edge}
+ # @param [Graph] graph the graph to perform the action on
+ # @param [String] origin_name
+ # @param [String] destination_name
+ # @param [Object] requirement
+ # @return (see DependencyGraph#delete_edge)
+ def delete_edge(graph, origin_name, destination_name, requirement)
+ push_action(graph, DeleteEdge.new(origin_name, destination_name, requirement))
+ end
+
+ # @macro action
+ def set_payload(graph, name, payload)
+ push_action(graph, SetPayload.new(name, payload))
+ end
+
+ # Pops the most recent action from the log and undoes the action
+ # @param [DependencyGraph] graph
+ # @return [Action] the action that was popped off the log
+ def pop!(graph)
+ return unless action = @current_action
+ unless @current_action = action.previous
+ @first_action = nil
+ end
+ action.down(graph)
+ action
+ end
+
+ extend Enumerable
+
+ # @!visibility private
+ # Enumerates each action in the log
+ # @yield [Action]
+ def each
+ return enum_for unless block_given?
+ action = @first_action
+ loop do
+ break unless action
+ yield action
+ action = action.next
+ end
+ self
+ end
+
+ # @!visibility private
+ # Enumerates each action in the log in reverse order
+ # @yield [Action]
+ def reverse_each
+ return enum_for(:reverse_each) unless block_given?
+ action = @current_action
+ loop do
+ break unless action
+ yield action
+ action = action.previous
+ end
+ self
+ end
+
+ # @macro action
+ def rewind_to(graph, tag)
+ loop do
+ action = pop!(graph)
+ raise "No tag #{tag.inspect} found" unless action
+ break if action.class.action_name == :tag && action.tag == tag
+ end
+ end
+
+ private
+
+ # Adds the given action to the log, running the action
+ # @param [DependencyGraph] graph
+ # @param [Action] action
+ # @return The value returned by `action.up`
+ def push_action(graph, action)
+ action.previous = @current_action
+ @current_action.next = action if @current_action
+ @current_action = action
+ @first_action ||= action
+ action.up(graph)
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb
new file mode 100644
index 0000000000..37286d104a
--- /dev/null
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/action'
+module Bundler::Molinillo
+ class DependencyGraph
+ # @!visibility private
+ # @see DependencyGraph#set_payload
+ class SetPayload < Action # :nodoc:
+ # @!group Action
+
+ # (see Action.action_name)
+ def self.action_name
+ :set_payload
+ end
+
+ # (see Action#up)
+ def up(graph)
+ vertex = graph.vertex_named(name)
+ @old_payload = vertex.payload
+ vertex.payload = payload
+ end
+
+ # (see Action#down)
+ def down(graph)
+ graph.vertex_named(name).payload = @old_payload
+ end
+
+ # @!group SetPayload
+
+ # @return [String] the name of the vertex
+ attr_reader :name
+
+ # @return [Object] the payload for the vertex
+ attr_reader :payload
+
+ # Initialize an action to add set the payload for a vertex in a dependency
+ # graph
+ # @param [String] name the name of the vertex
+ # @param [Object] payload the payload for the vertex
+ def initialize(name, payload)
+ @name = name
+ @payload = payload
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb
new file mode 100644
index 0000000000..d6ad16e07a
--- /dev/null
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/action'
+module Bundler::Molinillo
+ class DependencyGraph
+ # @!visibility private
+ # @see DependencyGraph#tag
+ class Tag < Action
+ # @!group Action
+
+ # (see Action.action_name)
+ def self.action_name
+ :tag
+ end
+
+ # (see Action#up)
+ def up(_graph)
+ end
+
+ # (see Action#down)
+ def down(_graph)
+ end
+
+ # @!group Tag
+
+ # @return [Object] An opaque tag
+ attr_reader :tag
+
+ # Initialize an action to tag a state of a dependency graph
+ # @param [Object] tag an opaque tag
+ def initialize(tag)
+ @tag = tag
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb
new file mode 100644
index 0000000000..7ecdc4b65a
--- /dev/null
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb
@@ -0,0 +1,136 @@
+# frozen_string_literal: true
+
+module Bundler::Molinillo
+ class DependencyGraph
+ # A vertex in a {DependencyGraph} that encapsulates a {#name} and a
+ # {#payload}
+ class Vertex
+ # @return [String] the name of the vertex
+ attr_accessor :name
+
+ # @return [Object] the payload the vertex holds
+ attr_accessor :payload
+
+ # @return [Array<Object>] the explicit requirements that required
+ # this vertex
+ attr_reader :explicit_requirements
+
+ # @return [Boolean] whether the vertex is considered a root vertex
+ attr_accessor :root
+ alias root? root
+
+ # Initializes a vertex with the given name and payload.
+ # @param [String] name see {#name}
+ # @param [Object] payload see {#payload}
+ def initialize(name, payload)
+ @name = name.frozen? ? name : name.dup.freeze
+ @payload = payload
+ @explicit_requirements = []
+ @outgoing_edges = []
+ @incoming_edges = []
+ end
+
+ # @return [Array<Object>] all of the requirements that required
+ # this vertex
+ def requirements
+ (incoming_edges.map(&:requirement) + explicit_requirements).uniq
+ end
+
+ # @return [Array<Edge>] the edges of {#graph} that have `self` as their
+ # {Edge#origin}
+ attr_accessor :outgoing_edges
+
+ # @return [Array<Edge>] the edges of {#graph} that have `self` as their
+ # {Edge#destination}
+ attr_accessor :incoming_edges
+
+ # @return [Array<Vertex>] the vertices of {#graph} that have an edge with
+ # `self` as their {Edge#destination}
+ def predecessors
+ incoming_edges.map(&:origin)
+ end
+
+ # @return [Array<Vertex>] the vertices of {#graph} where `self` is a
+ # {#descendent?}
+ def recursive_predecessors
+ vertices = predecessors
+ vertices += Compatibility.flat_map(vertices, &:recursive_predecessors)
+ vertices.uniq!
+ vertices
+ end
+
+ # @return [Array<Vertex>] the vertices of {#graph} that have an edge with
+ # `self` as their {Edge#origin}
+ def successors
+ outgoing_edges.map(&:destination)
+ end
+
+ # @return [Array<Vertex>] the vertices of {#graph} where `self` is an
+ # {#ancestor?}
+ def recursive_successors
+ vertices = successors
+ vertices += Compatibility.flat_map(vertices, &:recursive_successors)
+ vertices.uniq!
+ vertices
+ end
+
+ # @return [String] a string suitable for debugging
+ def inspect
+ "#{self.class}:#{name}(#{payload.inspect})"
+ end
+
+ # @return [Boolean] whether the two vertices are equal, determined
+ # by a recursive traversal of each {Vertex#successors}
+ def ==(other)
+ return true if equal?(other)
+ shallow_eql?(other) &&
+ successors.to_set == other.successors.to_set
+ end
+
+ # @param [Vertex] other the other vertex to compare to
+ # @return [Boolean] whether the two vertices are equal, determined
+ # solely by {#name} and {#payload} equality
+ def shallow_eql?(other)
+ return true if equal?(other)
+ other &&
+ name == other.name &&
+ payload == other.payload
+ end
+
+ alias eql? ==
+
+ # @return [Fixnum] a hash for the vertex based upon its {#name}
+ def hash
+ name.hash
+ end
+
+ # Is there a path from `self` to `other` following edges in the
+ # dependency graph?
+ # @return true iff there is a path following edges within this {#graph}
+ def path_to?(other)
+ _path_to?(other)
+ end
+
+ alias descendent? path_to?
+
+ # @param [Vertex] other the vertex to check if there's a path to
+ # @param [Set<Vertex>] visited the vertices of {#graph} that have been visited
+ # @return [Boolean] whether there is a path to `other` from `self`
+ def _path_to?(other, visited = Set.new)
+ return false unless visited.add?(self)
+ return true if equal?(other)
+ successors.any? { |v| v._path_to?(other, visited) }
+ end
+ protected :_path_to?
+
+ # Is there a path from `other` to `self` following edges in the
+ # dependency graph?
+ # @return true iff there is a path following edges within this {#graph}
+ def ancestor?(other)
+ other.path_to?(self)
+ end
+
+ alias is_reachable_from? ancestor?
+ end
+ end
+end
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb b/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb
new file mode 100644
index 0000000000..ce0931f103
--- /dev/null
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb
@@ -0,0 +1,143 @@
+# frozen_string_literal: true
+
+module Bundler::Molinillo
+ # An error that occurred during the resolution process
+ class ResolverError < StandardError; end
+
+ # An error caused by searching for a dependency that is completely unknown,
+ # i.e. has no versions available whatsoever.
+ class NoSuchDependencyError < ResolverError
+ # @return [Object] the dependency that could not be found
+ attr_accessor :dependency
+
+ # @return [Array<Object>] the specifications that depended upon {#dependency}
+ attr_accessor :required_by
+
+ # Initializes a new error with the given missing dependency.
+ # @param [Object] dependency @see {#dependency}
+ # @param [Array<Object>] required_by @see {#required_by}
+ def initialize(dependency, required_by = [])
+ @dependency = dependency
+ @required_by = required_by.uniq
+ super()
+ end
+
+ # The error message for the missing dependency, including the specifications
+ # that had this dependency.
+ def message
+ sources = required_by.map { |r| "`#{r}`" }.join(' and ')
+ message = "Unable to find a specification for `#{dependency}`"
+ message += " depended upon by #{sources}" unless sources.empty?
+ message
+ end
+ end
+
+ # An error caused by attempting to fulfil a dependency that was circular
+ #
+ # @note This exception will be thrown iff a {Vertex} is added to a
+ # {DependencyGraph} that has a {DependencyGraph::Vertex#path_to?} an
+ # existing {DependencyGraph::Vertex}
+ class CircularDependencyError < ResolverError
+ # [Set<Object>] the dependencies responsible for causing the error
+ attr_reader :dependencies
+
+ # Initializes a new error with the given circular vertices.
+ # @param [Array<DependencyGraph::Vertex>] vertices the vertices in the dependency
+ # that caused the error
+ def initialize(vertices)
+ super "There is a circular dependency between #{vertices.map(&:name).join(' and ')}"
+ @dependencies = vertices.map { |vertex| vertex.payload.possibilities.last }.to_set
+ end
+ end
+
+ # An error caused by conflicts in version
+ class VersionConflict < ResolverError
+ # @return [{String => Resolution::Conflict}] the conflicts that caused
+ # resolution to fail
+ attr_reader :conflicts
+
+ # @return [SpecificationProvider] the specification provider used during
+ # resolution
+ attr_reader :specification_provider
+
+ # Initializes a new error with the given version conflicts.
+ # @param [{String => Resolution::Conflict}] conflicts see {#conflicts}
+ # @param [SpecificationProvider] specification_provider see {#specification_provider}
+ def initialize(conflicts, specification_provider)
+ pairs = []
+ Compatibility.flat_map(conflicts.values.flatten, &:requirements).each do |conflicting|
+ conflicting.each do |source, conflict_requirements|
+ conflict_requirements.each do |c|
+ pairs << [c, source]
+ end
+ end
+ end
+
+ super "Unable to satisfy the following requirements:\n\n" \
+ "#{pairs.map { |r, d| "- `#{r}` required by `#{d}`" }.join("\n")}"
+
+ @conflicts = conflicts
+ @specification_provider = specification_provider
+ end
+
+ require 'bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider'
+ include Delegates::SpecificationProvider
+
+ # @return [String] An error message that includes requirement trees,
+ # which is much more detailed & customizable than the default message
+ # @param [Hash] opts the options to create a message with.
+ # @option opts [String] :solver_name The user-facing name of the solver
+ # @option opts [String] :possibility_type The generic name of a possibility
+ # @option opts [Proc] :reduce_trees A proc that reduced the list of requirement trees
+ # @option opts [Proc] :printable_requirement A proc that pretty-prints requirements
+ # @option opts [Proc] :additional_message_for_conflict A proc that appends additional
+ # messages for each conflict
+ # @option opts [Proc] :version_for_spec A proc that returns the version number for a
+ # possibility
+ def message_with_trees(opts = {})
+ solver_name = opts.delete(:solver_name) { self.class.name.split('::').first }
+ possibility_type = opts.delete(:possibility_type) { 'possibility named' }
+ reduce_trees = opts.delete(:reduce_trees) { proc { |trees| trees.uniq.sort_by(&:to_s) } }
+ printable_requirement = opts.delete(:printable_requirement) { proc { |req| req.to_s } }
+ additional_message_for_conflict = opts.delete(:additional_message_for_conflict) { proc {} }
+ version_for_spec = opts.delete(:version_for_spec) { proc(&:to_s) }
+ incompatible_version_message_for_conflict = opts.delete(:incompatible_version_message_for_conflict) do
+ proc do |name, _conflict|
+ %(#{solver_name} could not find compatible versions for #{possibility_type} "#{name}":)
+ end
+ end
+
+ conflicts.sort.reduce(''.dup) do |o, (name, conflict)|
+ o << "\n" << incompatible_version_message_for_conflict.call(name, conflict) << "\n"
+ if conflict.locked_requirement
+ o << %( In snapshot (#{name_for_locking_dependency_source}):\n)
+ o << %( #{printable_requirement.call(conflict.locked_requirement)}\n)
+ o << %(\n)
+ end
+ o << %( In #{name_for_explicit_dependency_source}:\n)
+ trees = reduce_trees.call(conflict.requirement_trees)
+
+ o << trees.map do |tree|
+ t = ''.dup
+ depth = 2
+ tree.each do |req|
+ t << ' ' * depth << req.to_s
+ unless tree.last == req
+ if spec = conflict.activated_by_name[name_for(req)]
+ t << %( was resolved to #{version_for_spec.call(spec)}, which)
+ end
+ t << %( depends on)
+ end
+ t << %(\n)
+ depth += 1
+ end
+ t
+ end.join("\n")
+
+ additional_message_for_conflict.call(o, name, conflict)
+
+ o
+ end.strip
+ end
+ end
+end
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb b/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb
new file mode 100644
index 0000000000..73f8fbf2ac
--- /dev/null
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+module Bundler::Molinillo
+ # The version of Bundler::Molinillo.
+ VERSION = '0.6.6'.freeze
+end
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb b/lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb
new file mode 100644
index 0000000000..fa094c1981
--- /dev/null
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb
@@ -0,0 +1,101 @@
+# frozen_string_literal: true
+
+module Bundler::Molinillo
+ # Provides information about specifcations and dependencies to the resolver,
+ # allowing the {Resolver} class to remain generic while still providing power
+ # and flexibility.
+ #
+ # This module contains the methods that users of Bundler::Molinillo must to implement,
+ # using knowledge of their own model classes.
+ module SpecificationProvider
+ # Search for the specifications that match the given dependency.
+ # The specifications in the returned array will be considered in reverse
+ # order, so the latest version ought to be last.
+ # @note This method should be 'pure', i.e. the return value should depend
+ # only on the `dependency` parameter.
+ #
+ # @param [Object] dependency
+ # @return [Array<Object>] the specifications that satisfy the given
+ # `dependency`.
+ def search_for(dependency)
+ []
+ end
+
+ # Returns the dependencies of `specification`.
+ # @note This method should be 'pure', i.e. the return value should depend
+ # only on the `specification` parameter.
+ #
+ # @param [Object] specification
+ # @return [Array<Object>] the dependencies that are required by the given
+ # `specification`.
+ def dependencies_for(specification)
+ []
+ end
+
+ # Determines whether the given `requirement` is satisfied by the given
+ # `spec`, in the context of the current `activated` dependency graph.
+ #
+ # @param [Object] requirement
+ # @param [DependencyGraph] activated the current dependency graph in the
+ # resolution process.
+ # @param [Object] spec
+ # @return [Boolean] whether `requirement` is satisfied by `spec` in the
+ # context of the current `activated` dependency graph.
+ def requirement_satisfied_by?(requirement, activated, spec)
+ true
+ end
+
+ # Returns the name for the given `dependency`.
+ # @note This method should be 'pure', i.e. the return value should depend
+ # only on the `dependency` parameter.
+ #
+ # @param [Object] dependency
+ # @return [String] the name for the given `dependency`.
+ def name_for(dependency)
+ dependency.to_s
+ end
+
+ # @return [String] the name of the source of explicit dependencies, i.e.
+ # those passed to {Resolver#resolve} directly.
+ def name_for_explicit_dependency_source
+ 'user-specified dependency'
+ end
+
+ # @return [String] the name of the source of 'locked' dependencies, i.e.
+ # those passed to {Resolver#resolve} directly as the `base`
+ def name_for_locking_dependency_source
+ 'Lockfile'
+ end
+
+ # Sort dependencies so that the ones that are easiest to resolve are first.
+ # Easiest to resolve is (usually) defined by:
+ # 1) Is this dependency already activated?
+ # 2) How relaxed are the requirements?
+ # 3) Are there any conflicts for this dependency?
+ # 4) How many possibilities are there to satisfy this dependency?
+ #
+ # @param [Array<Object>] dependencies
+ # @param [DependencyGraph] activated the current dependency graph in the
+ # resolution process.
+ # @param [{String => Array<Conflict>}] conflicts
+ # @return [Array<Object>] a sorted copy of `dependencies`.
+ def sort_dependencies(dependencies, activated, conflicts)
+ dependencies.sort_by do |dependency|
+ name = name_for(dependency)
+ [
+ activated.vertex_named(name).payload ? 0 : 1,
+ conflicts[name] ? 0 : 1,
+ ]
+ end
+ end
+
+ # Returns whether this dependency, which has no possible matching
+ # specifications, can safely be ignored.
+ #
+ # @param [Object] dependency
+ # @return [Boolean] whether this dependency can safely be skipped.
+ def allow_missing?(dependency)
+ false
+ end
+ end
+end
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rb b/lib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rb
new file mode 100644
index 0000000000..a166bc6991
--- /dev/null
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rb
@@ -0,0 +1,67 @@
+# frozen_string_literal: true
+
+module Bundler::Molinillo
+ # Conveys information about the resolution process to a user.
+ module UI
+ # The {IO} object that should be used to print output. `STDOUT`, by default.
+ #
+ # @return [IO]
+ def output
+ STDOUT
+ end
+
+ # Called roughly every {#progress_rate}, this method should convey progress
+ # to the user.
+ #
+ # @return [void]
+ def indicate_progress
+ output.print '.' unless debug?
+ end
+
+ # How often progress should be conveyed to the user via
+ # {#indicate_progress}, in seconds. A third of a second, by default.
+ #
+ # @return [Float]
+ def progress_rate
+ 0.33
+ end
+
+ # Called before resolution begins.
+ #
+ # @return [void]
+ def before_resolution
+ output.print 'Resolving dependencies...'
+ end
+
+ # Called after resolution ends (either successfully or with an error).
+ # By default, prints a newline.
+ #
+ # @return [void]
+ def after_resolution
+ output.puts
+ end
+
+ # Conveys debug information to the user.
+ #
+ # @param [Integer] depth the current depth of the resolution process.
+ # @return [void]
+ def debug(depth = 0)
+ if debug?
+ debug_info = yield
+ debug_info = debug_info.inspect unless debug_info.is_a?(String)
+ debug_info = debug_info.split("\n").map { |s| ":#{depth.to_s.rjust 4}: #{s}" }
+ output.puts debug_info
+ end
+ end
+
+ # Whether or not debug messages should be printed.
+ # By default, whether or not the `MOLINILLO_DEBUG` environment variable is
+ # set.
+ #
+ # @return [Boolean]
+ def debug?
+ return @debug_mode if defined?(@debug_mode)
+ @debug_mode = ENV['MOLINILLO_DEBUG']
+ end
+ end
+end
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb b/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb
new file mode 100644
index 0000000000..0eb665d17a
--- /dev/null
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb
@@ -0,0 +1,837 @@
+# frozen_string_literal: true
+
+module Bundler::Molinillo
+ class Resolver
+ # A specific resolution from a given {Resolver}
+ class Resolution
+ # A conflict that the resolution process encountered
+ # @attr [Object] requirement the requirement that immediately led to the conflict
+ # @attr [{String,Nil=>[Object]}] requirements the requirements that caused the conflict
+ # @attr [Object, nil] existing the existing spec that was in conflict with
+ # the {#possibility}
+ # @attr [Object] possibility_set the set of specs that was unable to be
+ # activated due to a conflict.
+ # @attr [Object] locked_requirement the relevant locking requirement.
+ # @attr [Array<Array<Object>>] requirement_trees the different requirement
+ # trees that led to every requirement for the conflicting name.
+ # @attr [{String=>Object}] activated_by_name the already-activated specs.
+ # @attr [Object] underlying_error an error that has occurred during resolution, and
+ # will be raised at the end of it if no resolution is found.
+ Conflict = Struct.new(
+ :requirement,
+ :requirements,
+ :existing,
+ :possibility_set,
+ :locked_requirement,
+ :requirement_trees,
+ :activated_by_name,
+ :underlying_error
+ )
+
+ class Conflict
+ # @return [Object] a spec that was unable to be activated due to a conflict
+ def possibility
+ possibility_set && possibility_set.latest_version
+ end
+ end
+
+ # A collection of possibility states that share the same dependencies
+ # @attr [Array] dependencies the dependencies for this set of possibilities
+ # @attr [Array] possibilities the possibilities
+ PossibilitySet = Struct.new(:dependencies, :possibilities)
+
+ class PossibilitySet
+ # String representation of the possibility set, for debugging
+ def to_s
+ "[#{possibilities.join(', ')}]"
+ end
+
+ # @return [Object] most up-to-date dependency in the possibility set
+ def latest_version
+ possibilities.last
+ end
+ end
+
+ # Details of the state to unwind to when a conflict occurs, and the cause of the unwind
+ # @attr [Integer] state_index the index of the state to unwind to
+ # @attr [Object] state_requirement the requirement of the state we're unwinding to
+ # @attr [Array] requirement_tree for the requirement we're relaxing
+ # @attr [Array] conflicting_requirements the requirements that combined to cause the conflict
+ # @attr [Array] requirement_trees for the conflict
+ # @attr [Array] requirements_unwound_to_instead array of unwind requirements that were chosen over this unwind
+ UnwindDetails = Struct.new(
+ :state_index,
+ :state_requirement,
+ :requirement_tree,
+ :conflicting_requirements,
+ :requirement_trees,
+ :requirements_unwound_to_instead
+ )
+
+ class UnwindDetails
+ include Comparable
+
+ # We compare UnwindDetails when choosing which state to unwind to. If
+ # two options have the same state_index we prefer the one most
+ # removed from a requirement that caused the conflict. Both options
+ # would unwind to the same state, but a `grandparent` option will
+ # filter out fewer of its possibilities after doing so - where a state
+ # is both a `parent` and a `grandparent` to requirements that have
+ # caused a conflict this is the correct behaviour.
+ # @param [UnwindDetail] other UnwindDetail to be compared
+ # @return [Integer] integer specifying ordering
+ def <=>(other)
+ if state_index > other.state_index
+ 1
+ elsif state_index == other.state_index
+ reversed_requirement_tree_index <=> other.reversed_requirement_tree_index
+ else
+ -1
+ end
+ end
+
+ # @return [Integer] index of state requirement in reversed requirement tree
+ # (the conflicting requirement itself will be at position 0)
+ def reversed_requirement_tree_index
+ @reversed_requirement_tree_index ||=
+ if state_requirement
+ requirement_tree.reverse.index(state_requirement)
+ else
+ 999_999
+ end
+ end
+
+ # @return [Boolean] where the requirement of the state we're unwinding
+ # to directly caused the conflict. Note: in this case, it is
+ # impossible for the state we're unwinding to to be a parent of
+ # any of the other conflicting requirements (or we would have
+ # circularity)
+ def unwinding_to_primary_requirement?
+ requirement_tree.last == state_requirement
+ end
+
+ # @return [Array] array of sub-dependencies to avoid when choosing a
+ # new possibility for the state we've unwound to. Only relevant for
+ # non-primary unwinds
+ def sub_dependencies_to_avoid
+ @requirements_to_avoid ||=
+ requirement_trees.map do |tree|
+ index = tree.index(state_requirement)
+ tree[index + 1] if index
+ end.compact
+ end
+
+ # @return [Array] array of all the requirements that led to the need for
+ # this unwind
+ def all_requirements
+ @all_requirements ||= requirement_trees.flatten(1)
+ end
+ end
+
+ # @return [SpecificationProvider] the provider that knows about
+ # dependencies, requirements, specifications, versions, etc.
+ attr_reader :specification_provider
+
+ # @return [UI] the UI that knows how to communicate feedback about the
+ # resolution process back to the user
+ attr_reader :resolver_ui
+
+ # @return [DependencyGraph] the base dependency graph to which
+ # dependencies should be 'locked'
+ attr_reader :base
+
+ # @return [Array] the dependencies that were explicitly required
+ attr_reader :original_requested
+
+ # Initializes a new resolution.
+ # @param [SpecificationProvider] specification_provider
+ # see {#specification_provider}
+ # @param [UI] resolver_ui see {#resolver_ui}
+ # @param [Array] requested see {#original_requested}
+ # @param [DependencyGraph] base see {#base}
+ def initialize(specification_provider, resolver_ui, requested, base)
+ @specification_provider = specification_provider
+ @resolver_ui = resolver_ui
+ @original_requested = requested
+ @base = base
+ @states = []
+ @iteration_counter = 0
+ @parents_of = Hash.new { |h, k| h[k] = [] }
+ end
+
+ # Resolves the {#original_requested} dependencies into a full dependency
+ # graph
+ # @raise [ResolverError] if successful resolution is impossible
+ # @return [DependencyGraph] the dependency graph of successfully resolved
+ # dependencies
+ def resolve
+ start_resolution
+
+ while state
+ break if !state.requirement && state.requirements.empty?
+ indicate_progress
+ if state.respond_to?(:pop_possibility_state) # DependencyState
+ debug(depth) { "Creating possibility state for #{requirement} (#{possibilities.count} remaining)" }
+ state.pop_possibility_state.tap do |s|
+ if s
+ states.push(s)
+ activated.tag(s)
+ end
+ end
+ end
+ process_topmost_state
+ end
+
+ resolve_activated_specs
+ ensure
+ end_resolution
+ end
+
+ # @return [Integer] the number of resolver iterations in between calls to
+ # {#resolver_ui}'s {UI#indicate_progress} method
+ attr_accessor :iteration_rate
+ private :iteration_rate
+
+ # @return [Time] the time at which resolution began
+ attr_accessor :started_at
+ private :started_at
+
+ # @return [Array<ResolutionState>] the stack of states for the resolution
+ attr_accessor :states
+ private :states
+
+ private
+
+ # Sets up the resolution process
+ # @return [void]
+ def start_resolution
+ @started_at = Time.now
+
+ handle_missing_or_push_dependency_state(initial_state)
+
+ debug { "Starting resolution (#{@started_at})\nUser-requested dependencies: #{original_requested}" }
+ resolver_ui.before_resolution
+ end
+
+ def resolve_activated_specs
+ activated.vertices.each do |_, vertex|
+ next unless vertex.payload
+
+ latest_version = vertex.payload.possibilities.reverse_each.find do |possibility|
+ vertex.requirements.all? { |req| requirement_satisfied_by?(req, activated, possibility) }
+ end
+
+ activated.set_payload(vertex.name, latest_version)
+ end
+ activated.freeze
+ end
+
+ # Ends the resolution process
+ # @return [void]
+ def end_resolution
+ resolver_ui.after_resolution
+ debug do
+ "Finished resolution (#{@iteration_counter} steps) " \
+ "(Took #{(ended_at = Time.now) - @started_at} seconds) (#{ended_at})"
+ end
+ debug { 'Unactivated: ' + Hash[activated.vertices.reject { |_n, v| v.payload }].keys.join(', ') } if state
+ debug { 'Activated: ' + Hash[activated.vertices.select { |_n, v| v.payload }].keys.join(', ') } if state
+ end
+
+ require 'bundler/vendor/molinillo/lib/molinillo/state'
+ require 'bundler/vendor/molinillo/lib/molinillo/modules/specification_provider'
+
+ require 'bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state'
+ require 'bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider'
+
+ include Bundler::Molinillo::Delegates::ResolutionState
+ include Bundler::Molinillo::Delegates::SpecificationProvider
+
+ # Processes the topmost available {RequirementState} on the stack
+ # @return [void]
+ def process_topmost_state
+ if possibility
+ attempt_to_activate
+ else
+ create_conflict
+ unwind_for_conflict
+ end
+ rescue CircularDependencyError => underlying_error
+ create_conflict(underlying_error)
+ unwind_for_conflict
+ end
+
+ # @return [Object] the current possibility that the resolution is trying
+ # to activate
+ def possibility
+ possibilities.last
+ end
+
+ # @return [RequirementState] the current state the resolution is
+ # operating upon
+ def state
+ states.last
+ end
+
+ # Creates the initial state for the resolution, based upon the
+ # {#requested} dependencies
+ # @return [DependencyState] the initial state for the resolution
+ def initial_state
+ graph = DependencyGraph.new.tap do |dg|
+ original_requested.each do |requested|
+ vertex = dg.add_vertex(name_for(requested), nil, true)
+ vertex.explicit_requirements << requested
+ end
+ dg.tag(:initial_state)
+ end
+
+ requirements = sort_dependencies(original_requested, graph, {})
+ initial_requirement = requirements.shift
+ DependencyState.new(
+ initial_requirement && name_for(initial_requirement),
+ requirements,
+ graph,
+ initial_requirement,
+ possibilities_for_requirement(initial_requirement, graph),
+ 0,
+ {},
+ []
+ )
+ end
+
+ # Unwinds the states stack because a conflict has been encountered
+ # @return [void]
+ def unwind_for_conflict
+ details_for_unwind = build_details_for_unwind
+ unwind_options = unused_unwind_options
+ debug(depth) { "Unwinding for conflict: #{requirement} to #{details_for_unwind.state_index / 2}" }
+ conflicts.tap do |c|
+ sliced_states = states.slice!((details_for_unwind.state_index + 1)..-1)
+ raise_error_unless_state(c)
+ activated.rewind_to(sliced_states.first || :initial_state) if sliced_states
+ state.conflicts = c
+ state.unused_unwind_options = unwind_options
+ filter_possibilities_after_unwind(details_for_unwind)
+ index = states.size - 1
+ @parents_of.each { |_, a| a.reject! { |i| i >= index } }
+ state.unused_unwind_options.reject! { |uw| uw.state_index >= index }
+ end
+ end
+
+ # Raises a VersionConflict error, or any underlying error, if there is no
+ # current state
+ # @return [void]
+ def raise_error_unless_state(conflicts)
+ return if state
+
+ error = conflicts.values.map(&:underlying_error).compact.first
+ raise error || VersionConflict.new(conflicts, specification_provider)
+ end
+
+ # @return [UnwindDetails] Details of the nearest index to which we could unwind
+ def build_details_for_unwind
+ # Get the possible unwinds for the current conflict
+ current_conflict = conflicts[name]
+ binding_requirements = binding_requirements_for_conflict(current_conflict)
+ unwind_details = unwind_options_for_requirements(binding_requirements)
+
+ last_detail_for_current_unwind = unwind_details.sort.last
+ current_detail = last_detail_for_current_unwind
+
+ # Look for past conflicts that could be unwound to affect the
+ # requirement tree for the current conflict
+ relevant_unused_unwinds = unused_unwind_options.select do |alternative|
+ intersecting_requirements =
+ last_detail_for_current_unwind.all_requirements &
+ alternative.requirements_unwound_to_instead
+ next if intersecting_requirements.empty?
+ # Find the highest index unwind whilst looping through
+ current_detail = alternative if alternative > current_detail
+ alternative
+ end
+
+ # Add the current unwind options to the `unused_unwind_options` array.
+ # The "used" option will be filtered out during `unwind_for_conflict`.
+ state.unused_unwind_options += unwind_details.reject { |detail| detail.state_index == -1 }
+
+ # Update the requirements_unwound_to_instead on any relevant unused unwinds
+ relevant_unused_unwinds.each { |d| d.requirements_unwound_to_instead << current_detail.state_requirement }
+ unwind_details.each { |d| d.requirements_unwound_to_instead << current_detail.state_requirement }
+
+ current_detail
+ end
+
+ # @param [Array<Object>] array of requirements that combine to create a conflict
+ # @return [Array<UnwindDetails>] array of UnwindDetails that have a chance
+ # of resolving the passed requirements
+ def unwind_options_for_requirements(binding_requirements)
+ unwind_details = []
+
+ trees = []
+ binding_requirements.reverse_each do |r|
+ partial_tree = [r]
+ trees << partial_tree
+ unwind_details << UnwindDetails.new(-1, nil, partial_tree, binding_requirements, trees, [])
+
+ # If this requirement has alternative possibilities, check if any would
+ # satisfy the other requirements that created this conflict
+ requirement_state = find_state_for(r)
+ if conflict_fixing_possibilities?(requirement_state, binding_requirements)
+ unwind_details << UnwindDetails.new(
+ states.index(requirement_state),
+ r,
+ partial_tree,
+ binding_requirements,
+ trees,
+ []
+ )
+ end
+
+ # Next, look at the parent of this requirement, and check if the requirement
+ # could have been avoided if an alternative PossibilitySet had been chosen
+ parent_r = parent_of(r)
+ next if parent_r.nil?
+ partial_tree.unshift(parent_r)
+ requirement_state = find_state_for(parent_r)
+ if requirement_state.possibilities.any? { |set| !set.dependencies.include?(r) }
+ unwind_details << UnwindDetails.new(
+ states.index(requirement_state),
+ parent_r,
+ partial_tree,
+ binding_requirements,
+ trees,
+ []
+ )
+ end
+
+ # Finally, look at the grandparent and up of this requirement, looking
+ # for any possibilities that wouldn't create their parent requirement
+ grandparent_r = parent_of(parent_r)
+ until grandparent_r.nil?
+ partial_tree.unshift(grandparent_r)
+ requirement_state = find_state_for(grandparent_r)
+ if requirement_state.possibilities.any? { |set| !set.dependencies.include?(parent_r) }
+ unwind_details << UnwindDetails.new(
+ states.index(requirement_state),
+ grandparent_r,
+ partial_tree,
+ binding_requirements,
+ trees,
+ []
+ )
+ end
+ parent_r = grandparent_r
+ grandparent_r = parent_of(parent_r)
+ end
+ end
+
+ unwind_details
+ end
+
+ # @param [DependencyState] state
+ # @param [Array] array of requirements
+ # @return [Boolean] whether or not the given state has any possibilities
+ # that could satisfy the given requirements
+ def conflict_fixing_possibilities?(state, binding_requirements)
+ return false unless state
+
+ state.possibilities.any? do |possibility_set|
+ possibility_set.possibilities.any? do |poss|
+ possibility_satisfies_requirements?(poss, binding_requirements)
+ end
+ end
+ end
+
+ # Filter's a state's possibilities to remove any that would not fix the
+ # conflict we've just rewound from
+ # @param [UnwindDetails] details of the conflict just unwound from
+ # @return [void]
+ def filter_possibilities_after_unwind(unwind_details)
+ return unless state && !state.possibilities.empty?
+
+ if unwind_details.unwinding_to_primary_requirement?
+ filter_possibilities_for_primary_unwind(unwind_details)
+ else
+ filter_possibilities_for_parent_unwind(unwind_details)
+ end
+ end
+
+ # Filter's a state's possibilities to remove any that would not satisfy
+ # the requirements in the conflict we've just rewound from
+ # @param [UnwindDetails] details of the conflict just unwound from
+ # @return [void]
+ def filter_possibilities_for_primary_unwind(unwind_details)
+ unwinds_to_state = unused_unwind_options.select { |uw| uw.state_index == unwind_details.state_index }
+ unwinds_to_state << unwind_details
+ unwind_requirement_sets = unwinds_to_state.map(&:conflicting_requirements)
+
+ state.possibilities.reject! do |possibility_set|
+ possibility_set.possibilities.none? do |poss|
+ unwind_requirement_sets.any? do |requirements|
+ possibility_satisfies_requirements?(poss, requirements)
+ end
+ end
+ end
+ end
+
+ # @param [Object] possibility a single possibility
+ # @param [Array] requirements an array of requirements
+ # @return [Boolean] whether the possibility satisfies all of the
+ # given requirements
+ def possibility_satisfies_requirements?(possibility, requirements)
+ name = name_for(possibility)
+
+ activated.tag(:swap)
+ activated.set_payload(name, possibility) if activated.vertex_named(name)
+ satisfied = requirements.all? { |r| requirement_satisfied_by?(r, activated, possibility) }
+ activated.rewind_to(:swap)
+
+ satisfied
+ end
+
+ # Filter's a state's possibilities to remove any that would (eventually)
+ # create a requirement in the conflict we've just rewound from
+ # @param [UnwindDetails] details of the conflict just unwound from
+ # @return [void]
+ def filter_possibilities_for_parent_unwind(unwind_details)
+ unwinds_to_state = unused_unwind_options.select { |uw| uw.state_index == unwind_details.state_index }
+ unwinds_to_state << unwind_details
+
+ primary_unwinds = unwinds_to_state.select(&:unwinding_to_primary_requirement?).uniq
+ parent_unwinds = unwinds_to_state.uniq - primary_unwinds
+
+ allowed_possibility_sets = Compatibility.flat_map(primary_unwinds) do |unwind|
+ states[unwind.state_index].possibilities.select do |possibility_set|
+ possibility_set.possibilities.any? do |poss|
+ possibility_satisfies_requirements?(poss, unwind.conflicting_requirements)
+ end
+ end
+ end
+
+ requirements_to_avoid = Compatibility.flat_map(parent_unwinds, &:sub_dependencies_to_avoid)
+
+ state.possibilities.reject! do |possibility_set|
+ !allowed_possibility_sets.include?(possibility_set) &&
+ (requirements_to_avoid - possibility_set.dependencies).empty?
+ end
+ end
+
+ # @param [Conflict] conflict
+ # @return [Array] minimal array of requirements that would cause the passed
+ # conflict to occur.
+ def binding_requirements_for_conflict(conflict)
+ return [conflict.requirement] if conflict.possibility.nil?
+
+ possible_binding_requirements = conflict.requirements.values.flatten(1).uniq
+
+ # When there’s a `CircularDependency` error the conflicting requirement
+ # (the one causing the circular) won’t be `conflict.requirement`
+ # (which won’t be for the right state, because we won’t have created it,
+ # because it’s circular).
+ # We need to make sure we have that requirement in the conflict’s list,
+ # otherwise we won’t be able to unwind properly, so we just return all
+ # the requirements for the conflict.
+ return possible_binding_requirements if conflict.underlying_error
+
+ possibilities = search_for(conflict.requirement)
+
+ # If all the requirements together don't filter out all possibilities,
+ # then the only two requirements we need to consider are the initial one
+ # (where the dependency's version was first chosen) and the last
+ if binding_requirement_in_set?(nil, possible_binding_requirements, possibilities)
+ return [conflict.requirement, requirement_for_existing_name(name_for(conflict.requirement))].compact
+ end
+
+ # Loop through the possible binding requirements, removing each one
+ # that doesn't bind. Use a `reverse_each` as we want the earliest set of
+ # binding requirements, and don't use `reject!` as we wish to refine the
+ # array *on each iteration*.
+ binding_requirements = possible_binding_requirements.dup
+ possible_binding_requirements.reverse_each do |req|
+ next if req == conflict.requirement
+ unless binding_requirement_in_set?(req, binding_requirements, possibilities)
+ binding_requirements -= [req]
+ end
+ end
+
+ binding_requirements
+ end
+
+ # @param [Object] requirement we wish to check
+ # @param [Array] array of requirements
+ # @param [Array] array of possibilities the requirements will be used to filter
+ # @return [Boolean] whether or not the given requirement is required to filter
+ # out all elements of the array of possibilities.
+ def binding_requirement_in_set?(requirement, possible_binding_requirements, possibilities)
+ possibilities.any? do |poss|
+ possibility_satisfies_requirements?(poss, possible_binding_requirements - [requirement])
+ end
+ end
+
+ # @return [Object] the requirement that led to `requirement` being added
+ # to the list of requirements.
+ def parent_of(requirement)
+ return unless requirement
+ return unless index = @parents_of[requirement].last
+ return unless parent_state = @states[index]
+ parent_state.requirement
+ end
+
+ # @return [Object] the requirement that led to a version of a possibility
+ # with the given name being activated.
+ def requirement_for_existing_name(name)
+ return nil unless vertex = activated.vertex_named(name)
+ return nil unless vertex.payload
+ states.find { |s| s.name == name }.requirement
+ end
+
+ # @return [ResolutionState] the state whose `requirement` is the given
+ # `requirement`.
+ def find_state_for(requirement)
+ return nil unless requirement
+ states.find { |i| requirement == i.requirement }
+ end
+
+ # @return [Conflict] a {Conflict} that reflects the failure to activate
+ # the {#possibility} in conjunction with the current {#state}
+ def create_conflict(underlying_error = nil)
+ vertex = activated.vertex_named(name)
+ locked_requirement = locked_requirement_named(name)
+
+ requirements = {}
+ unless vertex.explicit_requirements.empty?
+ requirements[name_for_explicit_dependency_source] = vertex.explicit_requirements
+ end
+ requirements[name_for_locking_dependency_source] = [locked_requirement] if locked_requirement
+ vertex.incoming_edges.each do |edge|
+ (requirements[edge.origin.payload.latest_version] ||= []).unshift(edge.requirement)
+ end
+
+ activated_by_name = {}
+ activated.each { |v| activated_by_name[v.name] = v.payload.latest_version if v.payload }
+ conflicts[name] = Conflict.new(
+ requirement,
+ requirements,
+ vertex.payload && vertex.payload.latest_version,
+ possibility,
+ locked_requirement,
+ requirement_trees,
+ activated_by_name,
+ underlying_error
+ )
+ end
+
+ # @return [Array<Array<Object>>] The different requirement
+ # trees that led to every requirement for the current spec.
+ def requirement_trees
+ vertex = activated.vertex_named(name)
+ vertex.requirements.map { |r| requirement_tree_for(r) }
+ end
+
+ # @return [Array<Object>] the list of requirements that led to
+ # `requirement` being required.
+ def requirement_tree_for(requirement)
+ tree = []
+ while requirement
+ tree.unshift(requirement)
+ requirement = parent_of(requirement)
+ end
+ tree
+ end
+
+ # Indicates progress roughly once every second
+ # @return [void]
+ def indicate_progress
+ @iteration_counter += 1
+ @progress_rate ||= resolver_ui.progress_rate
+ if iteration_rate.nil?
+ if Time.now - started_at >= @progress_rate
+ self.iteration_rate = @iteration_counter
+ end
+ end
+
+ if iteration_rate && (@iteration_counter % iteration_rate) == 0
+ resolver_ui.indicate_progress
+ end
+ end
+
+ # Calls the {#resolver_ui}'s {UI#debug} method
+ # @param [Integer] depth the depth of the {#states} stack
+ # @param [Proc] block a block that yields a {#to_s}
+ # @return [void]
+ def debug(depth = 0, &block)
+ resolver_ui.debug(depth, &block)
+ end
+
+ # Attempts to activate the current {#possibility}
+ # @return [void]
+ def attempt_to_activate
+ debug(depth) { 'Attempting to activate ' + possibility.to_s }
+ existing_vertex = activated.vertex_named(name)
+ if existing_vertex.payload
+ debug(depth) { "Found existing spec (#{existing_vertex.payload})" }
+ attempt_to_filter_existing_spec(existing_vertex)
+ else
+ latest = possibility.latest_version
+ # use reject!(!satisfied) for 1.8.7 compatibility
+ possibility.possibilities.reject! do |possibility|
+ !requirement_satisfied_by?(requirement, activated, possibility)
+ end
+ if possibility.latest_version.nil?
+ # ensure there's a possibility for better error messages
+ possibility.possibilities << latest if latest
+ create_conflict
+ unwind_for_conflict
+ else
+ activate_new_spec
+ end
+ end
+ end
+
+ # Attempts to update the existing vertex's `PossibilitySet` with a filtered version
+ # @return [void]
+ def attempt_to_filter_existing_spec(vertex)
+ filtered_set = filtered_possibility_set(vertex)
+ if !filtered_set.possibilities.empty?
+ activated.set_payload(name, filtered_set)
+ new_requirements = requirements.dup
+ push_state_for_requirements(new_requirements, false)
+ else
+ create_conflict
+ debug(depth) { "Unsatisfied by existing spec (#{vertex.payload})" }
+ unwind_for_conflict
+ end
+ end
+
+ # Generates a filtered version of the existing vertex's `PossibilitySet` using the
+ # current state's `requirement`
+ # @param [Object] existing vertex
+ # @return [PossibilitySet] filtered possibility set
+ def filtered_possibility_set(vertex)
+ PossibilitySet.new(vertex.payload.dependencies, vertex.payload.possibilities & possibility.possibilities)
+ end
+
+ # @param [String] requirement_name the spec name to search for
+ # @return [Object] the locked spec named `requirement_name`, if one
+ # is found on {#base}
+ def locked_requirement_named(requirement_name)
+ vertex = base.vertex_named(requirement_name)
+ vertex && vertex.payload
+ end
+
+ # Add the current {#possibility} to the dependency graph of the current
+ # {#state}
+ # @return [void]
+ def activate_new_spec
+ conflicts.delete(name)
+ debug(depth) { "Activated #{name} at #{possibility}" }
+ activated.set_payload(name, possibility)
+ require_nested_dependencies_for(possibility)
+ end
+
+ # Requires the dependencies that the recently activated spec has
+ # @param [Object] activated_possibility the PossibilitySet that has just been
+ # activated
+ # @return [void]
+ def require_nested_dependencies_for(possibility_set)
+ nested_dependencies = dependencies_for(possibility_set.latest_version)
+ debug(depth) { "Requiring nested dependencies (#{nested_dependencies.join(', ')})" }
+ nested_dependencies.each do |d|
+ activated.add_child_vertex(name_for(d), nil, [name_for(possibility_set.latest_version)], d)
+ parent_index = states.size - 1
+ parents = @parents_of[d]
+ parents << parent_index if parents.empty?
+ end
+
+ push_state_for_requirements(requirements + nested_dependencies, !nested_dependencies.empty?)
+ end
+
+ # Pushes a new {DependencyState} that encapsulates both existing and new
+ # requirements
+ # @param [Array] new_requirements
+ # @return [void]
+ def push_state_for_requirements(new_requirements, requires_sort = true, new_activated = activated)
+ new_requirements = sort_dependencies(new_requirements.uniq, new_activated, conflicts) if requires_sort
+ new_requirement = nil
+ loop do
+ new_requirement = new_requirements.shift
+ break if new_requirement.nil? || states.none? { |s| s.requirement == new_requirement }
+ end
+ new_name = new_requirement ? name_for(new_requirement) : ''.freeze
+ possibilities = possibilities_for_requirement(new_requirement)
+ handle_missing_or_push_dependency_state DependencyState.new(
+ new_name, new_requirements, new_activated,
+ new_requirement, possibilities, depth, conflicts.dup, unused_unwind_options.dup
+ )
+ end
+
+ # Checks a proposed requirement with any existing locked requirement
+ # before generating an array of possibilities for it.
+ # @param [Object] the proposed requirement
+ # @return [Array] possibilities
+ def possibilities_for_requirement(requirement, activated = self.activated)
+ return [] unless requirement
+ if locked_requirement_named(name_for(requirement))
+ return locked_requirement_possibility_set(requirement, activated)
+ end
+
+ group_possibilities(search_for(requirement))
+ end
+
+ # @param [Object] the proposed requirement
+ # @return [Array] possibility set containing only the locked requirement, if any
+ def locked_requirement_possibility_set(requirement, activated = self.activated)
+ all_possibilities = search_for(requirement)
+ locked_requirement = locked_requirement_named(name_for(requirement))
+
+ # Longwinded way to build a possibilities array with either the locked
+ # requirement or nothing in it. Required, since the API for
+ # locked_requirement isn't guaranteed.
+ locked_possibilities = all_possibilities.select do |possibility|
+ requirement_satisfied_by?(locked_requirement, activated, possibility)
+ end
+
+ group_possibilities(locked_possibilities)
+ end
+
+ # Build an array of PossibilitySets, with each element representing a group of
+ # dependency versions that all have the same sub-dependency version constraints
+ # and are contiguous.
+ # @param [Array] an array of possibilities
+ # @return [Array] an array of possibility sets
+ def group_possibilities(possibilities)
+ possibility_sets = []
+ current_possibility_set = nil
+
+ possibilities.reverse_each do |possibility|
+ dependencies = dependencies_for(possibility)
+ if current_possibility_set && current_possibility_set.dependencies == dependencies
+ current_possibility_set.possibilities.unshift(possibility)
+ else
+ possibility_sets.unshift(PossibilitySet.new(dependencies, [possibility]))
+ current_possibility_set = possibility_sets.first
+ end
+ end
+
+ possibility_sets
+ end
+
+ # Pushes a new {DependencyState}.
+ # If the {#specification_provider} says to
+ # {SpecificationProvider#allow_missing?} that particular requirement, and
+ # there are no possibilities for that requirement, then `state` is not
+ # pushed, and the vertex in {#activated} is removed, and we continue
+ # resolving the remaining requirements.
+ # @param [DependencyState] state
+ # @return [void]
+ def handle_missing_or_push_dependency_state(state)
+ if state.requirement && state.possibilities.empty? && allow_missing?(state.requirement)
+ state.activated.detach_vertex_named(state.name)
+ push_state_for_requirements(state.requirements.dup, false, state.activated)
+ else
+ states.push(state).tap { activated.tag(state) }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/resolver.rb b/lib/bundler/vendor/molinillo/lib/molinillo/resolver.rb
new file mode 100644
index 0000000000..7d36858778
--- /dev/null
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/resolver.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph'
+
+module Bundler::Molinillo
+ # This class encapsulates a dependency resolver.
+ # The resolver is responsible for determining which set of dependencies to
+ # activate, with feedback from the {#specification_provider}
+ #
+ #
+ class Resolver
+ require 'bundler/vendor/molinillo/lib/molinillo/resolution'
+
+ # @return [SpecificationProvider] the specification provider used
+ # in the resolution process
+ attr_reader :specification_provider
+
+ # @return [UI] the UI module used to communicate back to the user
+ # during the resolution process
+ attr_reader :resolver_ui
+
+ # Initializes a new resolver.
+ # @param [SpecificationProvider] specification_provider
+ # see {#specification_provider}
+ # @param [UI] resolver_ui
+ # see {#resolver_ui}
+ def initialize(specification_provider, resolver_ui)
+ @specification_provider = specification_provider
+ @resolver_ui = resolver_ui
+ end
+
+ # Resolves the requested dependencies into a {DependencyGraph},
+ # locking to the base dependency graph (if specified)
+ # @param [Array] requested an array of 'requested' dependencies that the
+ # {#specification_provider} can understand
+ # @param [DependencyGraph,nil] base the base dependency graph to which
+ # dependencies should be 'locked'
+ def resolve(requested, base = DependencyGraph.new)
+ Resolution.new(specification_provider,
+ resolver_ui,
+ requested,
+ base).
+ resolve
+ end
+ end
+end
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/state.rb b/lib/bundler/vendor/molinillo/lib/molinillo/state.rb
new file mode 100644
index 0000000000..68fa1f54e3
--- /dev/null
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/state.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+module Bundler::Molinillo
+ # A state that a {Resolution} can be in
+ # @attr [String] name the name of the current requirement
+ # @attr [Array<Object>] requirements currently unsatisfied requirements
+ # @attr [DependencyGraph] activated the graph of activated dependencies
+ # @attr [Object] requirement the current requirement
+ # @attr [Object] possibilities the possibilities to satisfy the current requirement
+ # @attr [Integer] depth the depth of the resolution
+ # @attr [Hash] conflicts unresolved conflicts, indexed by dependency name
+ # @attr [Array<UnwindDetails>] unused_unwind_options unwinds for previous conflicts that weren't explored
+ ResolutionState = Struct.new(
+ :name,
+ :requirements,
+ :activated,
+ :requirement,
+ :possibilities,
+ :depth,
+ :conflicts,
+ :unused_unwind_options
+ )
+
+ class ResolutionState
+ # Returns an empty resolution state
+ # @return [ResolutionState] an empty state
+ def self.empty
+ new(nil, [], DependencyGraph.new, nil, nil, 0, {}, [])
+ end
+ end
+
+ # A state that encapsulates a set of {#requirements} with an {Array} of
+ # possibilities
+ class DependencyState < ResolutionState
+ # Removes a possibility from `self`
+ # @return [PossibilityState] a state with a single possibility,
+ # the possibility that was removed from `self`
+ def pop_possibility_state
+ PossibilityState.new(
+ name,
+ requirements.dup,
+ activated,
+ requirement,
+ [possibilities.pop],
+ depth + 1,
+ conflicts.dup,
+ unused_unwind_options.dup
+ ).tap do |state|
+ state.activated.tag(state)
+ end
+ end
+ end
+
+ # A state that encapsulates a single possibility to fulfill the given
+ # {#requirement}
+ class PossibilityState < ResolutionState
+ end
+end
diff --git a/lib/bundler/vendor/net-http-persistent/lib/net/http/faster.rb b/lib/bundler/vendor/net-http-persistent/lib/net/http/faster.rb
new file mode 100644
index 0000000000..e5e09080c2
--- /dev/null
+++ b/lib/bundler/vendor/net-http-persistent/lib/net/http/faster.rb
@@ -0,0 +1,27 @@
+require 'net/protocol'
+
+##
+# Aaron Patterson's monkeypatch (accepted into 1.9.1) to fix Net::HTTP's speed
+# problems.
+#
+# http://gist.github.com/251244
+
+class Net::BufferedIO #:nodoc:
+ alias :old_rbuf_fill :rbuf_fill
+
+ def rbuf_fill
+ if @io.respond_to? :read_nonblock then
+ begin
+ @rbuf << @io.read_nonblock(65536)
+ rescue Errno::EWOULDBLOCK, Errno::EAGAIN => e
+ retry if IO.select [@io], nil, nil, @read_timeout
+ raise Timeout::Error, e.message
+ end
+ else # SSL sockets do not have read_nonblock
+ timeout @read_timeout do
+ @rbuf << @io.sysread(65536)
+ end
+ end
+ end
+end if RUBY_VERSION < '1.9'
+
diff --git a/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb b/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb
new file mode 100644
index 0000000000..7cbca5bc06
--- /dev/null
+++ b/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb
@@ -0,0 +1,1233 @@
+require 'net/http'
+begin
+ require 'net/https'
+rescue LoadError
+ # net/https or openssl
+end if RUBY_VERSION < '1.9' # but only for 1.8
+require 'bundler/vendor/net-http-persistent/lib/net/http/faster'
+require 'uri'
+require 'cgi' # for escaping
+
+begin
+ require 'net/http/pipeline'
+rescue LoadError
+end
+
+autoload :OpenSSL, 'openssl'
+
+##
+# Persistent connections for Net::HTTP
+#
+# Bundler::Persistent::Net::HTTP::Persistent maintains persistent connections across all the
+# servers you wish to talk to. For each host:port you communicate with a
+# single persistent connection is created.
+#
+# Multiple Bundler::Persistent::Net::HTTP::Persistent objects will share the same set of
+# connections.
+#
+# For each thread you start a new connection will be created. A
+# Bundler::Persistent::Net::HTTP::Persistent connection will not be shared across threads.
+#
+# You can shut down the HTTP connections when done by calling #shutdown. You
+# should name your Bundler::Persistent::Net::HTTP::Persistent object if you intend to call this
+# method.
+#
+# Example:
+#
+# require 'bundler/vendor/net-http-persistent/lib/net/http/persistent'
+#
+# uri = URI 'http://example.com/awesome/web/service'
+#
+# http = Bundler::Persistent::Net::HTTP::Persistent.new 'my_app_name'
+#
+# # perform a GET
+# response = http.request uri
+#
+# # or
+#
+# get = Net::HTTP::Get.new uri.request_uri
+# response = http.request get
+#
+# # create a POST
+# post_uri = uri + 'create'
+# post = Net::HTTP::Post.new post_uri.path
+# post.set_form_data 'some' => 'cool data'
+#
+# # perform the POST, the URI is always required
+# response http.request post_uri, post
+#
+# Note that for GET, HEAD and other requests that do not have a body you want
+# to use URI#request_uri not URI#path. The request_uri contains the query
+# params which are sent in the body for other requests.
+#
+# == SSL
+#
+# SSL connections are automatically created depending upon the scheme of the
+# URI. SSL connections are automatically verified against the default
+# certificate store for your computer. You can override this by changing
+# verify_mode or by specifying an alternate cert_store.
+#
+# Here are the SSL settings, see the individual methods for documentation:
+#
+# #certificate :: This client's certificate
+# #ca_file :: The certificate-authority
+# #cert_store :: An SSL certificate store
+# #private_key :: The client's SSL private key
+# #reuse_ssl_sessions :: Reuse a previously opened SSL session for a new
+# connection
+# #ssl_version :: Which specific SSL version to use
+# #verify_callback :: For server certificate verification
+# #verify_mode :: How connections should be verified
+#
+# == Proxies
+#
+# A proxy can be set through #proxy= or at initialization time by providing a
+# second argument to ::new. The proxy may be the URI of the proxy server or
+# <code>:ENV</code> which will consult environment variables.
+#
+# See #proxy= and #proxy_from_env for details.
+#
+# == Headers
+#
+# Headers may be specified for use in every request. #headers are appended to
+# any headers on the request. #override_headers replace existing headers on
+# the request.
+#
+# The difference between the two can be seen in setting the User-Agent. Using
+# <code>http.headers['User-Agent'] = 'MyUserAgent'</code> will send "Ruby,
+# MyUserAgent" while <code>http.override_headers['User-Agent'] =
+# 'MyUserAgent'</code> will send "MyUserAgent".
+#
+# == Tuning
+#
+# === Segregation
+#
+# By providing an application name to ::new you can separate your connections
+# from the connections of other applications.
+#
+# === Idle Timeout
+#
+# If a connection hasn't been used for this number of seconds it will automatically be
+# reset upon the next use to avoid attempting to send to a closed connection.
+# The default value is 5 seconds. nil means no timeout. Set through #idle_timeout.
+#
+# Reducing this value may help avoid the "too many connection resets" error
+# when sending non-idempotent requests while increasing this value will cause
+# fewer round-trips.
+#
+# === Read Timeout
+#
+# The amount of time allowed between reading two chunks from the socket. Set
+# through #read_timeout
+#
+# === Max Requests
+#
+# The number of requests that should be made before opening a new connection.
+# Typically many keep-alive capable servers tune this to 100 or less, so the
+# 101st request will fail with ECONNRESET. If unset (default), this value has no
+# effect, if set, connections will be reset on the request after max_requests.
+#
+# === Open Timeout
+#
+# The amount of time to wait for a connection to be opened. Set through
+# #open_timeout.
+#
+# === Socket Options
+#
+# Socket options may be set on newly-created connections. See #socket_options
+# for details.
+#
+# === Non-Idempotent Requests
+#
+# By default non-idempotent requests will not be retried per RFC 2616. By
+# setting retry_change_requests to true requests will automatically be retried
+# once.
+#
+# Only do this when you know that retrying a POST or other non-idempotent
+# request is safe for your application and will not create duplicate
+# resources.
+#
+# The recommended way to handle non-idempotent requests is the following:
+#
+# require 'bundler/vendor/net-http-persistent/lib/net/http/persistent'
+#
+# uri = URI 'http://example.com/awesome/web/service'
+# post_uri = uri + 'create'
+#
+# http = Bundler::Persistent::Net::HTTP::Persistent.new 'my_app_name'
+#
+# post = Net::HTTP::Post.new post_uri.path
+# # ... fill in POST request
+#
+# begin
+# response = http.request post_uri, post
+# rescue Bundler::Persistent::Net::HTTP::Persistent::Error
+#
+# # POST failed, make a new request to verify the server did not process
+# # the request
+# exists_uri = uri + '...'
+# response = http.get exists_uri
+#
+# # Retry if it failed
+# retry if response.code == '404'
+# end
+#
+# The method of determining if the resource was created or not is unique to
+# the particular service you are using. Of course, you will want to add
+# protection from infinite looping.
+#
+# === Connection Termination
+#
+# If you are done using the Bundler::Persistent::Net::HTTP::Persistent instance you may shut down
+# all the connections in the current thread with #shutdown. This is not
+# recommended for normal use, it should only be used when it will be several
+# minutes before you make another HTTP request.
+#
+# If you are using multiple threads, call #shutdown in each thread when the
+# thread is done making requests. If you don't call shutdown, that's OK.
+# Ruby will automatically garbage collect and shutdown your HTTP connections
+# when the thread terminates.
+
+class Bundler::Persistent::Net::HTTP::Persistent
+
+ ##
+ # The beginning of Time
+
+ EPOCH = Time.at 0 # :nodoc:
+
+ ##
+ # Is OpenSSL available? This test works with autoload
+
+ HAVE_OPENSSL = defined? OpenSSL::SSL # :nodoc:
+
+ ##
+ # The version of Bundler::Persistent::Net::HTTP::Persistent you are using
+
+ VERSION = '2.9.4'
+
+ ##
+ # Exceptions rescued for automatic retry on ruby 2.0.0. This overlaps with
+ # the exception list for ruby 1.x.
+
+ RETRIED_EXCEPTIONS = [ # :nodoc:
+ (Net::ReadTimeout if Net.const_defined? :ReadTimeout),
+ IOError,
+ EOFError,
+ Errno::ECONNRESET,
+ Errno::ECONNABORTED,
+ Errno::EPIPE,
+ (OpenSSL::SSL::SSLError if HAVE_OPENSSL),
+ Timeout::Error,
+ ].compact
+
+ ##
+ # Error class for errors raised by Bundler::Persistent::Net::HTTP::Persistent. Various
+ # SystemCallErrors are re-raised with a human-readable message under this
+ # class.
+
+ class Error < StandardError; end
+
+ ##
+ # Use this method to detect the idle timeout of the host at +uri+. The
+ # value returned can be used to configure #idle_timeout. +max+ controls the
+ # maximum idle timeout to detect.
+ #
+ # After
+ #
+ # Idle timeout detection is performed by creating a connection then
+ # performing a HEAD request in a loop until the connection terminates
+ # waiting one additional second per loop.
+ #
+ # NOTE: This may not work on ruby > 1.9.
+
+ def self.detect_idle_timeout uri, max = 10
+ uri = URI uri unless URI::Generic === uri
+ uri += '/'
+
+ req = Net::HTTP::Head.new uri.request_uri
+
+ http = new 'net-http-persistent detect_idle_timeout'
+
+ connection = http.connection_for uri
+
+ sleep_time = 0
+
+ loop do
+ response = connection.request req
+
+ $stderr.puts "HEAD #{uri} => #{response.code}" if $DEBUG
+
+ unless Net::HTTPOK === response then
+ raise Error, "bad response code #{response.code} detecting idle timeout"
+ end
+
+ break if sleep_time >= max
+
+ sleep_time += 1
+
+ $stderr.puts "sleeping #{sleep_time}" if $DEBUG
+ sleep sleep_time
+ end
+ rescue
+ # ignore StandardErrors, we've probably found the idle timeout.
+ ensure
+ http.shutdown
+
+ return sleep_time unless $!
+ end
+
+ ##
+ # This client's OpenSSL::X509::Certificate
+
+ attr_reader :certificate
+
+ # For Net::HTTP parity
+ alias cert certificate
+
+ ##
+ # An SSL certificate authority. Setting this will set verify_mode to
+ # VERIFY_PEER.
+
+ attr_reader :ca_file
+
+ ##
+ # An SSL certificate store. Setting this will override the default
+ # certificate store. See verify_mode for more information.
+
+ attr_reader :cert_store
+
+ ##
+ # Sends debug_output to this IO via Net::HTTP#set_debug_output.
+ #
+ # Never use this method in production code, it causes a serious security
+ # hole.
+
+ attr_accessor :debug_output
+
+ ##
+ # Current connection generation
+
+ attr_reader :generation # :nodoc:
+
+ ##
+ # Where this instance's connections live in the thread local variables
+
+ attr_reader :generation_key # :nodoc:
+
+ ##
+ # Headers that are added to every request using Net::HTTP#add_field
+
+ attr_reader :headers
+
+ ##
+ # Maps host:port to an HTTP version. This allows us to enable version
+ # specific features.
+
+ attr_reader :http_versions
+
+ ##
+ # Maximum time an unused connection can remain idle before being
+ # automatically closed.
+
+ attr_accessor :idle_timeout
+
+ ##
+ # Maximum number of requests on a connection before it is considered expired
+ # and automatically closed.
+
+ attr_accessor :max_requests
+
+ ##
+ # The value sent in the Keep-Alive header. Defaults to 30. Not needed for
+ # HTTP/1.1 servers.
+ #
+ # This may not work correctly for HTTP/1.0 servers
+ #
+ # This method may be removed in a future version as RFC 2616 does not
+ # require this header.
+
+ attr_accessor :keep_alive
+
+ ##
+ # A name for this connection. Allows you to keep your connections apart
+ # from everybody else's.
+
+ attr_reader :name
+
+ ##
+ # Seconds to wait until a connection is opened. See Net::HTTP#open_timeout
+
+ attr_accessor :open_timeout
+
+ ##
+ # Headers that are added to every request using Net::HTTP#[]=
+
+ attr_reader :override_headers
+
+ ##
+ # This client's SSL private key
+
+ attr_reader :private_key
+
+ # For Net::HTTP parity
+ alias key private_key
+
+ ##
+ # The URL through which requests will be proxied
+
+ attr_reader :proxy_uri
+
+ ##
+ # List of host suffixes which will not be proxied
+
+ attr_reader :no_proxy
+
+ ##
+ # Seconds to wait until reading one block. See Net::HTTP#read_timeout
+
+ attr_accessor :read_timeout
+
+ ##
+ # Where this instance's request counts live in the thread local variables
+
+ attr_reader :request_key # :nodoc:
+
+ ##
+ # By default SSL sessions are reused to avoid extra SSL handshakes. Set
+ # this to false if you have problems communicating with an HTTPS server
+ # like:
+ #
+ # SSL_connect [...] read finished A: unexpected message (OpenSSL::SSL::SSLError)
+
+ attr_accessor :reuse_ssl_sessions
+
+ ##
+ # An array of options for Socket#setsockopt.
+ #
+ # By default the TCP_NODELAY option is set on sockets.
+ #
+ # To set additional options append them to this array:
+ #
+ # http.socket_options << [Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, 1]
+
+ attr_reader :socket_options
+
+ ##
+ # Current SSL connection generation
+
+ attr_reader :ssl_generation # :nodoc:
+
+ ##
+ # Where this instance's SSL connections live in the thread local variables
+
+ attr_reader :ssl_generation_key # :nodoc:
+
+ ##
+ # SSL version to use.
+ #
+ # By default, the version will be negotiated automatically between client
+ # and server. Ruby 1.9 and newer only.
+
+ attr_reader :ssl_version if RUBY_VERSION > '1.9'
+
+ ##
+ # Where this instance's last-use times live in the thread local variables
+
+ attr_reader :timeout_key # :nodoc:
+
+ ##
+ # SSL verification callback. Used when ca_file is set.
+
+ attr_reader :verify_callback
+
+ ##
+ # HTTPS verify mode. Defaults to OpenSSL::SSL::VERIFY_PEER which verifies
+ # the server certificate.
+ #
+ # If no ca_file or cert_store is set the default system certificate store is
+ # used.
+ #
+ # You can use +verify_mode+ to override any default values.
+
+ attr_reader :verify_mode
+
+ ##
+ # Enable retries of non-idempotent requests that change data (e.g. POST
+ # requests) when the server has disconnected.
+ #
+ # This will in the worst case lead to multiple requests with the same data,
+ # but it may be useful for some applications. Take care when enabling
+ # this option to ensure it is safe to POST or perform other non-idempotent
+ # requests to the server.
+
+ attr_accessor :retry_change_requests
+
+ ##
+ # Creates a new Bundler::Persistent::Net::HTTP::Persistent.
+ #
+ # Set +name+ to keep your connections apart from everybody else's. Not
+ # required currently, but highly recommended. Your library name should be
+ # good enough. This parameter will be required in a future version.
+ #
+ # +proxy+ may be set to a URI::HTTP or :ENV to pick up proxy options from
+ # the environment. See proxy_from_env for details.
+ #
+ # In order to use a URI for the proxy you may need to do some extra work
+ # beyond URI parsing if the proxy requires a password:
+ #
+ # proxy = URI 'http://proxy.example'
+ # proxy.user = 'AzureDiamond'
+ # proxy.password = 'hunter2'
+
+ def initialize name = nil, proxy = nil
+ @name = name
+
+ @debug_output = nil
+ @proxy_uri = nil
+ @no_proxy = []
+ @headers = {}
+ @override_headers = {}
+ @http_versions = {}
+ @keep_alive = 30
+ @open_timeout = nil
+ @read_timeout = nil
+ @idle_timeout = 5
+ @max_requests = nil
+ @socket_options = []
+
+ @socket_options << [Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1] if
+ Socket.const_defined? :TCP_NODELAY
+
+ key = ['net_http_persistent', name].compact
+ @generation_key = [key, 'generations' ].join('_').intern
+ @ssl_generation_key = [key, 'ssl_generations'].join('_').intern
+ @request_key = [key, 'requests' ].join('_').intern
+ @timeout_key = [key, 'timeouts' ].join('_').intern
+
+ @certificate = nil
+ @ca_file = nil
+ @private_key = nil
+ @ssl_version = nil
+ @verify_callback = nil
+ @verify_mode = nil
+ @cert_store = nil
+
+ @generation = 0 # incremented when proxy URI changes
+ @ssl_generation = 0 # incremented when SSL session variables change
+
+ if HAVE_OPENSSL then
+ @verify_mode = OpenSSL::SSL::VERIFY_PEER
+ @reuse_ssl_sessions = OpenSSL::SSL.const_defined? :Session
+ end
+
+ @retry_change_requests = false
+
+ @ruby_1 = RUBY_VERSION < '2'
+ @retried_on_ruby_2 = !@ruby_1
+
+ self.proxy = proxy if proxy
+ end
+
+ ##
+ # Sets this client's OpenSSL::X509::Certificate
+
+ def certificate= certificate
+ @certificate = certificate
+
+ reconnect_ssl
+ end
+
+ # For Net::HTTP parity
+ alias cert= certificate=
+
+ ##
+ # Sets the SSL certificate authority file.
+
+ def ca_file= file
+ @ca_file = file
+
+ reconnect_ssl
+ end
+
+ ##
+ # Overrides the default SSL certificate store used for verifying
+ # connections.
+
+ def cert_store= store
+ @cert_store = store
+
+ reconnect_ssl
+ end
+
+ ##
+ # Finishes all connections on the given +thread+ that were created before
+ # the given +generation+ in the threads +generation_key+ list.
+ #
+ # See #shutdown for a bunch of scary warning about misusing this method.
+
+ def cleanup(generation, thread = Thread.current,
+ generation_key = @generation_key) # :nodoc:
+ timeouts = thread[@timeout_key]
+
+ (0...generation).each do |old_generation|
+ next unless thread[generation_key]
+
+ conns = thread[generation_key].delete old_generation
+
+ conns.each_value do |conn|
+ finish conn, thread
+
+ timeouts.delete conn.object_id if timeouts
+ end if conns
+ end
+ end
+
+ ##
+ # Creates a new connection for +uri+
+
+ def connection_for uri
+ Thread.current[@generation_key] ||= Hash.new { |h,k| h[k] = {} }
+ Thread.current[@ssl_generation_key] ||= Hash.new { |h,k| h[k] = {} }
+ Thread.current[@request_key] ||= Hash.new 0
+ Thread.current[@timeout_key] ||= Hash.new EPOCH
+
+ use_ssl = uri.scheme.downcase == 'https'
+
+ if use_ssl then
+ raise Bundler::Persistent::Net::HTTP::Persistent::Error, 'OpenSSL is not available' unless
+ HAVE_OPENSSL
+
+ ssl_generation = @ssl_generation
+
+ ssl_cleanup ssl_generation
+
+ connections = Thread.current[@ssl_generation_key][ssl_generation]
+ else
+ generation = @generation
+
+ cleanup generation
+
+ connections = Thread.current[@generation_key][generation]
+ end
+
+ net_http_args = [uri.host, uri.port]
+ connection_id = net_http_args.join ':'
+
+ if @proxy_uri and not proxy_bypass? uri.host, uri.port then
+ connection_id << @proxy_connection_id
+ net_http_args.concat @proxy_args
+ else
+ net_http_args.concat [nil, nil, nil, nil]
+ end
+
+ connection = connections[connection_id]
+
+ unless connection = connections[connection_id] then
+ connections[connection_id] = http_class.new(*net_http_args)
+ connection = connections[connection_id]
+ ssl connection if use_ssl
+ else
+ reset connection if expired? connection
+ end
+
+ start connection unless connection.started?
+
+ connection.read_timeout = @read_timeout if @read_timeout
+ connection.keep_alive_timeout = @idle_timeout if @idle_timeout && connection.respond_to?(:keep_alive_timeout=)
+
+ connection
+ rescue Errno::ECONNREFUSED
+ address = connection.proxy_address || connection.address
+ port = connection.proxy_port || connection.port
+
+ raise Error, "connection refused: #{address}:#{port}"
+ rescue Errno::EHOSTDOWN
+ address = connection.proxy_address || connection.address
+ port = connection.proxy_port || connection.port
+
+ raise Error, "host down: #{address}:#{port}"
+ end
+
+ ##
+ # Returns an error message containing the number of requests performed on
+ # this connection
+
+ def error_message connection
+ requests = Thread.current[@request_key][connection.object_id] - 1 # fixup
+ last_use = Thread.current[@timeout_key][connection.object_id]
+
+ age = Time.now - last_use
+
+ "after #{requests} requests on #{connection.object_id}, " \
+ "last used #{age} seconds ago"
+ end
+
+ ##
+ # URI::escape wrapper
+
+ def escape str
+ CGI.escape str if str
+ end
+
+ ##
+ # URI::unescape wrapper
+
+ def unescape str
+ CGI.unescape str if str
+ end
+
+
+ ##
+ # Returns true if the connection should be reset due to an idle timeout, or
+ # maximum request count, false otherwise.
+
+ def expired? connection
+ requests = Thread.current[@request_key][connection.object_id]
+ return true if @max_requests && requests >= @max_requests
+ return false unless @idle_timeout
+ return true if @idle_timeout.zero?
+
+ last_used = Thread.current[@timeout_key][connection.object_id]
+
+ Time.now - last_used > @idle_timeout
+ end
+
+ ##
+ # Starts the Net::HTTP +connection+
+
+ def start connection
+ connection.set_debug_output @debug_output if @debug_output
+ connection.open_timeout = @open_timeout if @open_timeout
+
+ connection.start
+
+ socket = connection.instance_variable_get :@socket
+
+ if socket then # for fakeweb
+ @socket_options.each do |option|
+ socket.io.setsockopt(*option)
+ end
+ end
+ end
+
+ ##
+ # Finishes the Net::HTTP +connection+
+
+ def finish connection, thread = Thread.current
+ if requests = thread[@request_key] then
+ requests.delete connection.object_id
+ end
+
+ connection.finish
+ rescue IOError
+ end
+
+ def http_class # :nodoc:
+ if RUBY_VERSION > '2.0' then
+ Net::HTTP
+ elsif [:Artifice, :FakeWeb, :WebMock].any? { |klass|
+ Object.const_defined?(klass)
+ } or not @reuse_ssl_sessions then
+ Net::HTTP
+ else
+ Bundler::Persistent::Net::HTTP::Persistent::SSLReuse
+ end
+ end
+
+ ##
+ # Returns the HTTP protocol version for +uri+
+
+ def http_version uri
+ @http_versions["#{uri.host}:#{uri.port}"]
+ end
+
+ ##
+ # Is +req+ idempotent according to RFC 2616?
+
+ def idempotent? req
+ case req
+ when Net::HTTP::Delete, Net::HTTP::Get, Net::HTTP::Head,
+ Net::HTTP::Options, Net::HTTP::Put, Net::HTTP::Trace then
+ true
+ end
+ end
+
+ ##
+ # Is the request +req+ idempotent or is retry_change_requests allowed.
+ #
+ # If +retried_on_ruby_2+ is true, true will be returned if we are on ruby,
+ # retry_change_requests is allowed and the request is not idempotent.
+
+ def can_retry? req, retried_on_ruby_2 = false
+ return @retry_change_requests && !idempotent?(req) if retried_on_ruby_2
+
+ @retry_change_requests || idempotent?(req)
+ end
+
+ if RUBY_VERSION > '1.9' then
+ ##
+ # Workaround for missing Net::HTTPHeader#connection_close? on Ruby 1.8
+
+ def connection_close? header
+ header.connection_close?
+ end
+
+ ##
+ # Workaround for missing Net::HTTPHeader#connection_keep_alive? on Ruby 1.8
+
+ def connection_keep_alive? header
+ header.connection_keep_alive?
+ end
+ else
+ ##
+ # Workaround for missing Net::HTTPRequest#connection_close? on Ruby 1.8
+
+ def connection_close? header
+ header['connection'] =~ /close/ or header['proxy-connection'] =~ /close/
+ end
+
+ ##
+ # Workaround for missing Net::HTTPRequest#connection_keep_alive? on Ruby
+ # 1.8
+
+ def connection_keep_alive? header
+ header['connection'] =~ /keep-alive/ or
+ header['proxy-connection'] =~ /keep-alive/
+ end
+ end
+
+ ##
+ # Deprecated in favor of #expired?
+
+ def max_age # :nodoc:
+ return Time.now + 1 unless @idle_timeout
+
+ Time.now - @idle_timeout
+ end
+
+ ##
+ # Adds "http://" to the String +uri+ if it is missing.
+
+ def normalize_uri uri
+ (uri =~ /^https?:/) ? uri : "http://#{uri}"
+ end
+
+ ##
+ # Pipelines +requests+ to the HTTP server at +uri+ yielding responses if a
+ # block is given. Returns all responses received.
+ #
+ # See
+ # Net::HTTP::Pipeline[http://docs.seattlerb.org/net-http-pipeline/Net/HTTP/Pipeline.html]
+ # for further details.
+ #
+ # Only if <tt>net-http-pipeline</tt> was required before
+ # <tt>net-http-persistent</tt> #pipeline will be present.
+
+ def pipeline uri, requests, &block # :yields: responses
+ connection = connection_for uri
+
+ connection.pipeline requests, &block
+ end
+
+ ##
+ # Sets this client's SSL private key
+
+ def private_key= key
+ @private_key = key
+
+ reconnect_ssl
+ end
+
+ # For Net::HTTP parity
+ alias key= private_key=
+
+ ##
+ # Sets the proxy server. The +proxy+ may be the URI of the proxy server,
+ # the symbol +:ENV+ which will read the proxy from the environment or nil to
+ # disable use of a proxy. See #proxy_from_env for details on setting the
+ # proxy from the environment.
+ #
+ # If the proxy URI is set after requests have been made, the next request
+ # will shut-down and re-open all connections.
+ #
+ # The +no_proxy+ query parameter can be used to specify hosts which shouldn't
+ # be reached via proxy; if set it should be a comma separated list of
+ # hostname suffixes, optionally with +:port+ appended, for example
+ # <tt>example.com,some.host:8080</tt>.
+
+ def proxy= proxy
+ @proxy_uri = case proxy
+ when :ENV then proxy_from_env
+ when URI::HTTP then proxy
+ when nil then # ignore
+ else raise ArgumentError, 'proxy must be :ENV or a URI::HTTP'
+ end
+
+ @no_proxy.clear
+
+ if @proxy_uri then
+ @proxy_args = [
+ @proxy_uri.host,
+ @proxy_uri.port,
+ unescape(@proxy_uri.user),
+ unescape(@proxy_uri.password),
+ ]
+
+ @proxy_connection_id = [nil, *@proxy_args].join ':'
+
+ if @proxy_uri.query then
+ @no_proxy = CGI.parse(@proxy_uri.query)['no_proxy'].join(',').downcase.split(',').map { |x| x.strip }.reject { |x| x.empty? }
+ end
+ end
+
+ reconnect
+ reconnect_ssl
+ end
+
+ ##
+ # Creates a URI for an HTTP proxy server from ENV variables.
+ #
+ # If +HTTP_PROXY+ is set a proxy will be returned.
+ #
+ # If +HTTP_PROXY_USER+ or +HTTP_PROXY_PASS+ are set the URI is given the
+ # indicated user and password unless HTTP_PROXY contains either of these in
+ # the URI.
+ #
+ # The +NO_PROXY+ ENV variable can be used to specify hosts which shouldn't
+ # be reached via proxy; if set it should be a comma separated list of
+ # hostname suffixes, optionally with +:port+ appended, for example
+ # <tt>example.com,some.host:8080</tt>. When set to <tt>*</tt> no proxy will
+ # be returned.
+ #
+ # For Windows users, lowercase ENV variables are preferred over uppercase ENV
+ # variables.
+
+ def proxy_from_env
+ env_proxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
+
+ return nil if env_proxy.nil? or env_proxy.empty?
+
+ uri = URI normalize_uri env_proxy
+
+ env_no_proxy = ENV['no_proxy'] || ENV['NO_PROXY']
+
+ # '*' is special case for always bypass
+ return nil if env_no_proxy == '*'
+
+ if env_no_proxy then
+ uri.query = "no_proxy=#{escape(env_no_proxy)}"
+ end
+
+ unless uri.user or uri.password then
+ uri.user = escape ENV['http_proxy_user'] || ENV['HTTP_PROXY_USER']
+ uri.password = escape ENV['http_proxy_pass'] || ENV['HTTP_PROXY_PASS']
+ end
+
+ uri
+ end
+
+ ##
+ # Returns true when proxy should by bypassed for host.
+
+ def proxy_bypass? host, port
+ host = host.downcase
+ host_port = [host, port].join ':'
+
+ @no_proxy.each do |name|
+ return true if host[-name.length, name.length] == name or
+ host_port[-name.length, name.length] == name
+ end
+
+ false
+ end
+
+ ##
+ # Forces reconnection of HTTP connections.
+
+ def reconnect
+ @generation += 1
+ end
+
+ ##
+ # Forces reconnection of SSL connections.
+
+ def reconnect_ssl
+ @ssl_generation += 1
+ end
+
+ ##
+ # Finishes then restarts the Net::HTTP +connection+
+
+ def reset connection
+ Thread.current[@request_key].delete connection.object_id
+ Thread.current[@timeout_key].delete connection.object_id
+
+ finish connection
+
+ start connection
+ rescue Errno::ECONNREFUSED
+ e = Error.new "connection refused: #{connection.address}:#{connection.port}"
+ e.set_backtrace $@
+ raise e
+ rescue Errno::EHOSTDOWN
+ e = Error.new "host down: #{connection.address}:#{connection.port}"
+ e.set_backtrace $@
+ raise e
+ end
+
+ ##
+ # Makes a request on +uri+. If +req+ is nil a Net::HTTP::Get is performed
+ # against +uri+.
+ #
+ # If a block is passed #request behaves like Net::HTTP#request (the body of
+ # the response will not have been read).
+ #
+ # +req+ must be a Net::HTTPRequest subclass (see Net::HTTP for a list).
+ #
+ # If there is an error and the request is idempotent according to RFC 2616
+ # it will be retried automatically.
+
+ def request uri, req = nil, &block
+ retried = false
+ bad_response = false
+
+ req = request_setup req || uri
+
+ connection = connection_for uri
+ connection_id = connection.object_id
+
+ begin
+ Thread.current[@request_key][connection_id] += 1
+ response = connection.request req, &block
+
+ if connection_close?(req) or
+ (response.http_version <= '1.0' and
+ not connection_keep_alive?(response)) or
+ connection_close?(response) then
+ connection.finish
+ end
+ rescue Net::HTTPBadResponse => e
+ message = error_message connection
+
+ finish connection
+
+ raise Error, "too many bad responses #{message}" if
+ bad_response or not can_retry? req
+
+ bad_response = true
+ retry
+ rescue *RETRIED_EXCEPTIONS => e # retried on ruby 2
+ request_failed e, req, connection if
+ retried or not can_retry? req, @retried_on_ruby_2
+
+ reset connection
+
+ retried = true
+ retry
+ rescue Errno::EINVAL, Errno::ETIMEDOUT => e # not retried on ruby 2
+ request_failed e, req, connection if retried or not can_retry? req
+
+ reset connection
+
+ retried = true
+ retry
+ rescue Exception => e
+ finish connection
+
+ raise
+ ensure
+ Thread.current[@timeout_key][connection_id] = Time.now
+ end
+
+ @http_versions["#{uri.host}:#{uri.port}"] ||= response.http_version
+
+ response
+ end
+
+ ##
+ # Raises an Error for +exception+ which resulted from attempting the request
+ # +req+ on the +connection+.
+ #
+ # Finishes the +connection+.
+
+ def request_failed exception, req, connection # :nodoc:
+ due_to = "(due to #{exception.message} - #{exception.class})"
+ message = "too many connection resets #{due_to} #{error_message connection}"
+
+ finish connection
+
+
+ raise Error, message, exception.backtrace
+ end
+
+ ##
+ # Creates a GET request if +req_or_uri+ is a URI and adds headers to the
+ # request.
+ #
+ # Returns the request.
+
+ def request_setup req_or_uri # :nodoc:
+ req = if URI === req_or_uri then
+ Net::HTTP::Get.new req_or_uri.request_uri
+ else
+ req_or_uri
+ end
+
+ @headers.each do |pair|
+ req.add_field(*pair)
+ end
+
+ @override_headers.each do |name, value|
+ req[name] = value
+ end
+
+ unless req['Connection'] then
+ req.add_field 'Connection', 'keep-alive'
+ req.add_field 'Keep-Alive', @keep_alive
+ end
+
+ req
+ end
+
+ ##
+ # Shuts down all connections for +thread+.
+ #
+ # Uses the current thread by default.
+ #
+ # If you've used Bundler::Persistent::Net::HTTP::Persistent across multiple threads you should
+ # call this in each thread when you're done making HTTP requests.
+ #
+ # *NOTE*: Calling shutdown for another thread can be dangerous!
+ #
+ # If the thread is still using the connection it may cause an error! It is
+ # best to call #shutdown in the thread at the appropriate time instead!
+
+ def shutdown thread = Thread.current
+ generation = reconnect
+ cleanup generation, thread, @generation_key
+
+ ssl_generation = reconnect_ssl
+ cleanup ssl_generation, thread, @ssl_generation_key
+
+ thread[@request_key] = nil
+ thread[@timeout_key] = nil
+ end
+
+ ##
+ # Shuts down all connections in all threads
+ #
+ # *NOTE*: THIS METHOD IS VERY DANGEROUS!
+ #
+ # Do not call this method if other threads are still using their
+ # connections! Call #shutdown at the appropriate time instead!
+ #
+ # Use this method only as a last resort!
+
+ def shutdown_in_all_threads
+ Thread.list.each do |thread|
+ shutdown thread
+ end
+
+ nil
+ end
+
+ ##
+ # Enables SSL on +connection+
+
+ def ssl connection
+ connection.use_ssl = true
+
+ connection.ssl_version = @ssl_version if @ssl_version
+
+ connection.verify_mode = @verify_mode
+
+ if OpenSSL::SSL::VERIFY_PEER == OpenSSL::SSL::VERIFY_NONE and
+ not Object.const_defined?(:I_KNOW_THAT_OPENSSL_VERIFY_PEER_EQUALS_VERIFY_NONE_IS_WRONG) then
+ warn <<-WARNING
+ !!!SECURITY WARNING!!!
+
+The SSL HTTP connection to:
+
+ #{connection.address}:#{connection.port}
+
+ !!!MAY NOT BE VERIFIED!!!
+
+On your platform your OpenSSL implementation is broken.
+
+There is no difference between the values of VERIFY_NONE and VERIFY_PEER.
+
+This means that attempting to verify the security of SSL connections may not
+work. This exposes you to man-in-the-middle exploits, snooping on the
+contents of your connection and other dangers to the security of your data.
+
+To disable this warning define the following constant at top-level in your
+application:
+
+ I_KNOW_THAT_OPENSSL_VERIFY_PEER_EQUALS_VERIFY_NONE_IS_WRONG = nil
+
+ WARNING
+ end
+
+ if @ca_file then
+ connection.ca_file = @ca_file
+ connection.verify_mode = OpenSSL::SSL::VERIFY_PEER
+ connection.verify_callback = @verify_callback if @verify_callback
+ end
+
+ if @certificate and @private_key then
+ connection.cert = @certificate
+ connection.key = @private_key
+ end
+
+ connection.cert_store = if @cert_store then
+ @cert_store
+ else
+ store = OpenSSL::X509::Store.new
+ store.set_default_paths
+ store
+ end
+ end
+
+ ##
+ # Finishes all connections that existed before the given SSL parameter
+ # +generation+.
+
+ def ssl_cleanup generation # :nodoc:
+ cleanup generation, Thread.current, @ssl_generation_key
+ end
+
+ ##
+ # SSL version to use
+
+ def ssl_version= ssl_version
+ @ssl_version = ssl_version
+
+ reconnect_ssl
+ end if RUBY_VERSION > '1.9'
+
+ ##
+ # Sets the HTTPS verify mode. Defaults to OpenSSL::SSL::VERIFY_PEER.
+ #
+ # Setting this to VERIFY_NONE is a VERY BAD IDEA and should NEVER be used.
+ # Securely transfer the correct certificate and update the default
+ # certificate store or set the ca file instead.
+
+ def verify_mode= verify_mode
+ @verify_mode = verify_mode
+
+ reconnect_ssl
+ end
+
+ ##
+ # SSL verification callback.
+
+ def verify_callback= callback
+ @verify_callback = callback
+
+ reconnect_ssl
+ end
+
+end
+
+require 'bundler/vendor/net-http-persistent/lib/net/http/persistent/ssl_reuse'
+
diff --git a/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/ssl_reuse.rb b/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/ssl_reuse.rb
new file mode 100644
index 0000000000..1b6b789f6d
--- /dev/null
+++ b/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/ssl_reuse.rb
@@ -0,0 +1,129 @@
+##
+# This Net::HTTP subclass adds SSL session reuse and Server Name Indication
+# (SNI) RFC 3546.
+#
+# DO NOT DEPEND UPON THIS CLASS
+#
+# This class is an implementation detail and is subject to change or removal
+# at any time.
+
+class Bundler::Persistent::Net::HTTP::Persistent::SSLReuse < Net::HTTP
+
+ @is_proxy_class = false
+ @proxy_addr = nil
+ @proxy_port = nil
+ @proxy_user = nil
+ @proxy_pass = nil
+
+ def initialize address, port = nil # :nodoc:
+ super
+
+ @ssl_session = nil
+ end
+
+ ##
+ # From ruby trunk r33086 including http://redmine.ruby-lang.org/issues/5341
+
+ def connect # :nodoc:
+ D "opening connection to #{conn_address()}..."
+ s = timeout(@open_timeout) { TCPSocket.open(conn_address(), conn_port()) }
+ D "opened"
+ if use_ssl?
+ ssl_parameters = Hash.new
+ iv_list = instance_variables
+ SSL_ATTRIBUTES.each do |name|
+ ivname = "@#{name}".intern
+ if iv_list.include?(ivname) and
+ value = instance_variable_get(ivname)
+ ssl_parameters[name] = value
+ end
+ end
+ unless @ssl_context then
+ @ssl_context = OpenSSL::SSL::SSLContext.new
+ @ssl_context.set_params(ssl_parameters)
+ end
+ s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
+ s.sync_close = true
+ end
+ @socket = Net::BufferedIO.new(s)
+ @socket.read_timeout = @read_timeout
+ @socket.continue_timeout = @continue_timeout if
+ @socket.respond_to? :continue_timeout
+ @socket.debug_output = @debug_output
+ if use_ssl?
+ begin
+ if proxy?
+ @socket.writeline sprintf('CONNECT %s:%s HTTP/%s',
+ @address, @port, HTTPVersion)
+ @socket.writeline "Host: #{@address}:#{@port}"
+ if proxy_user
+ credential = ["#{proxy_user}:#{proxy_pass}"].pack('m')
+ credential.delete!("\r\n")
+ @socket.writeline "Proxy-Authorization: Basic #{credential}"
+ end
+ @socket.writeline ''
+ Net::HTTPResponse.read_new(@socket).value
+ end
+ s.session = @ssl_session if @ssl_session
+ # Server Name Indication (SNI) RFC 3546
+ s.hostname = @address if s.respond_to? :hostname=
+ timeout(@open_timeout) { s.connect }
+ if @ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE
+ s.post_connection_check(@address)
+ end
+ @ssl_session = s.session
+ rescue => exception
+ D "Conn close because of connect error #{exception}"
+ @socket.close if @socket and not @socket.closed?
+ raise exception
+ end
+ end
+ on_connect
+ end if RUBY_VERSION > '1.9'
+
+ ##
+ # From ruby_1_8_7 branch r29865 including a modified
+ # http://redmine.ruby-lang.org/issues/5341
+
+ def connect # :nodoc:
+ D "opening connection to #{conn_address()}..."
+ s = timeout(@open_timeout) { TCPSocket.open(conn_address(), conn_port()) }
+ D "opened"
+ if use_ssl?
+ unless @ssl_context.verify_mode
+ warn "warning: peer certificate won't be verified in this SSL session"
+ @ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
+ end
+ s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
+ s.sync_close = true
+ end
+ @socket = Net::BufferedIO.new(s)
+ @socket.read_timeout = @read_timeout
+ @socket.debug_output = @debug_output
+ if use_ssl?
+ if proxy?
+ @socket.writeline sprintf('CONNECT %s:%s HTTP/%s',
+ @address, @port, HTTPVersion)
+ @socket.writeline "Host: #{@address}:#{@port}"
+ if proxy_user
+ credential = ["#{proxy_user}:#{proxy_pass}"].pack('m')
+ credential.delete!("\r\n")
+ @socket.writeline "Proxy-Authorization: Basic #{credential}"
+ end
+ @socket.writeline ''
+ Net::HTTPResponse.read_new(@socket).value
+ end
+ s.session = @ssl_session if @ssl_session
+ s.connect
+ if @ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE
+ s.post_connection_check(@address)
+ end
+ @ssl_session = s.session
+ end
+ on_connect
+ end if RUBY_VERSION < '1.9'
+
+ private :connect
+
+end
+
diff --git a/lib/bundler/vendor/thor/lib/thor.rb b/lib/bundler/vendor/thor/lib/thor.rb
new file mode 100644
index 0000000000..999e8b7e61
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor.rb
@@ -0,0 +1,509 @@
+require "set"
+require "bundler/vendor/thor/lib/thor/base"
+
+class Bundler::Thor
+ class << self
+ # Allows for custom "Command" package naming.
+ #
+ # === Parameters
+ # name<String>
+ # options<Hash>
+ #
+ def package_name(name, _ = {})
+ @package_name = name.nil? || name == "" ? nil : name
+ end
+
+ # Sets the default command when thor is executed without an explicit command to be called.
+ #
+ # ==== Parameters
+ # meth<Symbol>:: name of the default command
+ #
+ def default_command(meth = nil)
+ if meth
+ @default_command = meth == :none ? "help" : meth.to_s
+ else
+ @default_command ||= from_superclass(:default_command, "help")
+ end
+ end
+ alias_method :default_task, :default_command
+
+ # Registers another Bundler::Thor subclass as a command.
+ #
+ # ==== Parameters
+ # klass<Class>:: Bundler::Thor subclass to register
+ # command<String>:: Subcommand name to use
+ # usage<String>:: Short usage for the subcommand
+ # description<String>:: Description for the subcommand
+ def register(klass, subcommand_name, usage, description, options = {})
+ if klass <= Bundler::Thor::Group
+ desc usage, description, options
+ define_method(subcommand_name) { |*args| invoke(klass, args) }
+ else
+ desc usage, description, options
+ subcommand subcommand_name, klass
+ end
+ end
+
+ # Defines the usage and the description of the next command.
+ #
+ # ==== Parameters
+ # usage<String>
+ # description<String>
+ # options<String>
+ #
+ def desc(usage, description, options = {})
+ if options[:for]
+ command = find_and_refresh_command(options[:for])
+ command.usage = usage if usage
+ command.description = description if description
+ else
+ @usage = usage
+ @desc = description
+ @hide = options[:hide] || false
+ end
+ end
+
+ # Defines the long description of the next command.
+ #
+ # ==== Parameters
+ # long description<String>
+ #
+ def long_desc(long_description, options = {})
+ if options[:for]
+ command = find_and_refresh_command(options[:for])
+ command.long_description = long_description if long_description
+ else
+ @long_desc = long_description
+ end
+ end
+
+ # Maps an input to a command. If you define:
+ #
+ # map "-T" => "list"
+ #
+ # Running:
+ #
+ # thor -T
+ #
+ # Will invoke the list command.
+ #
+ # ==== Parameters
+ # Hash[String|Array => Symbol]:: Maps the string or the strings in the array to the given command.
+ #
+ def map(mappings = nil)
+ @map ||= from_superclass(:map, {})
+
+ if mappings
+ mappings.each do |key, value|
+ if key.respond_to?(:each)
+ key.each { |subkey| @map[subkey] = value }
+ else
+ @map[key] = value
+ end
+ end
+ end
+
+ @map
+ end
+
+ # Declares the options for the next command to be declared.
+ #
+ # ==== Parameters
+ # Hash[Symbol => Object]:: The hash key is the name of the option and the value
+ # is the type of the option. Can be :string, :array, :hash, :boolean, :numeric
+ # or :required (string). If you give a value, the type of the value is used.
+ #
+ def method_options(options = nil)
+ @method_options ||= {}
+ build_options(options, @method_options) if options
+ @method_options
+ end
+
+ alias_method :options, :method_options
+
+ # Adds an option to the set of method options. If :for is given as option,
+ # it allows you to change the options from a previous defined command.
+ #
+ # def previous_command
+ # # magic
+ # end
+ #
+ # method_option :foo => :bar, :for => :previous_command
+ #
+ # def next_command
+ # # magic
+ # end
+ #
+ # ==== Parameters
+ # name<Symbol>:: The name of the argument.
+ # options<Hash>:: Described below.
+ #
+ # ==== Options
+ # :desc - Description for the argument.
+ # :required - If the argument is required or not.
+ # :default - Default value for this argument. It cannot be required and have default values.
+ # :aliases - Aliases for this option.
+ # :type - The type of the argument, can be :string, :hash, :array, :numeric or :boolean.
+ # :banner - String to show on usage notes.
+ # :hide - If you want to hide this option from the help.
+ #
+ def method_option(name, options = {})
+ scope = if options[:for]
+ find_and_refresh_command(options[:for]).options
+ else
+ method_options
+ end
+
+ build_option(name, options, scope)
+ end
+ alias_method :option, :method_option
+
+ # Prints help information for the given command.
+ #
+ # ==== Parameters
+ # shell<Bundler::Thor::Shell>
+ # command_name<String>
+ #
+ def command_help(shell, command_name)
+ meth = normalize_command_name(command_name)
+ command = all_commands[meth]
+ handle_no_command_error(meth) unless command
+
+ shell.say "Usage:"
+ shell.say " #{banner(command)}"
+ shell.say
+ class_options_help(shell, nil => command.options.values)
+ if command.long_description
+ shell.say "Description:"
+ shell.print_wrapped(command.long_description, :indent => 2)
+ else
+ shell.say command.description
+ end
+ end
+ alias_method :task_help, :command_help
+
+ # Prints help information for this class.
+ #
+ # ==== Parameters
+ # shell<Bundler::Thor::Shell>
+ #
+ def help(shell, subcommand = false)
+ list = printable_commands(true, subcommand)
+ Bundler::Thor::Util.thor_classes_in(self).each do |klass|
+ list += klass.printable_commands(false)
+ end
+ list.sort! { |a, b| a[0] <=> b[0] }
+
+ if defined?(@package_name) && @package_name
+ shell.say "#{@package_name} commands:"
+ else
+ shell.say "Commands:"
+ end
+
+ shell.print_table(list, :indent => 2, :truncate => true)
+ shell.say
+ class_options_help(shell)
+ end
+
+ # Returns commands ready to be printed.
+ def printable_commands(all = true, subcommand = false)
+ (all ? all_commands : commands).map do |_, command|
+ next if command.hidden?
+ item = []
+ item << banner(command, false, subcommand)
+ item << (command.description ? "# #{command.description.gsub(/\s+/m, ' ')}" : "")
+ item
+ end.compact
+ end
+ alias_method :printable_tasks, :printable_commands
+
+ def subcommands
+ @subcommands ||= from_superclass(:subcommands, [])
+ end
+ alias_method :subtasks, :subcommands
+
+ def subcommand_classes
+ @subcommand_classes ||= {}
+ end
+
+ def subcommand(subcommand, subcommand_class)
+ subcommands << subcommand.to_s
+ subcommand_class.subcommand_help subcommand
+ subcommand_classes[subcommand.to_s] = subcommand_class
+
+ define_method(subcommand) do |*args|
+ args, opts = Bundler::Thor::Arguments.split(args)
+ invoke_args = [args, opts, {:invoked_via_subcommand => true, :class_options => options}]
+ invoke_args.unshift "help" if opts.delete("--help") || opts.delete("-h")
+ invoke subcommand_class, *invoke_args
+ end
+ subcommand_class.commands.each do |_meth, command|
+ command.ancestor_name = subcommand
+ end
+ end
+ alias_method :subtask, :subcommand
+
+ # Extend check unknown options to accept a hash of conditions.
+ #
+ # === Parameters
+ # options<Hash>: A hash containing :only and/or :except keys
+ def check_unknown_options!(options = {})
+ @check_unknown_options ||= {}
+ options.each do |key, value|
+ if value
+ @check_unknown_options[key] = Array(value)
+ else
+ @check_unknown_options.delete(key)
+ end
+ end
+ @check_unknown_options
+ end
+
+ # Overwrite check_unknown_options? to take subcommands and options into account.
+ def check_unknown_options?(config) #:nodoc:
+ options = check_unknown_options
+ return false unless options
+
+ command = config[:current_command]
+ return true unless command
+
+ name = command.name
+
+ if subcommands.include?(name)
+ false
+ elsif options[:except]
+ !options[:except].include?(name.to_sym)
+ elsif options[:only]
+ options[:only].include?(name.to_sym)
+ else
+ true
+ end
+ end
+
+ # Stop parsing of options as soon as an unknown option or a regular
+ # argument is encountered. All remaining arguments are passed to the command.
+ # This is useful if you have a command that can receive arbitrary additional
+ # options, and where those additional options should not be handled by
+ # Bundler::Thor.
+ #
+ # ==== Example
+ #
+ # To better understand how this is useful, let's consider a command that calls
+ # an external command. A user may want to pass arbitrary options and
+ # arguments to that command. The command itself also accepts some options,
+ # which should be handled by Bundler::Thor.
+ #
+ # class_option "verbose", :type => :boolean
+ # stop_on_unknown_option! :exec
+ # check_unknown_options! :except => :exec
+ #
+ # desc "exec", "Run a shell command"
+ # def exec(*args)
+ # puts "diagnostic output" if options[:verbose]
+ # Kernel.exec(*args)
+ # end
+ #
+ # Here +exec+ can be called with +--verbose+ to get diagnostic output,
+ # e.g.:
+ #
+ # $ thor exec --verbose echo foo
+ # diagnostic output
+ # foo
+ #
+ # But if +--verbose+ is given after +echo+, it is passed to +echo+ instead:
+ #
+ # $ thor exec echo --verbose foo
+ # --verbose foo
+ #
+ # ==== Parameters
+ # Symbol ...:: A list of commands that should be affected.
+ def stop_on_unknown_option!(*command_names)
+ stop_on_unknown_option.merge(command_names)
+ end
+
+ def stop_on_unknown_option?(command) #:nodoc:
+ command && stop_on_unknown_option.include?(command.name.to_sym)
+ end
+
+ # Disable the check for required options for the given commands.
+ # This is useful if you have a command that does not need the required options
+ # to work, like help.
+ #
+ # ==== Parameters
+ # Symbol ...:: A list of commands that should be affected.
+ def disable_required_check!(*command_names)
+ disable_required_check.merge(command_names)
+ end
+
+ def disable_required_check?(command) #:nodoc:
+ command && disable_required_check.include?(command.name.to_sym)
+ end
+
+ protected
+
+ def stop_on_unknown_option #:nodoc:
+ @stop_on_unknown_option ||= Set.new
+ end
+
+ # help command has the required check disabled by default.
+ def disable_required_check #:nodoc:
+ @disable_required_check ||= Set.new([:help])
+ end
+
+ # The method responsible for dispatching given the args.
+ def dispatch(meth, given_args, given_opts, config) #:nodoc: # rubocop:disable MethodLength
+ meth ||= retrieve_command_name(given_args)
+ command = all_commands[normalize_command_name(meth)]
+
+ if !command && config[:invoked_via_subcommand]
+ # We're a subcommand and our first argument didn't match any of our
+ # commands. So we put it back and call our default command.
+ given_args.unshift(meth)
+ command = all_commands[normalize_command_name(default_command)]
+ end
+
+ if command
+ args, opts = Bundler::Thor::Options.split(given_args)
+ if stop_on_unknown_option?(command) && !args.empty?
+ # given_args starts with a non-option, so we treat everything as
+ # ordinary arguments
+ args.concat opts
+ opts.clear
+ end
+ else
+ args = given_args
+ opts = nil
+ command = dynamic_command_class.new(meth)
+ end
+
+ opts = given_opts || opts || []
+ config[:current_command] = command
+ config[:command_options] = command.options
+
+ instance = new(args, opts, config)
+ yield instance if block_given?
+ args = instance.args
+ trailing = args[Range.new(arguments.size, -1)]
+ instance.invoke_command(command, trailing || [])
+ end
+
+ # The banner for this class. You can customize it if you are invoking the
+ # thor class by another ways which is not the Bundler::Thor::Runner. It receives
+ # the command that is going to be invoked and a boolean which indicates if
+ # the namespace should be displayed as arguments.
+ #
+ def banner(command, namespace = nil, subcommand = false)
+ "#{basename} #{command.formatted_usage(self, $thor_runner, subcommand)}"
+ end
+
+ def baseclass #:nodoc:
+ Bundler::Thor
+ end
+
+ def dynamic_command_class #:nodoc:
+ Bundler::Thor::DynamicCommand
+ end
+
+ def create_command(meth) #:nodoc:
+ @usage ||= nil
+ @desc ||= nil
+ @long_desc ||= nil
+ @hide ||= nil
+
+ if @usage && @desc
+ base_class = @hide ? Bundler::Thor::HiddenCommand : Bundler::Thor::Command
+ commands[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options)
+ @usage, @desc, @long_desc, @method_options, @hide = nil
+ true
+ elsif all_commands[meth] || meth == "method_missing"
+ true
+ else
+ puts "[WARNING] Attempted to create command #{meth.inspect} without usage or description. " \
+ "Call desc if you want this method to be available as command or declare it inside a " \
+ "no_commands{} block. Invoked from #{caller[1].inspect}."
+ false
+ end
+ end
+ alias_method :create_task, :create_command
+
+ def initialize_added #:nodoc:
+ class_options.merge!(method_options)
+ @method_options = nil
+ end
+
+ # Retrieve the command name from given args.
+ def retrieve_command_name(args) #:nodoc:
+ meth = args.first.to_s unless args.empty?
+ args.shift if meth && (map[meth] || meth !~ /^\-/)
+ end
+ alias_method :retrieve_task_name, :retrieve_command_name
+
+ # receives a (possibly nil) command name and returns a name that is in
+ # the commands hash. In addition to normalizing aliases, this logic
+ # will determine if a shortened command is an unambiguous substring of
+ # a command or alias.
+ #
+ # +normalize_command_name+ also converts names like +animal-prison+
+ # into +animal_prison+.
+ def normalize_command_name(meth) #:nodoc:
+ return default_command.to_s.tr("-", "_") unless meth
+
+ possibilities = find_command_possibilities(meth)
+ raise AmbiguousTaskError, "Ambiguous command #{meth} matches [#{possibilities.join(', ')}]" if possibilities.size > 1
+
+ if possibilities.empty?
+ meth ||= default_command
+ elsif map[meth]
+ meth = map[meth]
+ else
+ meth = possibilities.first
+ end
+
+ meth.to_s.tr("-", "_") # treat foo-bar as foo_bar
+ end
+ alias_method :normalize_task_name, :normalize_command_name
+
+ # this is the logic that takes the command name passed in by the user
+ # and determines whether it is an unambiguous substrings of a command or
+ # alias name.
+ def find_command_possibilities(meth)
+ len = meth.to_s.length
+ possibilities = all_commands.merge(map).keys.select { |n| meth == n[0, len] }.sort
+ unique_possibilities = possibilities.map { |k| map[k] || k }.uniq
+
+ if possibilities.include?(meth)
+ [meth]
+ elsif unique_possibilities.size == 1
+ unique_possibilities
+ else
+ possibilities
+ end
+ end
+ alias_method :find_task_possibilities, :find_command_possibilities
+
+ def subcommand_help(cmd)
+ desc "help [COMMAND]", "Describe subcommands or one specific subcommand"
+ class_eval "
+ def help(command = nil, subcommand = true); super; end
+"
+ end
+ alias_method :subtask_help, :subcommand_help
+ end
+
+ include Bundler::Thor::Base
+
+ map HELP_MAPPINGS => :help
+
+ desc "help [COMMAND]", "Describe available commands or one specific command"
+ def help(command = nil, subcommand = false)
+ if command
+ if self.class.subcommands.include? command
+ self.class.subcommand_classes[command].help(shell, true)
+ else
+ self.class.command_help(shell, command)
+ end
+ else
+ self.class.help(shell, subcommand)
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/actions.rb b/lib/bundler/vendor/thor/lib/thor/actions.rb
new file mode 100644
index 0000000000..e6698572a9
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/actions.rb
@@ -0,0 +1,321 @@
+require "uri"
+require "bundler/vendor/thor/lib/thor/core_ext/io_binary_read"
+require "bundler/vendor/thor/lib/thor/actions/create_file"
+require "bundler/vendor/thor/lib/thor/actions/create_link"
+require "bundler/vendor/thor/lib/thor/actions/directory"
+require "bundler/vendor/thor/lib/thor/actions/empty_directory"
+require "bundler/vendor/thor/lib/thor/actions/file_manipulation"
+require "bundler/vendor/thor/lib/thor/actions/inject_into_file"
+
+class Bundler::Thor
+ module Actions
+ attr_accessor :behavior
+
+ def self.included(base) #:nodoc:
+ base.extend ClassMethods
+ end
+
+ module ClassMethods
+ # Hold source paths for one Bundler::Thor instance. source_paths_for_search is the
+ # method responsible to gather source_paths from this current class,
+ # inherited paths and the source root.
+ #
+ def source_paths
+ @_source_paths ||= []
+ end
+
+ # Stores and return the source root for this class
+ def source_root(path = nil)
+ @_source_root = path if path
+ @_source_root ||= nil
+ end
+
+ # Returns the source paths in the following order:
+ #
+ # 1) This class source paths
+ # 2) Source root
+ # 3) Parents source paths
+ #
+ def source_paths_for_search
+ paths = []
+ paths += source_paths
+ paths << source_root if source_root
+ paths += from_superclass(:source_paths, [])
+ paths
+ end
+
+ # Add runtime options that help actions execution.
+ #
+ def add_runtime_options!
+ class_option :force, :type => :boolean, :aliases => "-f", :group => :runtime,
+ :desc => "Overwrite files that already exist"
+
+ class_option :pretend, :type => :boolean, :aliases => "-p", :group => :runtime,
+ :desc => "Run but do not make any changes"
+
+ class_option :quiet, :type => :boolean, :aliases => "-q", :group => :runtime,
+ :desc => "Suppress status output"
+
+ class_option :skip, :type => :boolean, :aliases => "-s", :group => :runtime,
+ :desc => "Skip files that already exist"
+ end
+ end
+
+ # Extends initializer to add more configuration options.
+ #
+ # ==== Configuration
+ # behavior<Symbol>:: The actions default behavior. Can be :invoke or :revoke.
+ # It also accepts :force, :skip and :pretend to set the behavior
+ # and the respective option.
+ #
+ # destination_root<String>:: The root directory needed for some actions.
+ #
+ def initialize(args = [], options = {}, config = {})
+ self.behavior = case config[:behavior].to_s
+ when "force", "skip"
+ _cleanup_options_and_set(options, config[:behavior])
+ :invoke
+ when "revoke"
+ :revoke
+ else
+ :invoke
+ end
+
+ super
+ self.destination_root = config[:destination_root]
+ end
+
+ # Wraps an action object and call it accordingly to the thor class behavior.
+ #
+ def action(instance) #:nodoc:
+ if behavior == :revoke
+ instance.revoke!
+ else
+ instance.invoke!
+ end
+ end
+
+ # Returns the root for this thor class (also aliased as destination root).
+ #
+ def destination_root
+ @destination_stack.last
+ end
+
+ # Sets the root for this thor class. Relatives path are added to the
+ # directory where the script was invoked and expanded.
+ #
+ def destination_root=(root)
+ @destination_stack ||= []
+ @destination_stack[0] = File.expand_path(root || "")
+ end
+
+ # Returns the given path relative to the absolute root (ie, root where
+ # the script started).
+ #
+ def relative_to_original_destination_root(path, remove_dot = true)
+ path = path.dup
+ if path.gsub!(@destination_stack[0], ".")
+ remove_dot ? (path[2..-1] || "") : path
+ else
+ path
+ end
+ end
+
+ # Holds source paths in instance so they can be manipulated.
+ #
+ def source_paths
+ @source_paths ||= self.class.source_paths_for_search
+ end
+
+ # Receives a file or directory and search for it in the source paths.
+ #
+ def find_in_source_paths(file)
+ possible_files = [file, file + TEMPLATE_EXTNAME]
+ relative_root = relative_to_original_destination_root(destination_root, false)
+
+ source_paths.each do |source|
+ possible_files.each do |f|
+ source_file = File.expand_path(f, File.join(source, relative_root))
+ return source_file if File.exist?(source_file)
+ end
+ end
+
+ message = "Could not find #{file.inspect} in any of your source paths. ".dup
+
+ unless self.class.source_root
+ message << "Please invoke #{self.class.name}.source_root(PATH) with the PATH containing your templates. "
+ end
+
+ message << if source_paths.empty?
+ "Currently you have no source paths."
+ else
+ "Your current source paths are: \n#{source_paths.join("\n")}"
+ end
+
+ raise Error, message
+ end
+
+ # Do something in the root or on a provided subfolder. If a relative path
+ # is given it's referenced from the current root. The full path is yielded
+ # to the block you provide. The path is set back to the previous path when
+ # the method exits.
+ #
+ # ==== Parameters
+ # dir<String>:: the directory to move to.
+ # config<Hash>:: give :verbose => true to log and use padding.
+ #
+ def inside(dir = "", config = {}, &block)
+ verbose = config.fetch(:verbose, false)
+ pretend = options[:pretend]
+
+ say_status :inside, dir, verbose
+ shell.padding += 1 if verbose
+ @destination_stack.push File.expand_path(dir, destination_root)
+
+ # If the directory doesnt exist and we're not pretending
+ if !File.exist?(destination_root) && !pretend
+ require "fileutils"
+ FileUtils.mkdir_p(destination_root)
+ end
+
+ if pretend
+ # In pretend mode, just yield down to the block
+ block.arity == 1 ? yield(destination_root) : yield
+ else
+ require "fileutils"
+ FileUtils.cd(destination_root) { block.arity == 1 ? yield(destination_root) : yield }
+ end
+
+ @destination_stack.pop
+ shell.padding -= 1 if verbose
+ end
+
+ # Goes to the root and execute the given block.
+ #
+ def in_root
+ inside(@destination_stack.first) { yield }
+ end
+
+ # Loads an external file and execute it in the instance binding.
+ #
+ # ==== Parameters
+ # path<String>:: The path to the file to execute. Can be a web address or
+ # a relative path from the source root.
+ #
+ # ==== Examples
+ #
+ # apply "http://gist.github.com/103208"
+ #
+ # apply "recipes/jquery.rb"
+ #
+ def apply(path, config = {})
+ verbose = config.fetch(:verbose, true)
+ is_uri = path =~ %r{^https?\://}
+ path = find_in_source_paths(path) unless is_uri
+
+ say_status :apply, path, verbose
+ shell.padding += 1 if verbose
+
+ contents = if is_uri
+ open(path, "Accept" => "application/x-thor-template", &:read)
+ else
+ open(path, &:read)
+ end
+
+ instance_eval(contents, path)
+ shell.padding -= 1 if verbose
+ end
+
+ # Executes a command returning the contents of the command.
+ #
+ # ==== Parameters
+ # command<String>:: the command to be executed.
+ # config<Hash>:: give :verbose => false to not log the status, :capture => true to hide to output. Specify :with
+ # to append an executable to command execution.
+ #
+ # ==== Example
+ #
+ # inside('vendor') do
+ # run('ln -s ~/edge rails')
+ # end
+ #
+ def run(command, config = {})
+ return unless behavior == :invoke
+
+ destination = relative_to_original_destination_root(destination_root, false)
+ desc = "#{command} from #{destination.inspect}"
+
+ if config[:with]
+ desc = "#{File.basename(config[:with].to_s)} #{desc}"
+ command = "#{config[:with]} #{command}"
+ end
+
+ say_status :run, desc, config.fetch(:verbose, true)
+
+ unless options[:pretend]
+ config[:capture] ? `#{command}` : system(command.to_s)
+ end
+ end
+
+ # Executes a ruby script (taking into account WIN32 platform quirks).
+ #
+ # ==== Parameters
+ # command<String>:: the command to be executed.
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ def run_ruby_script(command, config = {})
+ return unless behavior == :invoke
+ run command, config.merge(:with => Bundler::Thor::Util.ruby_command)
+ end
+
+ # Run a thor command. A hash of options can be given and it's converted to
+ # switches.
+ #
+ # ==== Parameters
+ # command<String>:: the command to be invoked
+ # args<Array>:: arguments to the command
+ # config<Hash>:: give :verbose => false to not log the status, :capture => true to hide to output.
+ # Other options are given as parameter to Bundler::Thor.
+ #
+ #
+ # ==== Examples
+ #
+ # thor :install, "http://gist.github.com/103208"
+ # #=> thor install http://gist.github.com/103208
+ #
+ # thor :list, :all => true, :substring => 'rails'
+ # #=> thor list --all --substring=rails
+ #
+ def thor(command, *args)
+ config = args.last.is_a?(Hash) ? args.pop : {}
+ verbose = config.key?(:verbose) ? config.delete(:verbose) : true
+ pretend = config.key?(:pretend) ? config.delete(:pretend) : false
+ capture = config.key?(:capture) ? config.delete(:capture) : false
+
+ args.unshift(command)
+ args.push Bundler::Thor::Options.to_switches(config)
+ command = args.join(" ").strip
+
+ run command, :with => :thor, :verbose => verbose, :pretend => pretend, :capture => capture
+ end
+
+ protected
+
+ # Allow current root to be shared between invocations.
+ #
+ def _shared_configuration #:nodoc:
+ super.merge!(:destination_root => destination_root)
+ end
+
+ def _cleanup_options_and_set(options, key) #:nodoc:
+ case options
+ when Array
+ %w(--force -f --skip -s).each { |i| options.delete(i) }
+ options << "--#{key}"
+ when Hash
+ [:force, :skip, "force", "skip"].each { |i| options.delete(i) }
+ options.merge!(key => true)
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/actions/create_file.rb b/lib/bundler/vendor/thor/lib/thor/actions/create_file.rb
new file mode 100644
index 0000000000..97d22d9bbd
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/actions/create_file.rb
@@ -0,0 +1,104 @@
+require "bundler/vendor/thor/lib/thor/actions/empty_directory"
+
+class Bundler::Thor
+ module Actions
+ # Create a new file relative to the destination root with the given data,
+ # which is the return value of a block or a data string.
+ #
+ # ==== Parameters
+ # destination<String>:: the relative path to the destination root.
+ # data<String|NilClass>:: the data to append to the file.
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ # ==== Examples
+ #
+ # create_file "lib/fun_party.rb" do
+ # hostname = ask("What is the virtual hostname I should use?")
+ # "vhost.name = #{hostname}"
+ # end
+ #
+ # create_file "config/apache.conf", "your apache config"
+ #
+ def create_file(destination, *args, &block)
+ config = args.last.is_a?(Hash) ? args.pop : {}
+ data = args.first
+ action CreateFile.new(self, destination, block || data.to_s, config)
+ end
+ alias_method :add_file, :create_file
+
+ # CreateFile is a subset of Template, which instead of rendering a file with
+ # ERB, it gets the content from the user.
+ #
+ class CreateFile < EmptyDirectory #:nodoc:
+ attr_reader :data
+
+ def initialize(base, destination, data, config = {})
+ @data = data
+ super(base, destination, config)
+ end
+
+ # Checks if the content of the file at the destination is identical to the rendered result.
+ #
+ # ==== Returns
+ # Boolean:: true if it is identical, false otherwise.
+ #
+ def identical?
+ exists? && File.binread(destination) == render
+ end
+
+ # Holds the content to be added to the file.
+ #
+ def render
+ @render ||= if data.is_a?(Proc)
+ data.call
+ else
+ data
+ end
+ end
+
+ def invoke!
+ invoke_with_conflict_check do
+ require "fileutils"
+ FileUtils.mkdir_p(File.dirname(destination))
+ File.open(destination, "wb") { |f| f.write render }
+ end
+ given_destination
+ end
+
+ protected
+
+ # Now on conflict we check if the file is identical or not.
+ #
+ def on_conflict_behavior(&block)
+ if identical?
+ say_status :identical, :blue
+ else
+ options = base.options.merge(config)
+ force_or_skip_or_conflict(options[:force], options[:skip], &block)
+ end
+ end
+
+ # If force is true, run the action, otherwise check if it's not being
+ # skipped. If both are false, show the file_collision menu, if the menu
+ # returns true, force it, otherwise skip.
+ #
+ def force_or_skip_or_conflict(force, skip, &block)
+ if force
+ say_status :force, :yellow
+ yield unless pretend?
+ elsif skip
+ say_status :skip, :yellow
+ else
+ say_status :conflict, :red
+ force_or_skip_or_conflict(force_on_collision?, true, &block)
+ end
+ end
+
+ # Shows the file collision menu to the user and gets the result.
+ #
+ def force_on_collision?
+ base.shell.file_collision(destination) { render }
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/actions/create_link.rb b/lib/bundler/vendor/thor/lib/thor/actions/create_link.rb
new file mode 100644
index 0000000000..3a664401b4
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/actions/create_link.rb
@@ -0,0 +1,60 @@
+require "bundler/vendor/thor/lib/thor/actions/create_file"
+
+class Bundler::Thor
+ module Actions
+ # Create a new file relative to the destination root from the given source.
+ #
+ # ==== Parameters
+ # destination<String>:: the relative path to the destination root.
+ # source<String|NilClass>:: the relative path to the source root.
+ # config<Hash>:: give :verbose => false to not log the status.
+ # :: give :symbolic => false for hard link.
+ #
+ # ==== Examples
+ #
+ # create_link "config/apache.conf", "/etc/apache.conf"
+ #
+ def create_link(destination, *args)
+ config = args.last.is_a?(Hash) ? args.pop : {}
+ source = args.first
+ action CreateLink.new(self, destination, source, config)
+ end
+ alias_method :add_link, :create_link
+
+ # CreateLink is a subset of CreateFile, which instead of taking a block of
+ # data, just takes a source string from the user.
+ #
+ class CreateLink < CreateFile #:nodoc:
+ attr_reader :data
+
+ # Checks if the content of the file at the destination is identical to the rendered result.
+ #
+ # ==== Returns
+ # Boolean:: true if it is identical, false otherwise.
+ #
+ def identical?
+ exists? && File.identical?(render, destination)
+ end
+
+ def invoke!
+ invoke_with_conflict_check do
+ require "fileutils"
+ FileUtils.mkdir_p(File.dirname(destination))
+ # Create a symlink by default
+ config[:symbolic] = true if config[:symbolic].nil?
+ File.unlink(destination) if exists?
+ if config[:symbolic]
+ File.symlink(render, destination)
+ else
+ File.link(render, destination)
+ end
+ end
+ given_destination
+ end
+
+ def exists?
+ super || File.symlink?(destination)
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/actions/directory.rb b/lib/bundler/vendor/thor/lib/thor/actions/directory.rb
new file mode 100644
index 0000000000..f555f7b7e0
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/actions/directory.rb
@@ -0,0 +1,118 @@
+require "bundler/vendor/thor/lib/thor/actions/empty_directory"
+
+class Bundler::Thor
+ module Actions
+ # Copies recursively the files from source directory to root directory.
+ # If any of the files finishes with .tt, it's considered to be a template
+ # and is placed in the destination without the extension .tt. If any
+ # empty directory is found, it's copied and all .empty_directory files are
+ # ignored. If any file name is wrapped within % signs, the text within
+ # the % signs will be executed as a method and replaced with the returned
+ # value. Let's suppose a doc directory with the following files:
+ #
+ # doc/
+ # components/.empty_directory
+ # README
+ # rdoc.rb.tt
+ # %app_name%.rb
+ #
+ # When invoked as:
+ #
+ # directory "doc"
+ #
+ # It will create a doc directory in the destination with the following
+ # files (assuming that the `app_name` method returns the value "blog"):
+ #
+ # doc/
+ # components/
+ # README
+ # rdoc.rb
+ # blog.rb
+ #
+ # <b>Encoded path note:</b> Since Bundler::Thor internals use Object#respond_to? to check if it can
+ # expand %something%, this `something` should be a public method in the class calling
+ # #directory. If a method is private, Bundler::Thor stack raises PrivateMethodEncodedError.
+ #
+ # ==== Parameters
+ # source<String>:: the relative path to the source root.
+ # destination<String>:: the relative path to the destination root.
+ # config<Hash>:: give :verbose => false to not log the status.
+ # If :recursive => false, does not look for paths recursively.
+ # If :mode => :preserve, preserve the file mode from the source.
+ # If :exclude_pattern => /regexp/, prevents copying files that match that regexp.
+ #
+ # ==== Examples
+ #
+ # directory "doc"
+ # directory "doc", "docs", :recursive => false
+ #
+ def directory(source, *args, &block)
+ config = args.last.is_a?(Hash) ? args.pop : {}
+ destination = args.first || source
+ action Directory.new(self, source, destination || source, config, &block)
+ end
+
+ class Directory < EmptyDirectory #:nodoc:
+ attr_reader :source
+
+ def initialize(base, source, destination = nil, config = {}, &block)
+ @source = File.expand_path(base.find_in_source_paths(source.to_s))
+ @block = block
+ super(base, destination, {:recursive => true}.merge(config))
+ end
+
+ def invoke!
+ base.empty_directory given_destination, config
+ execute!
+ end
+
+ def revoke!
+ execute!
+ end
+
+ protected
+
+ def execute!
+ lookup = Util.escape_globs(source)
+ lookup = config[:recursive] ? File.join(lookup, "**") : lookup
+ lookup = file_level_lookup(lookup)
+
+ files(lookup).sort.each do |file_source|
+ next if File.directory?(file_source)
+ next if config[:exclude_pattern] && file_source.match(config[:exclude_pattern])
+ file_destination = File.join(given_destination, file_source.gsub(source, "."))
+ file_destination.gsub!("/./", "/")
+
+ case file_source
+ when /\.empty_directory$/
+ dirname = File.dirname(file_destination).gsub(%r{/\.$}, "")
+ next if dirname == given_destination
+ base.empty_directory(dirname, config)
+ when /#{TEMPLATE_EXTNAME}$/
+ base.template(file_source, file_destination[0..-4], config, &@block)
+ else
+ base.copy_file(file_source, file_destination, config, &@block)
+ end
+ end
+ end
+
+ if RUBY_VERSION < "2.0"
+ def file_level_lookup(previous_lookup)
+ File.join(previous_lookup, "{*,.[a-z]*}")
+ end
+
+ def files(lookup)
+ Dir[lookup]
+ end
+ else
+ def file_level_lookup(previous_lookup)
+ File.join(previous_lookup, "*")
+ end
+
+ def files(lookup)
+ Dir.glob(lookup, File::FNM_DOTMATCH)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb b/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb
new file mode 100644
index 0000000000..284d92c19a
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb
@@ -0,0 +1,143 @@
+class Bundler::Thor
+ module Actions
+ # Creates an empty directory.
+ #
+ # ==== Parameters
+ # destination<String>:: the relative path to the destination root.
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ # ==== Examples
+ #
+ # empty_directory "doc"
+ #
+ def empty_directory(destination, config = {})
+ action EmptyDirectory.new(self, destination, config)
+ end
+
+ # Class which holds create directory logic. This is the base class for
+ # other actions like create_file and directory.
+ #
+ # This implementation is based in Templater actions, created by Jonas Nicklas
+ # and Michael S. Klishin under MIT LICENSE.
+ #
+ class EmptyDirectory #:nodoc:
+ attr_reader :base, :destination, :given_destination, :relative_destination, :config
+
+ # Initializes given the source and destination.
+ #
+ # ==== Parameters
+ # base<Bundler::Thor::Base>:: A Bundler::Thor::Base instance
+ # source<String>:: Relative path to the source of this file
+ # destination<String>:: Relative path to the destination of this file
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ def initialize(base, destination, config = {})
+ @base = base
+ @config = {:verbose => true}.merge(config)
+ self.destination = destination
+ end
+
+ # Checks if the destination file already exists.
+ #
+ # ==== Returns
+ # Boolean:: true if the file exists, false otherwise.
+ #
+ def exists?
+ ::File.exist?(destination)
+ end
+
+ def invoke!
+ invoke_with_conflict_check do
+ require "fileutils"
+ ::FileUtils.mkdir_p(destination)
+ end
+ end
+
+ def revoke!
+ say_status :remove, :red
+ require "fileutils"
+ ::FileUtils.rm_rf(destination) if !pretend? && exists?
+ given_destination
+ end
+
+ protected
+
+ # Shortcut for pretend.
+ #
+ def pretend?
+ base.options[:pretend]
+ end
+
+ # Sets the absolute destination value from a relative destination value.
+ # It also stores the given and relative destination. Let's suppose our
+ # script is being executed on "dest", it sets the destination root to
+ # "dest". The destination, given_destination and relative_destination
+ # are related in the following way:
+ #
+ # inside "bar" do
+ # empty_directory "baz"
+ # end
+ #
+ # destination #=> dest/bar/baz
+ # relative_destination #=> bar/baz
+ # given_destination #=> baz
+ #
+ def destination=(destination)
+ return unless destination
+ @given_destination = convert_encoded_instructions(destination.to_s)
+ @destination = ::File.expand_path(@given_destination, base.destination_root)
+ @relative_destination = base.relative_to_original_destination_root(@destination)
+ end
+
+ # Filenames in the encoded form are converted. If you have a file:
+ #
+ # %file_name%.rb
+ #
+ # It calls #file_name from the base and replaces %-string with the
+ # return value (should be String) of #file_name:
+ #
+ # user.rb
+ #
+ # The method referenced can be either public or private.
+ #
+ def convert_encoded_instructions(filename)
+ filename.gsub(/%(.*?)%/) do |initial_string|
+ method = $1.strip
+ base.respond_to?(method, true) ? base.send(method) : initial_string
+ end
+ end
+
+ # Receives a hash of options and just execute the block if some
+ # conditions are met.
+ #
+ def invoke_with_conflict_check(&block)
+ if exists?
+ on_conflict_behavior(&block)
+ else
+ yield unless pretend?
+ say_status :create, :green
+ end
+
+ destination
+ rescue Errno::EISDIR, Errno::EEXIST
+ on_file_clash_behavior
+ end
+
+ def on_file_clash_behavior
+ say_status :file_clash, :red
+ end
+
+ # What to do when the destination file already exists.
+ #
+ def on_conflict_behavior
+ say_status :exist, :blue
+ end
+
+ # Shortcut to say_status shell method.
+ #
+ def say_status(status, color)
+ base.shell.say_status status, relative_destination, color if config[:verbose]
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb b/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb
new file mode 100644
index 0000000000..4c83bebc86
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb
@@ -0,0 +1,364 @@
+require "erb"
+
+class Bundler::Thor
+ module Actions
+ # Copies the file from the relative source to the relative destination. If
+ # the destination is not given it's assumed to be equal to the source.
+ #
+ # ==== Parameters
+ # source<String>:: the relative path to the source root.
+ # destination<String>:: the relative path to the destination root.
+ # config<Hash>:: give :verbose => false to not log the status, and
+ # :mode => :preserve, to preserve the file mode from the source.
+
+ #
+ # ==== Examples
+ #
+ # copy_file "README", "doc/README"
+ #
+ # copy_file "doc/README"
+ #
+ def copy_file(source, *args, &block)
+ config = args.last.is_a?(Hash) ? args.pop : {}
+ destination = args.first || source
+ source = File.expand_path(find_in_source_paths(source.to_s))
+
+ create_file destination, nil, config do
+ content = File.binread(source)
+ content = yield(content) if block
+ content
+ end
+ if config[:mode] == :preserve
+ mode = File.stat(source).mode
+ chmod(destination, mode, config)
+ end
+ end
+
+ # Links the file from the relative source to the relative destination. If
+ # the destination is not given it's assumed to be equal to the source.
+ #
+ # ==== Parameters
+ # source<String>:: the relative path to the source root.
+ # destination<String>:: the relative path to the destination root.
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ # ==== Examples
+ #
+ # link_file "README", "doc/README"
+ #
+ # link_file "doc/README"
+ #
+ def link_file(source, *args)
+ config = args.last.is_a?(Hash) ? args.pop : {}
+ destination = args.first || source
+ source = File.expand_path(find_in_source_paths(source.to_s))
+
+ create_link destination, source, config
+ end
+
+ # Gets the content at the given address and places it at the given relative
+ # destination. If a block is given instead of destination, the content of
+ # the url is yielded and used as location.
+ #
+ # ==== Parameters
+ # source<String>:: the address of the given content.
+ # destination<String>:: the relative path to the destination root.
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ # ==== Examples
+ #
+ # get "http://gist.github.com/103208", "doc/README"
+ #
+ # get "http://gist.github.com/103208" do |content|
+ # content.split("\n").first
+ # end
+ #
+ def get(source, *args, &block)
+ config = args.last.is_a?(Hash) ? args.pop : {}
+ destination = args.first
+
+ if source =~ %r{^https?\://}
+ require "open-uri"
+ else
+ source = File.expand_path(find_in_source_paths(source.to_s))
+ end
+
+ render = open(source) { |input| input.binmode.read }
+
+ destination ||= if block_given?
+ block.arity == 1 ? yield(render) : yield
+ else
+ File.basename(source)
+ end
+
+ create_file destination, render, config
+ end
+
+ # Gets an ERB template at the relative source, executes it and makes a copy
+ # at the relative destination. If the destination is not given it's assumed
+ # to be equal to the source removing .tt from the filename.
+ #
+ # ==== Parameters
+ # source<String>:: the relative path to the source root.
+ # destination<String>:: the relative path to the destination root.
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ # ==== Examples
+ #
+ # template "README", "doc/README"
+ #
+ # template "doc/README"
+ #
+ def template(source, *args, &block)
+ config = args.last.is_a?(Hash) ? args.pop : {}
+ destination = args.first || source.sub(/#{TEMPLATE_EXTNAME}$/, "")
+
+ source = File.expand_path(find_in_source_paths(source.to_s))
+ context = config.delete(:context) || instance_eval("binding")
+
+ create_file destination, nil, config do
+ content = CapturableERB.new(::File.binread(source), nil, "-", "@output_buffer").tap do |erb|
+ erb.filename = source
+ end.result(context)
+ content = yield(content) if block
+ content
+ end
+ end
+
+ # Changes the mode of the given file or directory.
+ #
+ # ==== Parameters
+ # mode<Integer>:: the file mode
+ # path<String>:: the name of the file to change mode
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ # ==== Example
+ #
+ # chmod "script/server", 0755
+ #
+ def chmod(path, mode, config = {})
+ return unless behavior == :invoke
+ path = File.expand_path(path, destination_root)
+ say_status :chmod, relative_to_original_destination_root(path), config.fetch(:verbose, true)
+ unless options[:pretend]
+ require "fileutils"
+ FileUtils.chmod_R(mode, path)
+ end
+ end
+
+ # Prepend text to a file. Since it depends on insert_into_file, it's reversible.
+ #
+ # ==== Parameters
+ # path<String>:: path of the file to be changed
+ # data<String>:: the data to prepend to the file, can be also given as a block.
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ # ==== Example
+ #
+ # prepend_to_file 'config/environments/test.rb', 'config.gem "rspec"'
+ #
+ # prepend_to_file 'config/environments/test.rb' do
+ # 'config.gem "rspec"'
+ # end
+ #
+ def prepend_to_file(path, *args, &block)
+ config = args.last.is_a?(Hash) ? args.pop : {}
+ config[:after] = /\A/
+ insert_into_file(path, *(args << config), &block)
+ end
+ alias_method :prepend_file, :prepend_to_file
+
+ # Append text to a file. Since it depends on insert_into_file, it's reversible.
+ #
+ # ==== Parameters
+ # path<String>:: path of the file to be changed
+ # data<String>:: the data to append to the file, can be also given as a block.
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ # ==== Example
+ #
+ # append_to_file 'config/environments/test.rb', 'config.gem "rspec"'
+ #
+ # append_to_file 'config/environments/test.rb' do
+ # 'config.gem "rspec"'
+ # end
+ #
+ def append_to_file(path, *args, &block)
+ config = args.last.is_a?(Hash) ? args.pop : {}
+ config[:before] = /\z/
+ insert_into_file(path, *(args << config), &block)
+ end
+ alias_method :append_file, :append_to_file
+
+ # Injects text right after the class definition. Since it depends on
+ # insert_into_file, it's reversible.
+ #
+ # ==== Parameters
+ # path<String>:: path of the file to be changed
+ # klass<String|Class>:: the class to be manipulated
+ # data<String>:: the data to append to the class, can be also given as a block.
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ # ==== Examples
+ #
+ # inject_into_class "app/controllers/application_controller.rb", ApplicationController, " filter_parameter :password\n"
+ #
+ # inject_into_class "app/controllers/application_controller.rb", ApplicationController do
+ # " filter_parameter :password\n"
+ # end
+ #
+ def inject_into_class(path, klass, *args, &block)
+ config = args.last.is_a?(Hash) ? args.pop : {}
+ config[:after] = /class #{klass}\n|class #{klass} .*\n/
+ insert_into_file(path, *(args << config), &block)
+ end
+
+ # Injects text right after the module definition. Since it depends on
+ # insert_into_file, it's reversible.
+ #
+ # ==== Parameters
+ # path<String>:: path of the file to be changed
+ # module_name<String|Class>:: the module to be manipulated
+ # data<String>:: the data to append to the class, can be also given as a block.
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ # ==== Examples
+ #
+ # inject_into_module "app/helpers/application_helper.rb", ApplicationHelper, " def help; 'help'; end\n"
+ #
+ # inject_into_module "app/helpers/application_helper.rb", ApplicationHelper do
+ # " def help; 'help'; end\n"
+ # end
+ #
+ def inject_into_module(path, module_name, *args, &block)
+ config = args.last.is_a?(Hash) ? args.pop : {}
+ config[:after] = /module #{module_name}\n|module #{module_name} .*\n/
+ insert_into_file(path, *(args << config), &block)
+ end
+
+ # Run a regular expression replacement on a file.
+ #
+ # ==== Parameters
+ # path<String>:: path of the file to be changed
+ # flag<Regexp|String>:: the regexp or string to be replaced
+ # replacement<String>:: the replacement, can be also given as a block
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ # ==== Example
+ #
+ # gsub_file 'app/controllers/application_controller.rb', /#\s*(filter_parameter_logging :password)/, '\1'
+ #
+ # gsub_file 'README', /rake/, :green do |match|
+ # match << " no more. Use thor!"
+ # end
+ #
+ def gsub_file(path, flag, *args, &block)
+ return unless behavior == :invoke
+ config = args.last.is_a?(Hash) ? args.pop : {}
+
+ path = File.expand_path(path, destination_root)
+ say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true)
+
+ unless options[:pretend]
+ content = File.binread(path)
+ content.gsub!(flag, *args, &block)
+ File.open(path, "wb") { |file| file.write(content) }
+ end
+ end
+
+ # Uncomment all lines matching a given regex. It will leave the space
+ # which existed before the comment hash in tact but will remove any spacing
+ # between the comment hash and the beginning of the line.
+ #
+ # ==== Parameters
+ # path<String>:: path of the file to be changed
+ # flag<Regexp|String>:: the regexp or string used to decide which lines to uncomment
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ # ==== Example
+ #
+ # uncomment_lines 'config/initializers/session_store.rb', /active_record/
+ #
+ def uncomment_lines(path, flag, *args)
+ flag = flag.respond_to?(:source) ? flag.source : flag
+
+ gsub_file(path, /^(\s*)#[[:blank:]]*(.*#{flag})/, '\1\2', *args)
+ end
+
+ # Comment all lines matching a given regex. It will leave the space
+ # which existed before the beginning of the line in tact and will insert
+ # a single space after the comment hash.
+ #
+ # ==== Parameters
+ # path<String>:: path of the file to be changed
+ # flag<Regexp|String>:: the regexp or string used to decide which lines to comment
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ # ==== Example
+ #
+ # comment_lines 'config/initializers/session_store.rb', /cookie_store/
+ #
+ def comment_lines(path, flag, *args)
+ flag = flag.respond_to?(:source) ? flag.source : flag
+
+ gsub_file(path, /^(\s*)([^#|\n]*#{flag})/, '\1# \2', *args)
+ end
+
+ # Removes a file at the given location.
+ #
+ # ==== Parameters
+ # path<String>:: path of the file to be changed
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ # ==== Example
+ #
+ # remove_file 'README'
+ # remove_file 'app/controllers/application_controller.rb'
+ #
+ def remove_file(path, config = {})
+ return unless behavior == :invoke
+ path = File.expand_path(path, destination_root)
+
+ say_status :remove, relative_to_original_destination_root(path), config.fetch(:verbose, true)
+ if !options[:pretend] && File.exist?(path)
+ require "fileutils"
+ ::FileUtils.rm_rf(path)
+ end
+ end
+ alias_method :remove_dir, :remove_file
+
+ attr_accessor :output_buffer
+ private :output_buffer, :output_buffer=
+
+ private
+
+ def concat(string)
+ @output_buffer.concat(string)
+ end
+
+ def capture(*args)
+ with_output_buffer { yield(*args) }
+ end
+
+ def with_output_buffer(buf = "".dup) #:nodoc:
+ raise ArgumentError, "Buffer can not be a frozen object" if buf.frozen?
+ old_buffer = output_buffer
+ self.output_buffer = buf
+ yield
+ output_buffer
+ ensure
+ self.output_buffer = old_buffer
+ end
+
+ # Bundler::Thor::Actions#capture depends on what kind of buffer is used in ERB.
+ # Thus CapturableERB fixes ERB to use String buffer.
+ class CapturableERB < ERB
+ def set_eoutvar(compiler, eoutvar = "_erbout")
+ compiler.put_cmd = "#{eoutvar}.concat"
+ compiler.insert_cmd = "#{eoutvar}.concat"
+ compiler.pre_cmd = ["#{eoutvar} = ''.dup"]
+ compiler.post_cmd = [eoutvar]
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb b/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb
new file mode 100644
index 0000000000..349b26ff65
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb
@@ -0,0 +1,109 @@
+require "bundler/vendor/thor/lib/thor/actions/empty_directory"
+
+class Bundler::Thor
+ module Actions
+ # Injects the given content into a file. Different from gsub_file, this
+ # method is reversible.
+ #
+ # ==== Parameters
+ # destination<String>:: Relative path to the destination root
+ # data<String>:: Data to add to the file. Can be given as a block.
+ # config<Hash>:: give :verbose => false to not log the status and the flag
+ # for injection (:after or :before) or :force => true for
+ # insert two or more times the same content.
+ #
+ # ==== Examples
+ #
+ # insert_into_file "config/environment.rb", "config.gem :thor", :after => "Rails::Initializer.run do |config|\n"
+ #
+ # insert_into_file "config/environment.rb", :after => "Rails::Initializer.run do |config|\n" do
+ # gems = ask "Which gems would you like to add?"
+ # gems.split(" ").map{ |gem| " config.gem :#{gem}" }.join("\n")
+ # end
+ #
+ def insert_into_file(destination, *args, &block)
+ data = block_given? ? block : args.shift
+ config = args.shift
+ action InjectIntoFile.new(self, destination, data, config)
+ end
+ alias_method :inject_into_file, :insert_into_file
+
+ class InjectIntoFile < EmptyDirectory #:nodoc:
+ attr_reader :replacement, :flag, :behavior
+
+ def initialize(base, destination, data, config)
+ super(base, destination, {:verbose => true}.merge(config))
+
+ @behavior, @flag = if @config.key?(:after)
+ [:after, @config.delete(:after)]
+ else
+ [:before, @config.delete(:before)]
+ end
+
+ @replacement = data.is_a?(Proc) ? data.call : data
+ @flag = Regexp.escape(@flag) unless @flag.is_a?(Regexp)
+ end
+
+ def invoke!
+ say_status :invoke
+
+ content = if @behavior == :after
+ '\0' + replacement
+ else
+ replacement + '\0'
+ end
+
+ if exists?
+ replace!(/#{flag}/, content, config[:force])
+ else
+ unless pretend?
+ raise Bundler::Thor::Error, "The file #{ destination } does not appear to exist"
+ end
+ end
+ end
+
+ def revoke!
+ say_status :revoke
+
+ regexp = if @behavior == :after
+ content = '\1\2'
+ /(#{flag})(.*)(#{Regexp.escape(replacement)})/m
+ else
+ content = '\2\3'
+ /(#{Regexp.escape(replacement)})(.*)(#{flag})/m
+ end
+
+ replace!(regexp, content, true)
+ end
+
+ protected
+
+ def say_status(behavior)
+ status = if behavior == :invoke
+ if flag == /\A/
+ :prepend
+ elsif flag == /\z/
+ :append
+ else
+ :insert
+ end
+ else
+ :subtract
+ end
+
+ super(status, config[:verbose])
+ end
+
+ # Adds the content to the file.
+ #
+ def replace!(regexp, string, force)
+ return if pretend?
+ content = File.read(destination)
+ if force || !content.include?(replacement)
+ content.gsub!(regexp, string)
+ File.open(destination, "wb") { |file| file.write(content) }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/base.rb b/lib/bundler/vendor/thor/lib/thor/base.rb
new file mode 100644
index 0000000000..9bd1077170
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/base.rb
@@ -0,0 +1,679 @@
+require "bundler/vendor/thor/lib/thor/command"
+require "bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access"
+require "bundler/vendor/thor/lib/thor/core_ext/ordered_hash"
+require "bundler/vendor/thor/lib/thor/error"
+require "bundler/vendor/thor/lib/thor/invocation"
+require "bundler/vendor/thor/lib/thor/parser"
+require "bundler/vendor/thor/lib/thor/shell"
+require "bundler/vendor/thor/lib/thor/line_editor"
+require "bundler/vendor/thor/lib/thor/util"
+
+class Bundler::Thor
+ autoload :Actions, "bundler/vendor/thor/lib/thor/actions"
+ autoload :RakeCompat, "bundler/vendor/thor/lib/thor/rake_compat"
+ autoload :Group, "bundler/vendor/thor/lib/thor/group"
+
+ # Shortcuts for help.
+ HELP_MAPPINGS = %w(-h -? --help -D)
+
+ # Bundler::Thor methods that should not be overwritten by the user.
+ THOR_RESERVED_WORDS = %w(invoke shell options behavior root destination_root relative_root
+ action add_file create_file in_root inside run run_ruby_script)
+
+ TEMPLATE_EXTNAME = ".tt"
+
+ module Base
+ attr_accessor :options, :parent_options, :args
+
+ # It receives arguments in an Array and two hashes, one for options and
+ # other for configuration.
+ #
+ # Notice that it does not check if all required arguments were supplied.
+ # It should be done by the parser.
+ #
+ # ==== Parameters
+ # args<Array[Object]>:: An array of objects. The objects are applied to their
+ # respective accessors declared with <tt>argument</tt>.
+ #
+ # options<Hash>:: An options hash that will be available as self.options.
+ # The hash given is converted to a hash with indifferent
+ # access, magic predicates (options.skip?) and then frozen.
+ #
+ # config<Hash>:: Configuration for this Bundler::Thor class.
+ #
+ def initialize(args = [], local_options = {}, config = {})
+ parse_options = self.class.class_options
+
+ # The start method splits inbound arguments at the first argument
+ # that looks like an option (starts with - or --). It then calls
+ # new, passing in the two halves of the arguments Array as the
+ # first two parameters.
+
+ command_options = config.delete(:command_options) # hook for start
+ parse_options = parse_options.merge(command_options) if command_options
+ if local_options.is_a?(Array)
+ array_options = local_options
+ hash_options = {}
+ else
+ # Handle the case where the class was explicitly instantiated
+ # with pre-parsed options.
+ array_options = []
+ hash_options = local_options
+ end
+
+ # Let Bundler::Thor::Options parse the options first, so it can remove
+ # declared options from the array. This will leave us with
+ # a list of arguments that weren't declared.
+ stop_on_unknown = self.class.stop_on_unknown_option? config[:current_command]
+ disable_required_check = self.class.disable_required_check? config[:current_command]
+ opts = Bundler::Thor::Options.new(parse_options, hash_options, stop_on_unknown, disable_required_check)
+ self.options = opts.parse(array_options)
+ self.options = config[:class_options].merge(options) if config[:class_options]
+
+ # If unknown options are disallowed, make sure that none of the
+ # remaining arguments looks like an option.
+ opts.check_unknown! if self.class.check_unknown_options?(config)
+
+ # Add the remaining arguments from the options parser to the
+ # arguments passed in to initialize. Then remove any positional
+ # arguments declared using #argument (this is primarily used
+ # by Bundler::Thor::Group). Tis will leave us with the remaining
+ # positional arguments.
+ to_parse = args
+ to_parse += opts.remaining unless self.class.strict_args_position?(config)
+
+ thor_args = Bundler::Thor::Arguments.new(self.class.arguments)
+ thor_args.parse(to_parse).each { |k, v| __send__("#{k}=", v) }
+ @args = thor_args.remaining
+ end
+
+ class << self
+ def included(base) #:nodoc:
+ base.extend ClassMethods
+ base.send :include, Invocation
+ base.send :include, Shell
+ end
+
+ # Returns the classes that inherits from Bundler::Thor or Bundler::Thor::Group.
+ #
+ # ==== Returns
+ # Array[Class]
+ #
+ def subclasses
+ @subclasses ||= []
+ end
+
+ # Returns the files where the subclasses are kept.
+ #
+ # ==== Returns
+ # Hash[path<String> => Class]
+ #
+ def subclass_files
+ @subclass_files ||= Hash.new { |h, k| h[k] = [] }
+ end
+
+ # Whenever a class inherits from Bundler::Thor or Bundler::Thor::Group, we should track the
+ # class and the file on Bundler::Thor::Base. This is the method responsable for it.
+ #
+ def register_klass_file(klass) #:nodoc:
+ file = caller[1].match(/(.*):\d+/)[1]
+ Bundler::Thor::Base.subclasses << klass unless Bundler::Thor::Base.subclasses.include?(klass)
+
+ file_subclasses = Bundler::Thor::Base.subclass_files[File.expand_path(file)]
+ file_subclasses << klass unless file_subclasses.include?(klass)
+ end
+ end
+
+ module ClassMethods
+ def attr_reader(*) #:nodoc:
+ no_commands { super }
+ end
+
+ def attr_writer(*) #:nodoc:
+ no_commands { super }
+ end
+
+ def attr_accessor(*) #:nodoc:
+ no_commands { super }
+ end
+
+ # If you want to raise an error for unknown options, call check_unknown_options!
+ # This is disabled by default to allow dynamic invocations.
+ def check_unknown_options!
+ @check_unknown_options = true
+ end
+
+ def check_unknown_options #:nodoc:
+ @check_unknown_options ||= from_superclass(:check_unknown_options, false)
+ end
+
+ def check_unknown_options?(config) #:nodoc:
+ !!check_unknown_options
+ end
+
+ # If you want to raise an error when the default value of an option does not match
+ # the type call check_default_type!
+ # This is disabled by default for compatibility.
+ def check_default_type!
+ @check_default_type = true
+ end
+
+ def check_default_type #:nodoc:
+ @check_default_type ||= from_superclass(:check_default_type, false)
+ end
+
+ def check_default_type? #:nodoc:
+ !!check_default_type
+ end
+
+ # If true, option parsing is suspended as soon as an unknown option or a
+ # regular argument is encountered. All remaining arguments are passed to
+ # the command as regular arguments.
+ def stop_on_unknown_option?(command_name) #:nodoc:
+ false
+ end
+
+ # If true, option set will not suspend the execution of the command when
+ # a required option is not provided.
+ def disable_required_check?(command_name) #:nodoc:
+ false
+ end
+
+ # If you want only strict string args (useful when cascading thor classes),
+ # call strict_args_position! This is disabled by default to allow dynamic
+ # invocations.
+ def strict_args_position!
+ @strict_args_position = true
+ end
+
+ def strict_args_position #:nodoc:
+ @strict_args_position ||= from_superclass(:strict_args_position, false)
+ end
+
+ def strict_args_position?(config) #:nodoc:
+ !!strict_args_position
+ end
+
+ # Adds an argument to the class and creates an attr_accessor for it.
+ #
+ # Arguments are different from options in several aspects. The first one
+ # is how they are parsed from the command line, arguments are retrieved
+ # from position:
+ #
+ # thor command NAME
+ #
+ # Instead of:
+ #
+ # thor command --name=NAME
+ #
+ # Besides, arguments are used inside your code as an accessor (self.argument),
+ # while options are all kept in a hash (self.options).
+ #
+ # Finally, arguments cannot have type :default or :boolean but can be
+ # optional (supplying :optional => :true or :required => false), although
+ # you cannot have a required argument after a non-required argument. If you
+ # try it, an error is raised.
+ #
+ # ==== Parameters
+ # name<Symbol>:: The name of the argument.
+ # options<Hash>:: Described below.
+ #
+ # ==== Options
+ # :desc - Description for the argument.
+ # :required - If the argument is required or not.
+ # :optional - If the argument is optional or not.
+ # :type - The type of the argument, can be :string, :hash, :array, :numeric.
+ # :default - Default value for this argument. It cannot be required and have default values.
+ # :banner - String to show on usage notes.
+ #
+ # ==== Errors
+ # ArgumentError:: Raised if you supply a required argument after a non required one.
+ #
+ def argument(name, options = {})
+ is_thor_reserved_word?(name, :argument)
+ no_commands { attr_accessor name }
+
+ required = if options.key?(:optional)
+ !options[:optional]
+ elsif options.key?(:required)
+ options[:required]
+ else
+ options[:default].nil?
+ end
+
+ remove_argument name
+
+ if required
+ arguments.each do |argument|
+ next if argument.required?
+ raise ArgumentError, "You cannot have #{name.to_s.inspect} as required argument after " \
+ "the non-required argument #{argument.human_name.inspect}."
+ end
+ end
+
+ options[:required] = required
+
+ arguments << Bundler::Thor::Argument.new(name, options)
+ end
+
+ # Returns this class arguments, looking up in the ancestors chain.
+ #
+ # ==== Returns
+ # Array[Bundler::Thor::Argument]
+ #
+ def arguments
+ @arguments ||= from_superclass(:arguments, [])
+ end
+
+ # Adds a bunch of options to the set of class options.
+ #
+ # class_options :foo => false, :bar => :required, :baz => :string
+ #
+ # If you prefer more detailed declaration, check class_option.
+ #
+ # ==== Parameters
+ # Hash[Symbol => Object]
+ #
+ def class_options(options = nil)
+ @class_options ||= from_superclass(:class_options, {})
+ build_options(options, @class_options) if options
+ @class_options
+ end
+
+ # Adds an option to the set of class options
+ #
+ # ==== Parameters
+ # name<Symbol>:: The name of the argument.
+ # options<Hash>:: Described below.
+ #
+ # ==== Options
+ # :desc:: -- Description for the argument.
+ # :required:: -- If the argument is required or not.
+ # :default:: -- Default value for this argument.
+ # :group:: -- The group for this options. Use by class options to output options in different levels.
+ # :aliases:: -- Aliases for this option. <b>Note:</b> Bundler::Thor follows a convention of one-dash-one-letter options. Thus aliases like "-something" wouldn't be parsed; use either "\--something" or "-s" instead.
+ # :type:: -- The type of the argument, can be :string, :hash, :array, :numeric or :boolean.
+ # :banner:: -- String to show on usage notes.
+ # :hide:: -- If you want to hide this option from the help.
+ #
+ def class_option(name, options = {})
+ build_option(name, options, class_options)
+ end
+
+ # Removes a previous defined argument. If :undefine is given, undefine
+ # accessors as well.
+ #
+ # ==== Parameters
+ # names<Array>:: Arguments to be removed
+ #
+ # ==== Examples
+ #
+ # remove_argument :foo
+ # remove_argument :foo, :bar, :baz, :undefine => true
+ #
+ def remove_argument(*names)
+ options = names.last.is_a?(Hash) ? names.pop : {}
+
+ names.each do |name|
+ arguments.delete_if { |a| a.name == name.to_s }
+ undef_method name, "#{name}=" if options[:undefine]
+ end
+ end
+
+ # Removes a previous defined class option.
+ #
+ # ==== Parameters
+ # names<Array>:: Class options to be removed
+ #
+ # ==== Examples
+ #
+ # remove_class_option :foo
+ # remove_class_option :foo, :bar, :baz
+ #
+ def remove_class_option(*names)
+ names.each do |name|
+ class_options.delete(name)
+ end
+ end
+
+ # Defines the group. This is used when thor list is invoked so you can specify
+ # that only commands from a pre-defined group will be shown. Defaults to standard.
+ #
+ # ==== Parameters
+ # name<String|Symbol>
+ #
+ def group(name = nil)
+ if name
+ @group = name.to_s
+ else
+ @group ||= from_superclass(:group, "standard")
+ end
+ end
+
+ # Returns the commands for this Bundler::Thor class.
+ #
+ # ==== Returns
+ # OrderedHash:: An ordered hash with commands names as keys and Bundler::Thor::Command
+ # objects as values.
+ #
+ def commands
+ @commands ||= Bundler::Thor::CoreExt::OrderedHash.new
+ end
+ alias_method :tasks, :commands
+
+ # Returns the commands for this Bundler::Thor class and all subclasses.
+ #
+ # ==== Returns
+ # OrderedHash:: An ordered hash with commands names as keys and Bundler::Thor::Command
+ # objects as values.
+ #
+ def all_commands
+ @all_commands ||= from_superclass(:all_commands, Bundler::Thor::CoreExt::OrderedHash.new)
+ @all_commands.merge!(commands)
+ end
+ alias_method :all_tasks, :all_commands
+
+ # Removes a given command from this Bundler::Thor class. This is usually done if you
+ # are inheriting from another class and don't want it to be available
+ # anymore.
+ #
+ # By default it only remove the mapping to the command. But you can supply
+ # :undefine => true to undefine the method from the class as well.
+ #
+ # ==== Parameters
+ # name<Symbol|String>:: The name of the command to be removed
+ # options<Hash>:: You can give :undefine => true if you want commands the method
+ # to be undefined from the class as well.
+ #
+ def remove_command(*names)
+ options = names.last.is_a?(Hash) ? names.pop : {}
+
+ names.each do |name|
+ commands.delete(name.to_s)
+ all_commands.delete(name.to_s)
+ undef_method name if options[:undefine]
+ end
+ end
+ alias_method :remove_task, :remove_command
+
+ # All methods defined inside the given block are not added as commands.
+ #
+ # So you can do:
+ #
+ # class MyScript < Bundler::Thor
+ # no_commands do
+ # def this_is_not_a_command
+ # end
+ # end
+ # end
+ #
+ # You can also add the method and remove it from the command list:
+ #
+ # class MyScript < Bundler::Thor
+ # def this_is_not_a_command
+ # end
+ # remove_command :this_is_not_a_command
+ # end
+ #
+ def no_commands
+ @no_commands = true
+ yield
+ ensure
+ @no_commands = false
+ end
+ alias_method :no_tasks, :no_commands
+
+ # Sets the namespace for the Bundler::Thor or Bundler::Thor::Group class. By default the
+ # namespace is retrieved from the class name. If your Bundler::Thor class is named
+ # Scripts::MyScript, the help method, for example, will be called as:
+ #
+ # thor scripts:my_script -h
+ #
+ # If you change the namespace:
+ #
+ # namespace :my_scripts
+ #
+ # You change how your commands are invoked:
+ #
+ # thor my_scripts -h
+ #
+ # Finally, if you change your namespace to default:
+ #
+ # namespace :default
+ #
+ # Your commands can be invoked with a shortcut. Instead of:
+ #
+ # thor :my_command
+ #
+ def namespace(name = nil)
+ if name
+ @namespace = name.to_s
+ else
+ @namespace ||= Bundler::Thor::Util.namespace_from_thor_class(self)
+ end
+ end
+
+ # Parses the command and options from the given args, instantiate the class
+ # and invoke the command. This method is used when the arguments must be parsed
+ # from an array. If you are inside Ruby and want to use a Bundler::Thor class, you
+ # can simply initialize it:
+ #
+ # script = MyScript.new(args, options, config)
+ # script.invoke(:command, first_arg, second_arg, third_arg)
+ #
+ def start(given_args = ARGV, config = {})
+ config[:shell] ||= Bundler::Thor::Base.shell.new
+ dispatch(nil, given_args.dup, nil, config)
+ rescue Bundler::Thor::Error => e
+ config[:debug] || ENV["THOR_DEBUG"] == "1" ? (raise e) : config[:shell].error(e.message)
+ exit(1) if exit_on_failure?
+ rescue Errno::EPIPE
+ # This happens if a thor command is piped to something like `head`,
+ # which closes the pipe when it's done reading. This will also
+ # mean that if the pipe is closed, further unnecessary
+ # computation will not occur.
+ exit(0)
+ end
+
+ # Allows to use private methods from parent in child classes as commands.
+ #
+ # ==== Parameters
+ # names<Array>:: Method names to be used as commands
+ #
+ # ==== Examples
+ #
+ # public_command :foo
+ # public_command :foo, :bar, :baz
+ #
+ def public_command(*names)
+ names.each do |name|
+ class_eval "def #{name}(*); super end"
+ end
+ end
+ alias_method :public_task, :public_command
+
+ def handle_no_command_error(command, has_namespace = $thor_runner) #:nodoc:
+ raise UndefinedCommandError, "Could not find command #{command.inspect} in #{namespace.inspect} namespace." if has_namespace
+ raise UndefinedCommandError, "Could not find command #{command.inspect}."
+ end
+ alias_method :handle_no_task_error, :handle_no_command_error
+
+ def handle_argument_error(command, error, args, arity) #:nodoc:
+ name = [command.ancestor_name, command.name].compact.join(" ")
+ msg = "ERROR: \"#{basename} #{name}\" was called with ".dup
+ msg << "no arguments" if args.empty?
+ msg << "arguments " << args.inspect unless args.empty?
+ msg << "\nUsage: #{banner(command).inspect}"
+ raise InvocationError, msg
+ end
+
+ protected
+
+ # Prints the class options per group. If an option does not belong to
+ # any group, it's printed as Class option.
+ #
+ def class_options_help(shell, groups = {}) #:nodoc:
+ # Group options by group
+ class_options.each do |_, value|
+ groups[value.group] ||= []
+ groups[value.group] << value
+ end
+
+ # Deal with default group
+ global_options = groups.delete(nil) || []
+ print_options(shell, global_options)
+
+ # Print all others
+ groups.each do |group_name, options|
+ print_options(shell, options, group_name)
+ end
+ end
+
+ # Receives a set of options and print them.
+ def print_options(shell, options, group_name = nil)
+ return if options.empty?
+
+ list = []
+ padding = options.map { |o| o.aliases.size }.max.to_i * 4
+
+ options.each do |option|
+ next if option.hide
+ item = [option.usage(padding)]
+ item.push(option.description ? "# #{option.description}" : "")
+
+ list << item
+ list << ["", "# Default: #{option.default}"] if option.show_default?
+ list << ["", "# Possible values: #{option.enum.join(', ')}"] if option.enum
+ end
+
+ shell.say(group_name ? "#{group_name} options:" : "Options:")
+ shell.print_table(list, :indent => 2)
+ shell.say ""
+ end
+
+ # Raises an error if the word given is a Bundler::Thor reserved word.
+ def is_thor_reserved_word?(word, type) #:nodoc:
+ return false unless THOR_RESERVED_WORDS.include?(word.to_s)
+ raise "#{word.inspect} is a Bundler::Thor reserved word and cannot be defined as #{type}"
+ end
+
+ # Build an option and adds it to the given scope.
+ #
+ # ==== Parameters
+ # name<Symbol>:: The name of the argument.
+ # options<Hash>:: Described in both class_option and method_option.
+ # scope<Hash>:: Options hash that is being built up
+ def build_option(name, options, scope) #:nodoc:
+ scope[name] = Bundler::Thor::Option.new(name, options.merge(:check_default_type => check_default_type?))
+ end
+
+ # Receives a hash of options, parse them and add to the scope. This is a
+ # fast way to set a bunch of options:
+ #
+ # build_options :foo => true, :bar => :required, :baz => :string
+ #
+ # ==== Parameters
+ # Hash[Symbol => Object]
+ def build_options(options, scope) #:nodoc:
+ options.each do |key, value|
+ scope[key] = Bundler::Thor::Option.parse(key, value)
+ end
+ end
+
+ # Finds a command with the given name. If the command belongs to the current
+ # class, just return it, otherwise dup it and add the fresh copy to the
+ # current command hash.
+ def find_and_refresh_command(name) #:nodoc:
+ if commands[name.to_s]
+ commands[name.to_s]
+ elsif command = all_commands[name.to_s] # rubocop:disable AssignmentInCondition
+ commands[name.to_s] = command.clone
+ else
+ raise ArgumentError, "You supplied :for => #{name.inspect}, but the command #{name.inspect} could not be found."
+ end
+ end
+ alias_method :find_and_refresh_task, :find_and_refresh_command
+
+ # Everytime someone inherits from a Bundler::Thor class, register the klass
+ # and file into baseclass.
+ def inherited(klass)
+ Bundler::Thor::Base.register_klass_file(klass)
+ klass.instance_variable_set(:@no_commands, false)
+ end
+
+ # Fire this callback whenever a method is added. Added methods are
+ # tracked as commands by invoking the create_command method.
+ def method_added(meth)
+ meth = meth.to_s
+
+ if meth == "initialize"
+ initialize_added
+ return
+ end
+
+ # Return if it's not a public instance method
+ return unless public_method_defined?(meth.to_sym)
+
+ @no_commands ||= false
+ return if @no_commands || !create_command(meth)
+
+ is_thor_reserved_word?(meth, :command)
+ Bundler::Thor::Base.register_klass_file(self)
+ end
+
+ # Retrieves a value from superclass. If it reaches the baseclass,
+ # returns default.
+ def from_superclass(method, default = nil)
+ if self == baseclass || !superclass.respond_to?(method, true)
+ default
+ else
+ value = superclass.send(method)
+
+ # Ruby implements `dup` on Object, but raises a `TypeError`
+ # if the method is called on immediates. As a result, we
+ # don't have a good way to check whether dup will succeed
+ # without calling it and rescuing the TypeError.
+ begin
+ value.dup
+ rescue TypeError
+ value
+ end
+
+ end
+ end
+
+ # A flag that makes the process exit with status 1 if any error happens.
+ def exit_on_failure?
+ false
+ end
+
+ #
+ # The basename of the program invoking the thor class.
+ #
+ def basename
+ File.basename($PROGRAM_NAME).split(" ").first
+ end
+
+ # SIGNATURE: Sets the baseclass. This is where the superclass lookup
+ # finishes.
+ def baseclass #:nodoc:
+ end
+
+ # SIGNATURE: Creates a new command if valid_command? is true. This method is
+ # called when a new method is added to the class.
+ def create_command(meth) #:nodoc:
+ end
+ alias_method :create_task, :create_command
+
+ # SIGNATURE: Defines behavior when the initialize method is added to the
+ # class.
+ def initialize_added #:nodoc:
+ end
+
+ # SIGNATURE: The hook invoked by start.
+ def dispatch(command, given_args, given_opts, config) #:nodoc:
+ raise NotImplementedError
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/command.rb b/lib/bundler/vendor/thor/lib/thor/command.rb
new file mode 100644
index 0000000000..c636948e5d
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/command.rb
@@ -0,0 +1,135 @@
+class Bundler::Thor
+ class Command < Struct.new(:name, :description, :long_description, :usage, :options, :ancestor_name)
+ FILE_REGEXP = /^#{Regexp.escape(File.dirname(__FILE__))}/
+
+ def initialize(name, description, long_description, usage, options = nil)
+ super(name.to_s, description, long_description, usage, options || {})
+ end
+
+ def initialize_copy(other) #:nodoc:
+ super(other)
+ self.options = other.options.dup if other.options
+ end
+
+ def hidden?
+ false
+ end
+
+ # By default, a command invokes a method in the thor class. You can change this
+ # implementation to create custom commands.
+ def run(instance, args = [])
+ arity = nil
+
+ if private_method?(instance)
+ instance.class.handle_no_command_error(name)
+ elsif public_method?(instance)
+ arity = instance.method(name).arity
+ instance.__send__(name, *args)
+ elsif local_method?(instance, :method_missing)
+ instance.__send__(:method_missing, name.to_sym, *args)
+ else
+ instance.class.handle_no_command_error(name)
+ end
+ rescue ArgumentError => e
+ handle_argument_error?(instance, e, caller) ? instance.class.handle_argument_error(self, e, args, arity) : (raise e)
+ rescue NoMethodError => e
+ handle_no_method_error?(instance, e, caller) ? instance.class.handle_no_command_error(name) : (raise e)
+ end
+
+ # Returns the formatted usage by injecting given required arguments
+ # and required options into the given usage.
+ def formatted_usage(klass, namespace = true, subcommand = false)
+ if ancestor_name
+ formatted = "#{ancestor_name} ".dup # add space
+ elsif namespace
+ namespace = klass.namespace
+ formatted = "#{namespace.gsub(/^(default)/, '')}:".dup
+ end
+ formatted ||= "#{klass.namespace.split(':').last} ".dup if subcommand
+
+ formatted ||= "".dup
+
+ # Add usage with required arguments
+ formatted << if klass && !klass.arguments.empty?
+ usage.to_s.gsub(/^#{name}/) do |match|
+ match << " " << klass.arguments.map(&:usage).compact.join(" ")
+ end
+ else
+ usage.to_s
+ end
+
+ # Add required options
+ formatted << " #{required_options}"
+
+ # Strip and go!
+ formatted.strip
+ end
+
+ protected
+
+ def not_debugging?(instance)
+ !(instance.class.respond_to?(:debugging) && instance.class.debugging)
+ end
+
+ def required_options
+ @required_options ||= options.map { |_, o| o.usage if o.required? }.compact.sort.join(" ")
+ end
+
+ # Given a target, checks if this class name is a public method.
+ def public_method?(instance) #:nodoc:
+ !(instance.public_methods & [name.to_s, name.to_sym]).empty?
+ end
+
+ def private_method?(instance)
+ !(instance.private_methods & [name.to_s, name.to_sym]).empty?
+ end
+
+ def local_method?(instance, name)
+ methods = instance.public_methods(false) + instance.private_methods(false) + instance.protected_methods(false)
+ !(methods & [name.to_s, name.to_sym]).empty?
+ end
+
+ def sans_backtrace(backtrace, caller) #:nodoc:
+ saned = backtrace.reject { |frame| frame =~ FILE_REGEXP || (frame =~ /\.java:/ && RUBY_PLATFORM =~ /java/) || (frame =~ %r{^kernel/} && RUBY_ENGINE =~ /rbx/) }
+ saned - caller
+ end
+
+ def handle_argument_error?(instance, error, caller)
+ not_debugging?(instance) && (error.message =~ /wrong number of arguments/ || error.message =~ /given \d*, expected \d*/) && begin
+ saned = sans_backtrace(error.backtrace, caller)
+ # Ruby 1.9 always include the called method in the backtrace
+ saned.empty? || (saned.size == 1 && RUBY_VERSION >= "1.9")
+ end
+ end
+
+ def handle_no_method_error?(instance, error, caller)
+ not_debugging?(instance) &&
+ error.message =~ /^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/
+ end
+ end
+ Task = Command
+
+ # A command that is hidden in help messages but still invocable.
+ class HiddenCommand < Command
+ def hidden?
+ true
+ end
+ end
+ HiddenTask = HiddenCommand
+
+ # A dynamic command that handles method missing scenarios.
+ class DynamicCommand < Command
+ def initialize(name, options = nil)
+ super(name.to_s, "A dynamically-generated command", name.to_s, name.to_s, options)
+ end
+
+ def run(instance, args = [])
+ if (instance.methods & [name.to_s, name.to_sym]).empty?
+ super
+ else
+ instance.class.handle_no_command_error(name)
+ end
+ end
+ end
+ DynamicTask = DynamicCommand
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb b/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb
new file mode 100644
index 0000000000..c167aa33b8
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb
@@ -0,0 +1,97 @@
+class Bundler::Thor
+ module CoreExt #:nodoc:
+ # A hash with indifferent access and magic predicates.
+ #
+ # hash = Bundler::Thor::CoreExt::HashWithIndifferentAccess.new 'foo' => 'bar', 'baz' => 'bee', 'force' => true
+ #
+ # hash[:foo] #=> 'bar'
+ # hash['foo'] #=> 'bar'
+ # hash.foo? #=> true
+ #
+ class HashWithIndifferentAccess < ::Hash #:nodoc:
+ def initialize(hash = {})
+ super()
+ hash.each do |key, value|
+ self[convert_key(key)] = value
+ end
+ end
+
+ def [](key)
+ super(convert_key(key))
+ end
+
+ def []=(key, value)
+ super(convert_key(key), value)
+ end
+
+ def delete(key)
+ super(convert_key(key))
+ end
+
+ def fetch(key, *args)
+ super(convert_key(key), *args)
+ end
+
+ def key?(key)
+ super(convert_key(key))
+ end
+
+ def values_at(*indices)
+ indices.map { |key| self[convert_key(key)] }
+ end
+
+ def merge(other)
+ dup.merge!(other)
+ end
+
+ def merge!(other)
+ other.each do |key, value|
+ self[convert_key(key)] = value
+ end
+ self
+ end
+
+ def reverse_merge(other)
+ self.class.new(other).merge(self)
+ end
+
+ def reverse_merge!(other_hash)
+ replace(reverse_merge(other_hash))
+ end
+
+ def replace(other_hash)
+ super(other_hash)
+ end
+
+ # Convert to a Hash with String keys.
+ def to_hash
+ Hash.new(default).merge!(self)
+ end
+
+ protected
+
+ def convert_key(key)
+ key.is_a?(Symbol) ? key.to_s : key
+ end
+
+ # Magic predicates. For instance:
+ #
+ # options.force? # => !!options['force']
+ # options.shebang # => "/usr/lib/local/ruby"
+ # options.test_framework?(:rspec) # => options[:test_framework] == :rspec
+ #
+ def method_missing(method, *args)
+ method = method.to_s
+ if method =~ /^(\w+)\?$/
+ if args.empty?
+ !!self[$1]
+ else
+ self[$1] == args.first
+ end
+ else
+ self[method]
+ end
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/core_ext/io_binary_read.rb b/lib/bundler/vendor/thor/lib/thor/core_ext/io_binary_read.rb
new file mode 100644
index 0000000000..0f6e2e0af2
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/core_ext/io_binary_read.rb
@@ -0,0 +1,12 @@
+class IO #:nodoc:
+ class << self
+ unless method_defined? :binread
+ def binread(file, *args)
+ raise ArgumentError, "wrong number of arguments (#{1 + args.size} for 1..3)" unless args.size < 3
+ File.open(file, "rb") do |f|
+ f.read(*args)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/core_ext/ordered_hash.rb b/lib/bundler/vendor/thor/lib/thor/core_ext/ordered_hash.rb
new file mode 100644
index 0000000000..76f1e43c65
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/core_ext/ordered_hash.rb
@@ -0,0 +1,129 @@
+class Bundler::Thor
+ module CoreExt
+ class OrderedHash < ::Hash
+ if RUBY_VERSION < "1.9"
+ def initialize(*args, &block)
+ super
+ @keys = []
+ end
+
+ def initialize_copy(other)
+ super
+ # make a deep copy of keys
+ @keys = other.keys
+ end
+
+ def []=(key, value)
+ @keys << key unless key?(key)
+ super
+ end
+
+ def delete(key)
+ if key? key
+ index = @keys.index(key)
+ @keys.delete_at index
+ end
+ super
+ end
+
+ def delete_if
+ super
+ sync_keys!
+ self
+ end
+
+ alias_method :reject!, :delete_if
+
+ def reject(&block)
+ dup.reject!(&block)
+ end
+
+ def keys
+ @keys.dup
+ end
+
+ def values
+ @keys.map { |key| self[key] }
+ end
+
+ def to_hash
+ self
+ end
+
+ def to_a
+ @keys.map { |key| [key, self[key]] }
+ end
+
+ def each_key
+ return to_enum(:each_key) unless block_given?
+ @keys.each { |key| yield(key) }
+ self
+ end
+
+ def each_value
+ return to_enum(:each_value) unless block_given?
+ @keys.each { |key| yield(self[key]) }
+ self
+ end
+
+ def each
+ return to_enum(:each) unless block_given?
+ @keys.each { |key| yield([key, self[key]]) }
+ self
+ end
+
+ def each_pair
+ return to_enum(:each_pair) unless block_given?
+ @keys.each { |key| yield(key, self[key]) }
+ self
+ end
+
+ alias_method :select, :find_all
+
+ def clear
+ super
+ @keys.clear
+ self
+ end
+
+ def shift
+ k = @keys.first
+ v = delete(k)
+ [k, v]
+ end
+
+ def merge!(other_hash)
+ if block_given?
+ other_hash.each { |k, v| self[k] = key?(k) ? yield(k, self[k], v) : v }
+ else
+ other_hash.each { |k, v| self[k] = v }
+ end
+ self
+ end
+
+ alias_method :update, :merge!
+
+ def merge(other_hash, &block)
+ dup.merge!(other_hash, &block)
+ end
+
+ # When replacing with another hash, the initial order of our keys must come from the other hash -ordered or not.
+ def replace(other)
+ super
+ @keys = other.keys
+ self
+ end
+
+ def inspect
+ "#<#{self.class} #{super}>"
+ end
+
+ private
+
+ def sync_keys!
+ @keys.delete_if { |k| !key?(k) }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/error.rb b/lib/bundler/vendor/thor/lib/thor/error.rb
new file mode 100644
index 0000000000..2f816081f3
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/error.rb
@@ -0,0 +1,32 @@
+class Bundler::Thor
+ # Bundler::Thor::Error is raised when it's caused by wrong usage of thor classes. Those
+ # errors have their backtrace suppressed and are nicely shown to the user.
+ #
+ # Errors that are caused by the developer, like declaring a method which
+ # overwrites a thor keyword, SHOULD NOT raise a Bundler::Thor::Error. This way, we
+ # ensure that developer errors are shown with full backtrace.
+ class Error < StandardError
+ end
+
+ # Raised when a command was not found.
+ class UndefinedCommandError < Error
+ end
+ UndefinedTaskError = UndefinedCommandError
+
+ class AmbiguousCommandError < Error
+ end
+ AmbiguousTaskError = AmbiguousCommandError
+
+ # Raised when a command was found, but not invoked properly.
+ class InvocationError < Error
+ end
+
+ class UnknownArgumentError < Error
+ end
+
+ class RequiredArgumentMissingError < InvocationError
+ end
+
+ class MalformattedArgumentError < InvocationError
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/group.rb b/lib/bundler/vendor/thor/lib/thor/group.rb
new file mode 100644
index 0000000000..05ddc10cd3
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/group.rb
@@ -0,0 +1,281 @@
+require "bundler/vendor/thor/lib/thor/base"
+
+# Bundler::Thor has a special class called Bundler::Thor::Group. The main difference to Bundler::Thor class
+# is that it invokes all commands at once. It also include some methods that allows
+# invocations to be done at the class method, which are not available to Bundler::Thor
+# commands.
+class Bundler::Thor::Group
+ class << self
+ # The description for this Bundler::Thor::Group. If none is provided, but a source root
+ # exists, tries to find the USAGE one folder above it, otherwise searches
+ # in the superclass.
+ #
+ # ==== Parameters
+ # description<String>:: The description for this Bundler::Thor::Group.
+ #
+ def desc(description = nil)
+ if description
+ @desc = description
+ else
+ @desc ||= from_superclass(:desc, nil)
+ end
+ end
+
+ # Prints help information.
+ #
+ # ==== Options
+ # short:: When true, shows only usage.
+ #
+ def help(shell)
+ shell.say "Usage:"
+ shell.say " #{banner}\n"
+ shell.say
+ class_options_help(shell)
+ shell.say desc if desc
+ end
+
+ # Stores invocations for this class merging with superclass values.
+ #
+ def invocations #:nodoc:
+ @invocations ||= from_superclass(:invocations, {})
+ end
+
+ # Stores invocation blocks used on invoke_from_option.
+ #
+ def invocation_blocks #:nodoc:
+ @invocation_blocks ||= from_superclass(:invocation_blocks, {})
+ end
+
+ # Invoke the given namespace or class given. It adds an instance
+ # method that will invoke the klass and command. You can give a block to
+ # configure how it will be invoked.
+ #
+ # The namespace/class given will have its options showed on the help
+ # usage. Check invoke_from_option for more information.
+ #
+ def invoke(*names, &block)
+ options = names.last.is_a?(Hash) ? names.pop : {}
+ verbose = options.fetch(:verbose, true)
+
+ names.each do |name|
+ invocations[name] = false
+ invocation_blocks[name] = block if block_given?
+
+ class_eval <<-METHOD, __FILE__, __LINE__
+ def _invoke_#{name.to_s.gsub(/\W/, '_')}
+ klass, command = self.class.prepare_for_invocation(nil, #{name.inspect})
+
+ if klass
+ say_status :invoke, #{name.inspect}, #{verbose.inspect}
+ block = self.class.invocation_blocks[#{name.inspect}]
+ _invoke_for_class_method klass, command, &block
+ else
+ say_status :error, %(#{name.inspect} [not found]), :red
+ end
+ end
+ METHOD
+ end
+ end
+
+ # Invoke a thor class based on the value supplied by the user to the
+ # given option named "name". A class option must be created before this
+ # method is invoked for each name given.
+ #
+ # ==== Examples
+ #
+ # class GemGenerator < Bundler::Thor::Group
+ # class_option :test_framework, :type => :string
+ # invoke_from_option :test_framework
+ # end
+ #
+ # ==== Boolean options
+ #
+ # In some cases, you want to invoke a thor class if some option is true or
+ # false. This is automatically handled by invoke_from_option. Then the
+ # option name is used to invoke the generator.
+ #
+ # ==== Preparing for invocation
+ #
+ # In some cases you want to customize how a specified hook is going to be
+ # invoked. You can do that by overwriting the class method
+ # prepare_for_invocation. The class method must necessarily return a klass
+ # and an optional command.
+ #
+ # ==== Custom invocations
+ #
+ # You can also supply a block to customize how the option is going to be
+ # invoked. The block receives two parameters, an instance of the current
+ # class and the klass to be invoked.
+ #
+ def invoke_from_option(*names, &block)
+ options = names.last.is_a?(Hash) ? names.pop : {}
+ verbose = options.fetch(:verbose, :white)
+
+ names.each do |name|
+ unless class_options.key?(name)
+ raise ArgumentError, "You have to define the option #{name.inspect} " \
+ "before setting invoke_from_option."
+ end
+
+ invocations[name] = true
+ invocation_blocks[name] = block if block_given?
+
+ class_eval <<-METHOD, __FILE__, __LINE__
+ def _invoke_from_option_#{name.to_s.gsub(/\W/, '_')}
+ return unless options[#{name.inspect}]
+
+ value = options[#{name.inspect}]
+ value = #{name.inspect} if TrueClass === value
+ klass, command = self.class.prepare_for_invocation(#{name.inspect}, value)
+
+ if klass
+ say_status :invoke, value, #{verbose.inspect}
+ block = self.class.invocation_blocks[#{name.inspect}]
+ _invoke_for_class_method klass, command, &block
+ else
+ say_status :error, %(\#{value} [not found]), :red
+ end
+ end
+ METHOD
+ end
+ end
+
+ # Remove a previously added invocation.
+ #
+ # ==== Examples
+ #
+ # remove_invocation :test_framework
+ #
+ def remove_invocation(*names)
+ names.each do |name|
+ remove_command(name)
+ remove_class_option(name)
+ invocations.delete(name)
+ invocation_blocks.delete(name)
+ end
+ end
+
+ # Overwrite class options help to allow invoked generators options to be
+ # shown recursively when invoking a generator.
+ #
+ def class_options_help(shell, groups = {}) #:nodoc:
+ get_options_from_invocations(groups, class_options) do |klass|
+ klass.send(:get_options_from_invocations, groups, class_options)
+ end
+ super(shell, groups)
+ end
+
+ # Get invocations array and merge options from invocations. Those
+ # options are added to group_options hash. Options that already exists
+ # in base_options are not added twice.
+ #
+ def get_options_from_invocations(group_options, base_options) #:nodoc: # rubocop:disable MethodLength
+ invocations.each do |name, from_option|
+ value = if from_option
+ option = class_options[name]
+ option.type == :boolean ? name : option.default
+ else
+ name
+ end
+ next unless value
+
+ klass, _ = prepare_for_invocation(name, value)
+ next unless klass && klass.respond_to?(:class_options)
+
+ value = value.to_s
+ human_name = value.respond_to?(:classify) ? value.classify : value
+
+ group_options[human_name] ||= []
+ group_options[human_name] += klass.class_options.values.select do |class_option|
+ base_options[class_option.name.to_sym].nil? && class_option.group.nil? &&
+ !group_options.values.flatten.any? { |i| i.name == class_option.name }
+ end
+
+ yield klass if block_given?
+ end
+ end
+
+ # Returns commands ready to be printed.
+ def printable_commands(*)
+ item = []
+ item << banner
+ item << (desc ? "# #{desc.gsub(/\s+/m, ' ')}" : "")
+ [item]
+ end
+ alias_method :printable_tasks, :printable_commands
+
+ def handle_argument_error(command, error, _args, arity) #:nodoc:
+ msg = "#{basename} #{command.name} takes #{arity} argument".dup
+ msg << "s" if arity > 1
+ msg << ", but it should not."
+ raise error, msg
+ end
+
+ protected
+
+ # The method responsible for dispatching given the args.
+ def dispatch(command, given_args, given_opts, config) #:nodoc:
+ if Bundler::Thor::HELP_MAPPINGS.include?(given_args.first)
+ help(config[:shell])
+ return
+ end
+
+ args, opts = Bundler::Thor::Options.split(given_args)
+ opts = given_opts || opts
+
+ instance = new(args, opts, config)
+ yield instance if block_given?
+
+ if command
+ instance.invoke_command(all_commands[command])
+ else
+ instance.invoke_all
+ end
+ end
+
+ # The banner for this class. You can customize it if you are invoking the
+ # thor class by another ways which is not the Bundler::Thor::Runner.
+ def banner
+ "#{basename} #{self_command.formatted_usage(self, false)}"
+ end
+
+ # Represents the whole class as a command.
+ def self_command #:nodoc:
+ Bundler::Thor::DynamicCommand.new(namespace, class_options)
+ end
+ alias_method :self_task, :self_command
+
+ def baseclass #:nodoc:
+ Bundler::Thor::Group
+ end
+
+ def create_command(meth) #:nodoc:
+ commands[meth.to_s] = Bundler::Thor::Command.new(meth, nil, nil, nil, nil)
+ true
+ end
+ alias_method :create_task, :create_command
+ end
+
+ include Bundler::Thor::Base
+
+protected
+
+ # Shortcut to invoke with padding and block handling. Use internally by
+ # invoke and invoke_from_option class methods.
+ def _invoke_for_class_method(klass, command = nil, *args, &block) #:nodoc:
+ with_padding do
+ if block
+ case block.arity
+ when 3
+ yield(self, klass, command)
+ when 2
+ yield(self, klass)
+ when 1
+ instance_exec(klass, &block)
+ end
+ else
+ invoke klass, command, *args
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/invocation.rb b/lib/bundler/vendor/thor/lib/thor/invocation.rb
new file mode 100644
index 0000000000..866d2212a7
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/invocation.rb
@@ -0,0 +1,177 @@
+class Bundler::Thor
+ module Invocation
+ def self.included(base) #:nodoc:
+ base.extend ClassMethods
+ end
+
+ module ClassMethods
+ # This method is responsible for receiving a name and find the proper
+ # class and command for it. The key is an optional parameter which is
+ # available only in class methods invocations (i.e. in Bundler::Thor::Group).
+ def prepare_for_invocation(key, name) #:nodoc:
+ case name
+ when Symbol, String
+ Bundler::Thor::Util.find_class_and_command_by_namespace(name.to_s, !key)
+ else
+ name
+ end
+ end
+ end
+
+ # Make initializer aware of invocations and the initialization args.
+ def initialize(args = [], options = {}, config = {}, &block) #:nodoc:
+ @_invocations = config[:invocations] || Hash.new { |h, k| h[k] = [] }
+ @_initializer = [args, options, config]
+ super
+ end
+
+ # Make the current command chain accessible with in a Bundler::Thor-(sub)command
+ def current_command_chain
+ @_invocations.values.flatten.map(&:to_sym)
+ end
+
+ # Receives a name and invokes it. The name can be a string (either "command" or
+ # "namespace:command"), a Bundler::Thor::Command, a Class or a Bundler::Thor instance. If the
+ # command cannot be guessed by name, it can also be supplied as second argument.
+ #
+ # You can also supply the arguments, options and configuration values for
+ # the command to be invoked, if none is given, the same values used to
+ # initialize the invoker are used to initialize the invoked.
+ #
+ # When no name is given, it will invoke the default command of the current class.
+ #
+ # ==== Examples
+ #
+ # class A < Bundler::Thor
+ # def foo
+ # invoke :bar
+ # invoke "b:hello", ["Erik"]
+ # end
+ #
+ # def bar
+ # invoke "b:hello", ["Erik"]
+ # end
+ # end
+ #
+ # class B < Bundler::Thor
+ # def hello(name)
+ # puts "hello #{name}"
+ # end
+ # end
+ #
+ # You can notice that the method "foo" above invokes two commands: "bar",
+ # which belongs to the same class and "hello" which belongs to the class B.
+ #
+ # By using an invocation system you ensure that a command is invoked only once.
+ # In the example above, invoking "foo" will invoke "b:hello" just once, even
+ # if it's invoked later by "bar" method.
+ #
+ # When class A invokes class B, all arguments used on A initialization are
+ # supplied to B. This allows lazy parse of options. Let's suppose you have
+ # some rspec commands:
+ #
+ # class Rspec < Bundler::Thor::Group
+ # class_option :mock_framework, :type => :string, :default => :rr
+ #
+ # def invoke_mock_framework
+ # invoke "rspec:#{options[:mock_framework]}"
+ # end
+ # end
+ #
+ # As you noticed, it invokes the given mock framework, which might have its
+ # own options:
+ #
+ # class Rspec::RR < Bundler::Thor::Group
+ # class_option :style, :type => :string, :default => :mock
+ # end
+ #
+ # Since it's not rspec concern to parse mock framework options, when RR
+ # is invoked all options are parsed again, so RR can extract only the options
+ # that it's going to use.
+ #
+ # If you want Rspec::RR to be initialized with its own set of options, you
+ # have to do that explicitly:
+ #
+ # invoke "rspec:rr", [], :style => :foo
+ #
+ # Besides giving an instance, you can also give a class to invoke:
+ #
+ # invoke Rspec::RR, [], :style => :foo
+ #
+ def invoke(name = nil, *args)
+ if name.nil?
+ warn "[Bundler::Thor] Calling invoke() without argument is deprecated. Please use invoke_all instead.\n#{caller.join("\n")}"
+ return invoke_all
+ end
+
+ args.unshift(nil) if args.first.is_a?(Array) || args.first.nil?
+ command, args, opts, config = args
+
+ klass, command = _retrieve_class_and_command(name, command)
+ raise "Missing Bundler::Thor class for invoke #{name}" unless klass
+ raise "Expected Bundler::Thor class, got #{klass}" unless klass <= Bundler::Thor::Base
+
+ args, opts, config = _parse_initialization_options(args, opts, config)
+ klass.send(:dispatch, command, args, opts, config) do |instance|
+ instance.parent_options = options
+ end
+ end
+
+ # Invoke the given command if the given args.
+ def invoke_command(command, *args) #:nodoc:
+ current = @_invocations[self.class]
+
+ unless current.include?(command.name)
+ current << command.name
+ command.run(self, *args)
+ end
+ end
+ alias_method :invoke_task, :invoke_command
+
+ # Invoke all commands for the current instance.
+ def invoke_all #:nodoc:
+ self.class.all_commands.map { |_, command| invoke_command(command) }
+ end
+
+ # Invokes using shell padding.
+ def invoke_with_padding(*args)
+ with_padding { invoke(*args) }
+ end
+
+ protected
+
+ # Configuration values that are shared between invocations.
+ def _shared_configuration #:nodoc:
+ {:invocations => @_invocations}
+ end
+
+ # This method simply retrieves the class and command to be invoked.
+ # If the name is nil or the given name is a command in the current class,
+ # use the given name and return self as class. Otherwise, call
+ # prepare_for_invocation in the current class.
+ def _retrieve_class_and_command(name, sent_command = nil) #:nodoc:
+ if name.nil?
+ [self.class, nil]
+ elsif self.class.all_commands[name.to_s]
+ [self.class, name.to_s]
+ else
+ klass, command = self.class.prepare_for_invocation(nil, name)
+ [klass, command || sent_command]
+ end
+ end
+ alias_method :_retrieve_class_and_task, :_retrieve_class_and_command
+
+ # Initialize klass using values stored in the @_initializer.
+ def _parse_initialization_options(args, opts, config) #:nodoc:
+ stored_args, stored_opts, stored_config = @_initializer
+
+ args ||= stored_args.dup
+ opts ||= stored_opts.dup
+
+ config ||= {}
+ config = stored_config.merge(_shared_configuration).merge!(config)
+
+ [args, opts, config]
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/line_editor.rb b/lib/bundler/vendor/thor/lib/thor/line_editor.rb
new file mode 100644
index 0000000000..ce81a17484
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/line_editor.rb
@@ -0,0 +1,17 @@
+require "bundler/vendor/thor/lib/thor/line_editor/basic"
+require "bundler/vendor/thor/lib/thor/line_editor/readline"
+
+class Bundler::Thor
+ module LineEditor
+ def self.readline(prompt, options = {})
+ best_available.new(prompt, options).readline
+ end
+
+ def self.best_available
+ [
+ Bundler::Thor::LineEditor::Readline,
+ Bundler::Thor::LineEditor::Basic
+ ].detect(&:available?)
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/line_editor/basic.rb b/lib/bundler/vendor/thor/lib/thor/line_editor/basic.rb
new file mode 100644
index 0000000000..0adb2b3137
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/line_editor/basic.rb
@@ -0,0 +1,37 @@
+class Bundler::Thor
+ module LineEditor
+ class Basic
+ attr_reader :prompt, :options
+
+ def self.available?
+ true
+ end
+
+ def initialize(prompt, options)
+ @prompt = prompt
+ @options = options
+ end
+
+ def readline
+ $stdout.print(prompt)
+ get_input
+ end
+
+ private
+
+ def get_input
+ if echo?
+ $stdin.gets
+ else
+ # Lazy-load io/console since it is gem-ified as of 2.3
+ require "io/console" if RUBY_VERSION > "1.9.2"
+ $stdin.noecho(&:gets)
+ end
+ end
+
+ def echo?
+ options.fetch(:echo, true)
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/line_editor/readline.rb b/lib/bundler/vendor/thor/lib/thor/line_editor/readline.rb
new file mode 100644
index 0000000000..dd39cff35d
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/line_editor/readline.rb
@@ -0,0 +1,88 @@
+begin
+ require "readline"
+rescue LoadError
+end
+
+class Bundler::Thor
+ module LineEditor
+ class Readline < Basic
+ def self.available?
+ Object.const_defined?(:Readline)
+ end
+
+ def readline
+ if echo?
+ ::Readline.completion_append_character = nil
+ # Ruby 1.8.7 does not allow Readline.completion_proc= to receive nil.
+ if complete = completion_proc
+ ::Readline.completion_proc = complete
+ end
+ ::Readline.readline(prompt, add_to_history?)
+ else
+ super
+ end
+ end
+
+ private
+
+ def add_to_history?
+ options.fetch(:add_to_history, true)
+ end
+
+ def completion_proc
+ if use_path_completion?
+ proc { |text| PathCompletion.new(text).matches }
+ elsif completion_options.any?
+ proc do |text|
+ completion_options.select { |option| option.start_with?(text) }
+ end
+ end
+ end
+
+ def completion_options
+ options.fetch(:limited_to, [])
+ end
+
+ def use_path_completion?
+ options.fetch(:path, false)
+ end
+
+ class PathCompletion
+ attr_reader :text
+ private :text
+
+ def initialize(text)
+ @text = text
+ end
+
+ def matches
+ relative_matches
+ end
+
+ private
+
+ def relative_matches
+ absolute_matches.map { |path| path.sub(base_path, "") }
+ end
+
+ def absolute_matches
+ Dir[glob_pattern].map do |path|
+ if File.directory?(path)
+ "#{path}/"
+ else
+ path
+ end
+ end
+ end
+
+ def glob_pattern
+ "#{base_path}#{text}*"
+ end
+
+ def base_path
+ "#{Dir.pwd}/"
+ end
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/parser.rb b/lib/bundler/vendor/thor/lib/thor/parser.rb
new file mode 100644
index 0000000000..08f80e565d
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/parser.rb
@@ -0,0 +1,4 @@
+require "bundler/vendor/thor/lib/thor/parser/argument"
+require "bundler/vendor/thor/lib/thor/parser/arguments"
+require "bundler/vendor/thor/lib/thor/parser/option"
+require "bundler/vendor/thor/lib/thor/parser/options"
diff --git a/lib/bundler/vendor/thor/lib/thor/parser/argument.rb b/lib/bundler/vendor/thor/lib/thor/parser/argument.rb
new file mode 100644
index 0000000000..dfe7398583
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/parser/argument.rb
@@ -0,0 +1,70 @@
+class Bundler::Thor
+ class Argument #:nodoc:
+ VALID_TYPES = [:numeric, :hash, :array, :string]
+
+ attr_reader :name, :description, :enum, :required, :type, :default, :banner
+ alias_method :human_name, :name
+
+ def initialize(name, options = {})
+ class_name = self.class.name.split("::").last
+
+ type = options[:type]
+
+ raise ArgumentError, "#{class_name} name can't be nil." if name.nil?
+ raise ArgumentError, "Type :#{type} is not valid for #{class_name.downcase}s." if type && !valid_type?(type)
+
+ @name = name.to_s
+ @description = options[:desc]
+ @required = options.key?(:required) ? options[:required] : true
+ @type = (type || :string).to_sym
+ @default = options[:default]
+ @banner = options[:banner] || default_banner
+ @enum = options[:enum]
+
+ validate! # Trigger specific validations
+ end
+
+ def usage
+ required? ? banner : "[#{banner}]"
+ end
+
+ def required?
+ required
+ end
+
+ def show_default?
+ case default
+ when Array, String, Hash
+ !default.empty?
+ else
+ default
+ end
+ end
+
+ protected
+
+ def validate!
+ raise ArgumentError, "An argument cannot be required and have default value." if required? && !default.nil?
+ raise ArgumentError, "An argument cannot have an enum other than an array." if @enum && !@enum.is_a?(Array)
+ end
+
+ def valid_type?(type)
+ self.class::VALID_TYPES.include?(type.to_sym)
+ end
+
+ def default_banner
+ case type
+ when :boolean
+ nil
+ when :string, :default
+ human_name.upcase
+ when :numeric
+ "N"
+ when :hash
+ "key:value"
+ when :array
+ "one two three"
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb b/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb
new file mode 100644
index 0000000000..1fd790f4b7
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb
@@ -0,0 +1,175 @@
+class Bundler::Thor
+ class Arguments #:nodoc: # rubocop:disable ClassLength
+ NUMERIC = /[-+]?(\d*\.\d+|\d+)/
+
+ # Receives an array of args and returns two arrays, one with arguments
+ # and one with switches.
+ #
+ def self.split(args)
+ arguments = []
+
+ args.each do |item|
+ break if item =~ /^-/
+ arguments << item
+ end
+
+ [arguments, args[Range.new(arguments.size, -1)]]
+ end
+
+ def self.parse(*args)
+ to_parse = args.pop
+ new(*args).parse(to_parse)
+ end
+
+ # Takes an array of Bundler::Thor::Argument objects.
+ #
+ def initialize(arguments = [])
+ @assigns = {}
+ @non_assigned_required = []
+ @switches = arguments
+
+ arguments.each do |argument|
+ if !argument.default.nil?
+ @assigns[argument.human_name] = argument.default
+ elsif argument.required?
+ @non_assigned_required << argument
+ end
+ end
+ end
+
+ def parse(args)
+ @pile = args.dup
+
+ @switches.each do |argument|
+ break unless peek
+ @non_assigned_required.delete(argument)
+ @assigns[argument.human_name] = send(:"parse_#{argument.type}", argument.human_name)
+ end
+
+ check_requirement!
+ @assigns
+ end
+
+ def remaining
+ @pile
+ end
+
+ private
+
+ def no_or_skip?(arg)
+ arg =~ /^--(no|skip)-([-\w]+)$/
+ $2
+ end
+
+ def last?
+ @pile.empty?
+ end
+
+ def peek
+ @pile.first
+ end
+
+ def shift
+ @pile.shift
+ end
+
+ def unshift(arg)
+ if arg.is_a?(Array)
+ @pile = arg + @pile
+ else
+ @pile.unshift(arg)
+ end
+ end
+
+ def current_is_value?
+ peek && peek.to_s !~ /^-/
+ end
+
+ # Runs through the argument array getting strings that contains ":" and
+ # mark it as a hash:
+ #
+ # [ "name:string", "age:integer" ]
+ #
+ # Becomes:
+ #
+ # { "name" => "string", "age" => "integer" }
+ #
+ def parse_hash(name)
+ return shift if peek.is_a?(Hash)
+ hash = {}
+
+ while current_is_value? && peek.include?(":")
+ key, value = shift.split(":", 2)
+ raise MalformattedArgumentError, "You can't specify '#{key}' more than once in option '#{name}'; got #{key}:#{hash[key]} and #{key}:#{value}" if hash.include? key
+ hash[key] = value
+ end
+ hash
+ end
+
+ # Runs through the argument array getting all strings until no string is
+ # found or a switch is found.
+ #
+ # ["a", "b", "c"]
+ #
+ # And returns it as an array:
+ #
+ # ["a", "b", "c"]
+ #
+ def parse_array(name)
+ return shift if peek.is_a?(Array)
+ array = []
+ array << shift while current_is_value?
+ array
+ end
+
+ # Check if the peek is numeric format and return a Float or Integer.
+ # Check if the peek is included in enum if enum is provided.
+ # Otherwise raises an error.
+ #
+ def parse_numeric(name)
+ return shift if peek.is_a?(Numeric)
+
+ unless peek =~ NUMERIC && $& == peek
+ raise MalformattedArgumentError, "Expected numeric value for '#{name}'; got #{peek.inspect}"
+ end
+
+ value = $&.index(".") ? shift.to_f : shift.to_i
+ if @switches.is_a?(Hash) && switch = @switches[name]
+ if switch.enum && !switch.enum.include?(value)
+ raise MalformattedArgumentError, "Expected '#{name}' to be one of #{switch.enum.join(', ')}; got #{value}"
+ end
+ end
+ value
+ end
+
+ # Parse string:
+ # for --string-arg, just return the current value in the pile
+ # for --no-string-arg, nil
+ # Check if the peek is included in enum if enum is provided. Otherwise raises an error.
+ #
+ def parse_string(name)
+ if no_or_skip?(name)
+ nil
+ else
+ value = shift
+ if @switches.is_a?(Hash) && switch = @switches[name]
+ if switch.enum && !switch.enum.include?(value)
+ raise MalformattedArgumentError, "Expected '#{name}' to be one of #{switch.enum.join(', ')}; got #{value}"
+ end
+ end
+ value
+ end
+ end
+
+ # Raises an error if @non_assigned_required array is not empty.
+ #
+ def check_requirement!
+ return if @non_assigned_required.empty?
+ names = @non_assigned_required.map do |o|
+ o.respond_to?(:switch_name) ? o.switch_name : o.human_name
+ end.join("', '")
+ class_name = self.class.name.split("::").last.downcase
+ raise RequiredArgumentMissingError, "No value provided for required #{class_name} '#{names}'"
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/parser/option.rb b/lib/bundler/vendor/thor/lib/thor/parser/option.rb
new file mode 100644
index 0000000000..85169b56c8
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/parser/option.rb
@@ -0,0 +1,146 @@
+class Bundler::Thor
+ class Option < Argument #:nodoc:
+ attr_reader :aliases, :group, :lazy_default, :hide
+
+ VALID_TYPES = [:boolean, :numeric, :hash, :array, :string]
+
+ def initialize(name, options = {})
+ @check_default_type = options[:check_default_type]
+ options[:required] = false unless options.key?(:required)
+ super
+ @lazy_default = options[:lazy_default]
+ @group = options[:group].to_s.capitalize if options[:group]
+ @aliases = Array(options[:aliases])
+ @hide = options[:hide]
+ end
+
+ # This parse quick options given as method_options. It makes several
+ # assumptions, but you can be more specific using the option method.
+ #
+ # parse :foo => "bar"
+ # #=> Option foo with default value bar
+ #
+ # parse [:foo, :baz] => "bar"
+ # #=> Option foo with default value bar and alias :baz
+ #
+ # parse :foo => :required
+ # #=> Required option foo without default value
+ #
+ # parse :foo => 2
+ # #=> Option foo with default value 2 and type numeric
+ #
+ # parse :foo => :numeric
+ # #=> Option foo without default value and type numeric
+ #
+ # parse :foo => true
+ # #=> Option foo with default value true and type boolean
+ #
+ # The valid types are :boolean, :numeric, :hash, :array and :string. If none
+ # is given a default type is assumed. This default type accepts arguments as
+ # string (--foo=value) or booleans (just --foo).
+ #
+ # By default all options are optional, unless :required is given.
+ #
+ def self.parse(key, value)
+ if key.is_a?(Array)
+ name, *aliases = key
+ else
+ name = key
+ aliases = []
+ end
+
+ name = name.to_s
+ default = value
+
+ type = case value
+ when Symbol
+ default = nil
+ if VALID_TYPES.include?(value)
+ value
+ elsif required = (value == :required) # rubocop:disable AssignmentInCondition
+ :string
+ end
+ when TrueClass, FalseClass
+ :boolean
+ when Numeric
+ :numeric
+ when Hash, Array, String
+ value.class.name.downcase.to_sym
+ end
+
+ new(name.to_s, :required => required, :type => type, :default => default, :aliases => aliases)
+ end
+
+ def switch_name
+ @switch_name ||= dasherized? ? name : dasherize(name)
+ end
+
+ def human_name
+ @human_name ||= dasherized? ? undasherize(name) : name
+ end
+
+ def usage(padding = 0)
+ sample = if banner && !banner.to_s.empty?
+ "#{switch_name}=#{banner}".dup
+ else
+ switch_name
+ end
+
+ sample = "[#{sample}]".dup unless required?
+
+ if boolean?
+ sample << ", [#{dasherize('no-' + human_name)}]" unless (name == "force") || name.start_with?("no-")
+ end
+
+ if aliases.empty?
+ (" " * padding) << sample
+ else
+ "#{aliases.join(', ')}, #{sample}"
+ end
+ end
+
+ VALID_TYPES.each do |type|
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def #{type}?
+ self.type == #{type.inspect}
+ end
+ RUBY
+ end
+
+ protected
+
+ def validate!
+ raise ArgumentError, "An option cannot be boolean and required." if boolean? && required?
+ validate_default_type! if @check_default_type
+ end
+
+ def validate_default_type!
+ default_type = case @default
+ when nil
+ return
+ when TrueClass, FalseClass
+ required? ? :string : :boolean
+ when Numeric
+ :numeric
+ when Symbol
+ :string
+ when Hash, Array, String
+ @default.class.name.downcase.to_sym
+ end
+
+ raise ArgumentError, "Expected #{@type} default value for '#{switch_name}'; got #{@default.inspect} (#{default_type})" unless default_type == @type
+ end
+
+ def dasherized?
+ name.index("-") == 0
+ end
+
+ def undasherize(str)
+ str.sub(/^-{1,2}/, "")
+ end
+
+ def dasherize(str)
+ (str.length > 1 ? "--" : "-") + str.tr("_", "-")
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/parser/options.rb b/lib/bundler/vendor/thor/lib/thor/parser/options.rb
new file mode 100644
index 0000000000..70f6366842
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/parser/options.rb
@@ -0,0 +1,221 @@
+class Bundler::Thor
+ class Options < Arguments #:nodoc: # rubocop:disable ClassLength
+ LONG_RE = /^(--\w+(?:-\w+)*)$/
+ SHORT_RE = /^(-[a-z])$/i
+ EQ_RE = /^(--\w+(?:-\w+)*|-[a-z])=(.*)$/i
+ SHORT_SQ_RE = /^-([a-z]{2,})$/i # Allow either -x -v or -xv style for single char args
+ SHORT_NUM = /^(-[a-z])#{NUMERIC}$/i
+ OPTS_END = "--".freeze
+
+ # Receives a hash and makes it switches.
+ def self.to_switches(options)
+ options.map do |key, value|
+ case value
+ when true
+ "--#{key}"
+ when Array
+ "--#{key} #{value.map(&:inspect).join(' ')}"
+ when Hash
+ "--#{key} #{value.map { |k, v| "#{k}:#{v}" }.join(' ')}"
+ when nil, false
+ nil
+ else
+ "--#{key} #{value.inspect}"
+ end
+ end.compact.join(" ")
+ end
+
+ # Takes a hash of Bundler::Thor::Option and a hash with defaults.
+ #
+ # If +stop_on_unknown+ is true, #parse will stop as soon as it encounters
+ # an unknown option or a regular argument.
+ def initialize(hash_options = {}, defaults = {}, stop_on_unknown = false, disable_required_check = false)
+ @stop_on_unknown = stop_on_unknown
+ @disable_required_check = disable_required_check
+ options = hash_options.values
+ super(options)
+
+ # Add defaults
+ defaults.each do |key, value|
+ @assigns[key.to_s] = value
+ @non_assigned_required.delete(hash_options[key])
+ end
+
+ @shorts = {}
+ @switches = {}
+ @extra = []
+
+ options.each do |option|
+ @switches[option.switch_name] = option
+
+ option.aliases.each do |short|
+ name = short.to_s.sub(/^(?!\-)/, "-")
+ @shorts[name] ||= option.switch_name
+ end
+ end
+ end
+
+ def remaining
+ @extra
+ end
+
+ def peek
+ return super unless @parsing_options
+
+ result = super
+ if result == OPTS_END
+ shift
+ @parsing_options = false
+ super
+ else
+ result
+ end
+ end
+
+ def parse(args) # rubocop:disable MethodLength
+ @pile = args.dup
+ @parsing_options = true
+
+ while peek
+ if parsing_options?
+ match, is_switch = current_is_switch?
+ shifted = shift
+
+ if is_switch
+ case shifted
+ when SHORT_SQ_RE
+ unshift($1.split("").map { |f| "-#{f}" })
+ next
+ when EQ_RE, SHORT_NUM
+ unshift($2)
+ switch = $1
+ when LONG_RE, SHORT_RE
+ switch = $1
+ end
+
+ switch = normalize_switch(switch)
+ option = switch_option(switch)
+ @assigns[option.human_name] = parse_peek(switch, option)
+ elsif @stop_on_unknown
+ @parsing_options = false
+ @extra << shifted
+ @extra << shift while peek
+ break
+ elsif match
+ @extra << shifted
+ @extra << shift while peek && peek !~ /^-/
+ else
+ @extra << shifted
+ end
+ else
+ @extra << shift
+ end
+ end
+
+ check_requirement! unless @disable_required_check
+
+ assigns = Bundler::Thor::CoreExt::HashWithIndifferentAccess.new(@assigns)
+ assigns.freeze
+ assigns
+ end
+
+ def check_unknown!
+ # an unknown option starts with - or -- and has no more --'s afterward.
+ unknown = @extra.select { |str| str =~ /^--?(?:(?!--).)*$/ }
+ raise UnknownArgumentError, "Unknown switches '#{unknown.join(', ')}'" unless unknown.empty?
+ end
+
+ protected
+
+ # Check if the current value in peek is a registered switch.
+ #
+ # Two booleans are returned. The first is true if the current value
+ # starts with a hyphen; the second is true if it is a registered switch.
+ def current_is_switch?
+ case peek
+ when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM
+ [true, switch?($1)]
+ when SHORT_SQ_RE
+ [true, $1.split("").any? { |f| switch?("-#{f}") }]
+ else
+ [false, false]
+ end
+ end
+
+ def current_is_switch_formatted?
+ case peek
+ when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM, SHORT_SQ_RE
+ true
+ else
+ false
+ end
+ end
+
+ def current_is_value?
+ peek && (!parsing_options? || super)
+ end
+
+ def switch?(arg)
+ switch_option(normalize_switch(arg))
+ end
+
+ def switch_option(arg)
+ if match = no_or_skip?(arg) # rubocop:disable AssignmentInCondition
+ @switches[arg] || @switches["--#{match}"]
+ else
+ @switches[arg]
+ end
+ end
+
+ # Check if the given argument is actually a shortcut.
+ #
+ def normalize_switch(arg)
+ (@shorts[arg] || arg).tr("_", "-")
+ end
+
+ def parsing_options?
+ peek
+ @parsing_options
+ end
+
+ # Parse boolean values which can be given as --foo=true, --foo or --no-foo.
+ #
+ def parse_boolean(switch)
+ if current_is_value?
+ if ["true", "TRUE", "t", "T", true].include?(peek)
+ shift
+ true
+ elsif ["false", "FALSE", "f", "F", false].include?(peek)
+ shift
+ false
+ else
+ !no_or_skip?(switch)
+ end
+ else
+ @switches.key?(switch) || !no_or_skip?(switch)
+ end
+ end
+
+ # Parse the value at the peek analyzing if it requires an input or not.
+ #
+ def parse_peek(switch, option)
+ if parsing_options? && (current_is_switch_formatted? || last?)
+ if option.boolean?
+ # No problem for boolean types
+ elsif no_or_skip?(switch)
+ return nil # User set value to nil
+ elsif option.string? && !option.required?
+ # Return the default if there is one, else the human name
+ return option.lazy_default || option.default || option.human_name
+ elsif option.lazy_default
+ return option.lazy_default
+ else
+ raise MalformattedArgumentError, "No value provided for option '#{switch}'"
+ end
+ end
+
+ @non_assigned_required.delete(option)
+ send(:"parse_#{option.type}", switch)
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/rake_compat.rb b/lib/bundler/vendor/thor/lib/thor/rake_compat.rb
new file mode 100644
index 0000000000..60282e2991
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/rake_compat.rb
@@ -0,0 +1,71 @@
+require "rake"
+require "rake/dsl_definition"
+
+class Bundler::Thor
+ # Adds a compatibility layer to your Bundler::Thor classes which allows you to use
+ # rake package tasks. For example, to use rspec rake tasks, one can do:
+ #
+ # require 'bundler/vendor/thor/lib/thor/rake_compat'
+ # require 'rspec/core/rake_task'
+ #
+ # class Default < Bundler::Thor
+ # include Bundler::Thor::RakeCompat
+ #
+ # RSpec::Core::RakeTask.new(:spec) do |t|
+ # t.spec_opts = ['--options', './.rspec']
+ # t.spec_files = FileList['spec/**/*_spec.rb']
+ # end
+ # end
+ #
+ module RakeCompat
+ include Rake::DSL if defined?(Rake::DSL)
+
+ def self.rake_classes
+ @rake_classes ||= []
+ end
+
+ def self.included(base)
+ # Hack. Make rakefile point to invoker, so rdoc task is generated properly.
+ rakefile = File.basename(caller[0].match(/(.*):\d+/)[1])
+ Rake.application.instance_variable_set(:@rakefile, rakefile)
+ rake_classes << base
+ end
+ end
+end
+
+# override task on (main), for compatibility with Rake 0.9
+instance_eval do
+ alias rake_namespace namespace
+
+ def task(*)
+ task = super
+
+ if klass = Bundler::Thor::RakeCompat.rake_classes.last # rubocop:disable AssignmentInCondition
+ non_namespaced_name = task.name.split(":").last
+
+ description = non_namespaced_name
+ description << task.arg_names.map { |n| n.to_s.upcase }.join(" ")
+ description.strip!
+
+ klass.desc description, Rake.application.last_description || non_namespaced_name
+ Rake.application.last_description = nil
+ klass.send :define_method, non_namespaced_name do |*args|
+ Rake::Task[task.name.to_sym].invoke(*args)
+ end
+ end
+
+ task
+ end
+
+ def namespace(name)
+ if klass = Bundler::Thor::RakeCompat.rake_classes.last # rubocop:disable AssignmentInCondition
+ const_name = Bundler::Thor::Util.camel_case(name.to_s).to_sym
+ klass.const_set(const_name, Class.new(Bundler::Thor))
+ new_klass = klass.const_get(const_name)
+ Bundler::Thor::RakeCompat.rake_classes << new_klass
+ end
+
+ super
+ Bundler::Thor::RakeCompat.rake_classes.pop
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/runner.rb b/lib/bundler/vendor/thor/lib/thor/runner.rb
new file mode 100644
index 0000000000..b110b8d478
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/runner.rb
@@ -0,0 +1,324 @@
+require "bundler/vendor/thor/lib/thor"
+require "bundler/vendor/thor/lib/thor/group"
+require "bundler/vendor/thor/lib/thor/core_ext/io_binary_read"
+
+require "yaml"
+require "digest"
+require "pathname"
+
+class Bundler::Thor::Runner < Bundler::Thor #:nodoc: # rubocop:disable ClassLength
+ map "-T" => :list, "-i" => :install, "-u" => :update, "-v" => :version
+
+ def self.banner(command, all = false, subcommand = false)
+ "thor " + command.formatted_usage(self, all, subcommand)
+ end
+
+ def self.exit_on_failure?
+ true
+ end
+
+ # Override Bundler::Thor#help so it can give information about any class and any method.
+ #
+ def help(meth = nil)
+ if meth && !respond_to?(meth)
+ initialize_thorfiles(meth)
+ klass, command = Bundler::Thor::Util.find_class_and_command_by_namespace(meth)
+ self.class.handle_no_command_error(command, false) if klass.nil?
+ klass.start(["-h", command].compact, :shell => shell)
+ else
+ super
+ end
+ end
+
+ # If a command is not found on Bundler::Thor::Runner, method missing is invoked and
+ # Bundler::Thor::Runner is then responsible for finding the command in all classes.
+ #
+ def method_missing(meth, *args)
+ meth = meth.to_s
+ initialize_thorfiles(meth)
+ klass, command = Bundler::Thor::Util.find_class_and_command_by_namespace(meth)
+ self.class.handle_no_command_error(command, false) if klass.nil?
+ args.unshift(command) if command
+ klass.start(args, :shell => shell)
+ end
+
+ desc "install NAME", "Install an optionally named Bundler::Thor file into your system commands"
+ method_options :as => :string, :relative => :boolean, :force => :boolean
+ def install(name) # rubocop:disable MethodLength
+ initialize_thorfiles
+
+ # If a directory name is provided as the argument, look for a 'main.thor'
+ # command in said directory.
+ begin
+ if File.directory?(File.expand_path(name))
+ base = File.join(name, "main.thor")
+ package = :directory
+ contents = open(base, &:read)
+ else
+ base = name
+ package = :file
+ contents = open(name, &:read)
+ end
+ rescue OpenURI::HTTPError
+ raise Error, "Error opening URI '#{name}'"
+ rescue Errno::ENOENT
+ raise Error, "Error opening file '#{name}'"
+ end
+
+ say "Your Bundler::Thorfile contains:"
+ say contents
+
+ unless options["force"]
+ return false if no?("Do you wish to continue [y/N]?")
+ end
+
+ as = options["as"] || begin
+ first_line = contents.split("\n")[0]
+ (match = first_line.match(/\s*#\s*module:\s*([^\n]*)/)) ? match[1].strip : nil
+ end
+
+ unless as
+ basename = File.basename(name)
+ as = ask("Please specify a name for #{name} in the system repository [#{basename}]:")
+ as = basename if as.empty?
+ end
+
+ location = if options[:relative] || name =~ %r{^https?://}
+ name
+ else
+ File.expand_path(name)
+ end
+
+ thor_yaml[as] = {
+ :filename => Digest(:MD5).hexdigest(name + as),
+ :location => location,
+ :namespaces => Bundler::Thor::Util.namespaces_in_content(contents, base)
+ }
+
+ save_yaml(thor_yaml)
+ say "Storing thor file in your system repository"
+ destination = File.join(thor_root, thor_yaml[as][:filename])
+
+ if package == :file
+ File.open(destination, "w") { |f| f.puts contents }
+ else
+ require "fileutils"
+ FileUtils.cp_r(name, destination)
+ end
+
+ thor_yaml[as][:filename] # Indicate success
+ end
+
+ desc "version", "Show Bundler::Thor version"
+ def version
+ require "bundler/vendor/thor/lib/thor/version"
+ say "Bundler::Thor #{Bundler::Thor::VERSION}"
+ end
+
+ desc "uninstall NAME", "Uninstall a named Bundler::Thor module"
+ def uninstall(name)
+ raise Error, "Can't find module '#{name}'" unless thor_yaml[name]
+ say "Uninstalling #{name}."
+ require "fileutils"
+ FileUtils.rm_rf(File.join(thor_root, (thor_yaml[name][:filename]).to_s))
+
+ thor_yaml.delete(name)
+ save_yaml(thor_yaml)
+
+ puts "Done."
+ end
+
+ desc "update NAME", "Update a Bundler::Thor file from its original location"
+ def update(name)
+ raise Error, "Can't find module '#{name}'" if !thor_yaml[name] || !thor_yaml[name][:location]
+
+ say "Updating '#{name}' from #{thor_yaml[name][:location]}"
+
+ old_filename = thor_yaml[name][:filename]
+ self.options = options.merge("as" => name)
+
+ if File.directory? File.expand_path(name)
+ require "fileutils"
+ FileUtils.rm_rf(File.join(thor_root, old_filename))
+
+ thor_yaml.delete(old_filename)
+ save_yaml(thor_yaml)
+
+ filename = install(name)
+ else
+ filename = install(thor_yaml[name][:location])
+ end
+
+ File.delete(File.join(thor_root, old_filename)) unless filename == old_filename
+ end
+
+ desc "installed", "List the installed Bundler::Thor modules and commands"
+ method_options :internal => :boolean
+ def installed
+ initialize_thorfiles(nil, true)
+ display_klasses(true, options["internal"])
+ end
+
+ desc "list [SEARCH]", "List the available thor commands (--substring means .*SEARCH)"
+ method_options :substring => :boolean, :group => :string, :all => :boolean, :debug => :boolean
+ def list(search = "")
+ initialize_thorfiles
+
+ search = ".*#{search}" if options["substring"]
+ search = /^#{search}.*/i
+ group = options[:group] || "standard"
+
+ klasses = Bundler::Thor::Base.subclasses.select do |k|
+ (options[:all] || k.group == group) && k.namespace =~ search
+ end
+
+ display_klasses(false, false, klasses)
+ end
+
+private
+
+ def thor_root
+ Bundler::Thor::Util.thor_root
+ end
+
+ def thor_yaml
+ @thor_yaml ||= begin
+ yaml_file = File.join(thor_root, "thor.yml")
+ yaml = YAML.load_file(yaml_file) if File.exist?(yaml_file)
+ yaml || {}
+ end
+ end
+
+ # Save the yaml file. If none exists in thor root, creates one.
+ #
+ def save_yaml(yaml)
+ yaml_file = File.join(thor_root, "thor.yml")
+
+ unless File.exist?(yaml_file)
+ require "fileutils"
+ FileUtils.mkdir_p(thor_root)
+ yaml_file = File.join(thor_root, "thor.yml")
+ FileUtils.touch(yaml_file)
+ end
+
+ File.open(yaml_file, "w") { |f| f.puts yaml.to_yaml }
+ end
+
+ # Load the Bundler::Thorfiles. If relevant_to is supplied, looks for specific files
+ # in the thor_root instead of loading them all.
+ #
+ # By default, it also traverses the current path until find Bundler::Thor files, as
+ # described in thorfiles. This look up can be skipped by supplying
+ # skip_lookup true.
+ #
+ def initialize_thorfiles(relevant_to = nil, skip_lookup = false)
+ thorfiles(relevant_to, skip_lookup).each do |f|
+ Bundler::Thor::Util.load_thorfile(f, nil, options[:debug]) unless Bundler::Thor::Base.subclass_files.keys.include?(File.expand_path(f))
+ end
+ end
+
+ # Finds Bundler::Thorfiles by traversing from your current directory down to the root
+ # directory of your system. If at any time we find a Bundler::Thor file, we stop.
+ #
+ # We also ensure that system-wide Bundler::Thorfiles are loaded first, so local
+ # Bundler::Thorfiles can override them.
+ #
+ # ==== Example
+ #
+ # If we start at /Users/wycats/dev/thor ...
+ #
+ # 1. /Users/wycats/dev/thor
+ # 2. /Users/wycats/dev
+ # 3. /Users/wycats <-- we find a Bundler::Thorfile here, so we stop
+ #
+ # Suppose we start at c:\Documents and Settings\james\dev\thor ...
+ #
+ # 1. c:\Documents and Settings\james\dev\thor
+ # 2. c:\Documents and Settings\james\dev
+ # 3. c:\Documents and Settings\james
+ # 4. c:\Documents and Settings
+ # 5. c:\ <-- no Bundler::Thorfiles found!
+ #
+ def thorfiles(relevant_to = nil, skip_lookup = false)
+ thorfiles = []
+
+ unless skip_lookup
+ Pathname.pwd.ascend do |path|
+ thorfiles = Bundler::Thor::Util.globs_for(path).map { |g| Dir[g] }.flatten
+ break unless thorfiles.empty?
+ end
+ end
+
+ files = (relevant_to ? thorfiles_relevant_to(relevant_to) : Bundler::Thor::Util.thor_root_glob)
+ files += thorfiles
+ files -= ["#{thor_root}/thor.yml"]
+
+ files.map! do |file|
+ File.directory?(file) ? File.join(file, "main.thor") : file
+ end
+ end
+
+ # Load Bundler::Thorfiles relevant to the given method. If you provide "foo:bar" it
+ # will load all thor files in the thor.yaml that has "foo" e "foo:bar"
+ # namespaces registered.
+ #
+ def thorfiles_relevant_to(meth)
+ lookup = [meth, meth.split(":")[0...-1].join(":")]
+
+ files = thor_yaml.select do |_, v|
+ v[:namespaces] && !(v[:namespaces] & lookup).empty?
+ end
+
+ files.map { |_, v| File.join(thor_root, (v[:filename]).to_s) }
+ end
+
+ # Display information about the given klasses. If with_module is given,
+ # it shows a table with information extracted from the yaml file.
+ #
+ def display_klasses(with_modules = false, show_internal = false, klasses = Bundler::Thor::Base.subclasses)
+ klasses -= [Bundler::Thor, Bundler::Thor::Runner, Bundler::Thor::Group] unless show_internal
+
+ raise Error, "No Bundler::Thor commands available" if klasses.empty?
+ show_modules if with_modules && !thor_yaml.empty?
+
+ list = Hash.new { |h, k| h[k] = [] }
+ groups = klasses.select { |k| k.ancestors.include?(Bundler::Thor::Group) }
+
+ # Get classes which inherit from Bundler::Thor
+ (klasses - groups).each { |k| list[k.namespace.split(":").first] += k.printable_commands(false) }
+
+ # Get classes which inherit from Bundler::Thor::Base
+ groups.map! { |k| k.printable_commands(false).first }
+ list["root"] = groups
+
+ # Order namespaces with default coming first
+ list = list.sort { |a, b| a[0].sub(/^default/, "") <=> b[0].sub(/^default/, "") }
+ list.each { |n, commands| display_commands(n, commands) unless commands.empty? }
+ end
+
+ def display_commands(namespace, list) #:nodoc:
+ list.sort! { |a, b| a[0] <=> b[0] }
+
+ say shell.set_color(namespace, :blue, true)
+ say "-" * namespace.size
+
+ print_table(list, :truncate => true)
+ say
+ end
+ alias_method :display_tasks, :display_commands
+
+ def show_modules #:nodoc:
+ info = []
+ labels = %w(Modules Namespaces)
+
+ info << labels
+ info << ["-" * labels[0].size, "-" * labels[1].size]
+
+ thor_yaml.each do |name, hash|
+ info << [name, hash[:namespaces].join(", ")]
+ end
+
+ print_table info
+ say ""
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/shell.rb b/lib/bundler/vendor/thor/lib/thor/shell.rb
new file mode 100644
index 0000000000..e945549324
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/shell.rb
@@ -0,0 +1,81 @@
+require "rbconfig"
+
+class Bundler::Thor
+ module Base
+ class << self
+ attr_writer :shell
+
+ # Returns the shell used in all Bundler::Thor classes. If you are in a Unix platform
+ # it will use a colored log, otherwise it will use a basic one without color.
+ #
+ def shell
+ @shell ||= if ENV["THOR_SHELL"] && !ENV["THOR_SHELL"].empty?
+ Bundler::Thor::Shell.const_get(ENV["THOR_SHELL"])
+ elsif RbConfig::CONFIG["host_os"] =~ /mswin|mingw/ && !ENV["ANSICON"]
+ Bundler::Thor::Shell::Basic
+ else
+ Bundler::Thor::Shell::Color
+ end
+ end
+ end
+ end
+
+ module Shell
+ SHELL_DELEGATED_METHODS = [:ask, :error, :set_color, :yes?, :no?, :say, :say_status, :print_in_columns, :print_table, :print_wrapped, :file_collision, :terminal_width]
+ attr_writer :shell
+
+ autoload :Basic, "bundler/vendor/thor/lib/thor/shell/basic"
+ autoload :Color, "bundler/vendor/thor/lib/thor/shell/color"
+ autoload :HTML, "bundler/vendor/thor/lib/thor/shell/html"
+
+ # Add shell to initialize config values.
+ #
+ # ==== Configuration
+ # shell<Object>:: An instance of the shell to be used.
+ #
+ # ==== Examples
+ #
+ # class MyScript < Bundler::Thor
+ # argument :first, :type => :numeric
+ # end
+ #
+ # MyScript.new [1.0], { :foo => :bar }, :shell => Bundler::Thor::Shell::Basic.new
+ #
+ def initialize(args = [], options = {}, config = {})
+ super
+ self.shell = config[:shell]
+ shell.base ||= self if shell.respond_to?(:base)
+ end
+
+ # Holds the shell for the given Bundler::Thor instance. If no shell is given,
+ # it gets a default shell from Bundler::Thor::Base.shell.
+ def shell
+ @shell ||= Bundler::Thor::Base.shell.new
+ end
+
+ # Common methods that are delegated to the shell.
+ SHELL_DELEGATED_METHODS.each do |method|
+ module_eval <<-METHOD, __FILE__, __LINE__
+ def #{method}(*args,&block)
+ shell.#{method}(*args,&block)
+ end
+ METHOD
+ end
+
+ # Yields the given block with padding.
+ def with_padding
+ shell.padding += 1
+ yield
+ ensure
+ shell.padding -= 1
+ end
+
+ protected
+
+ # Allow shell to be shared between invocations.
+ #
+ def _shared_configuration #:nodoc:
+ super.merge!(:shell => shell)
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/shell/basic.rb b/lib/bundler/vendor/thor/lib/thor/shell/basic.rb
new file mode 100644
index 0000000000..5162390efd
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/shell/basic.rb
@@ -0,0 +1,437 @@
+class Bundler::Thor
+ module Shell
+ class Basic
+ attr_accessor :base
+ attr_reader :padding
+
+ # Initialize base, mute and padding to nil.
+ #
+ def initialize #:nodoc:
+ @base = nil
+ @mute = false
+ @padding = 0
+ @always_force = false
+ end
+
+ # Mute everything that's inside given block
+ #
+ def mute
+ @mute = true
+ yield
+ ensure
+ @mute = false
+ end
+
+ # Check if base is muted
+ #
+ def mute?
+ @mute
+ end
+
+ # Sets the output padding, not allowing less than zero values.
+ #
+ def padding=(value)
+ @padding = [0, value].max
+ end
+
+ # Sets the output padding while executing a block and resets it.
+ #
+ def indent(count = 1)
+ orig_padding = padding
+ self.padding = padding + count
+ yield
+ self.padding = orig_padding
+ end
+
+ # Asks something to the user and receives a response.
+ #
+ # If asked to limit the correct responses, you can pass in an
+ # array of acceptable answers. If one of those is not supplied,
+ # they will be shown a message stating that one of those answers
+ # must be given and re-asked the question.
+ #
+ # If asking for sensitive information, the :echo option can be set
+ # to false to mask user input from $stdin.
+ #
+ # If the required input is a path, then set the path option to
+ # true. This will enable tab completion for file paths relative
+ # to the current working directory on systems that support
+ # Readline.
+ #
+ # ==== Example
+ # ask("What is your name?")
+ #
+ # ask("What is your favorite Neopolitan flavor?", :limited_to => ["strawberry", "chocolate", "vanilla"])
+ #
+ # ask("What is your password?", :echo => false)
+ #
+ # ask("Where should the file be saved?", :path => true)
+ #
+ def ask(statement, *args)
+ options = args.last.is_a?(Hash) ? args.pop : {}
+ color = args.first
+
+ if options[:limited_to]
+ ask_filtered(statement, color, options)
+ else
+ ask_simply(statement, color, options)
+ end
+ end
+
+ # Say (print) something to the user. If the sentence ends with a whitespace
+ # or tab character, a new line is not appended (print + flush). Otherwise
+ # are passed straight to puts (behavior got from Highline).
+ #
+ # ==== Example
+ # say("I know you knew that.")
+ #
+ def say(message = "", color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/))
+ buffer = prepare_message(message, *color)
+ buffer << "\n" if force_new_line && !message.to_s.end_with?("\n")
+
+ stdout.print(buffer)
+ stdout.flush
+ end
+
+ # Say a status with the given color and appends the message. Since this
+ # method is used frequently by actions, it allows nil or false to be given
+ # in log_status, avoiding the message from being shown. If a Symbol is
+ # given in log_status, it's used as the color.
+ #
+ def say_status(status, message, log_status = true)
+ return if quiet? || log_status == false
+ spaces = " " * (padding + 1)
+ color = log_status.is_a?(Symbol) ? log_status : :green
+
+ status = status.to_s.rjust(12)
+ status = set_color status, color, true if color
+
+ buffer = "#{status}#{spaces}#{message}"
+ buffer = "#{buffer}\n" unless buffer.end_with?("\n")
+
+ stdout.print(buffer)
+ stdout.flush
+ end
+
+ # Make a question the to user and returns true if the user replies "y" or
+ # "yes".
+ #
+ def yes?(statement, color = nil)
+ !!(ask(statement, color, :add_to_history => false) =~ is?(:yes))
+ end
+
+ # Make a question the to user and returns true if the user replies "n" or
+ # "no".
+ #
+ def no?(statement, color = nil)
+ !!(ask(statement, color, :add_to_history => false) =~ is?(:no))
+ end
+
+ # Prints values in columns
+ #
+ # ==== Parameters
+ # Array[String, String, ...]
+ #
+ def print_in_columns(array)
+ return if array.empty?
+ colwidth = (array.map { |el| el.to_s.size }.max || 0) + 2
+ array.each_with_index do |value, index|
+ # Don't output trailing spaces when printing the last column
+ if ((((index + 1) % (terminal_width / colwidth))).zero? && !index.zero?) || index + 1 == array.length
+ stdout.puts value
+ else
+ stdout.printf("%-#{colwidth}s", value)
+ end
+ end
+ end
+
+ # Prints a table.
+ #
+ # ==== Parameters
+ # Array[Array[String, String, ...]]
+ #
+ # ==== Options
+ # indent<Integer>:: Indent the first column by indent value.
+ # colwidth<Integer>:: Force the first column to colwidth spaces wide.
+ #
+ def print_table(array, options = {}) # rubocop:disable MethodLength
+ return if array.empty?
+
+ formats = []
+ indent = options[:indent].to_i
+ colwidth = options[:colwidth]
+ options[:truncate] = terminal_width if options[:truncate] == true
+
+ formats << "%-#{colwidth + 2}s".dup if colwidth
+ start = colwidth ? 1 : 0
+
+ colcount = array.max { |a, b| a.size <=> b.size }.size
+
+ maximas = []
+
+ start.upto(colcount - 1) do |index|
+ maxima = array.map { |row| row[index] ? row[index].to_s.size : 0 }.max
+ maximas << maxima
+ formats << if index == colcount - 1
+ # Don't output 2 trailing spaces when printing the last column
+ "%-s".dup
+ else
+ "%-#{maxima + 2}s".dup
+ end
+ end
+
+ formats[0] = formats[0].insert(0, " " * indent)
+ formats << "%s"
+
+ array.each do |row|
+ sentence = "".dup
+
+ row.each_with_index do |column, index|
+ maxima = maximas[index]
+
+ f = if column.is_a?(Numeric)
+ if index == row.size - 1
+ # Don't output 2 trailing spaces when printing the last column
+ "%#{maxima}s"
+ else
+ "%#{maxima}s "
+ end
+ else
+ formats[index]
+ end
+ sentence << f % column.to_s
+ end
+
+ sentence = truncate(sentence, options[:truncate]) if options[:truncate]
+ stdout.puts sentence
+ end
+ end
+
+ # Prints a long string, word-wrapping the text to the current width of the
+ # terminal display. Ideal for printing heredocs.
+ #
+ # ==== Parameters
+ # String
+ #
+ # ==== Options
+ # indent<Integer>:: Indent each line of the printed paragraph by indent value.
+ #
+ def print_wrapped(message, options = {})
+ indent = options[:indent] || 0
+ width = terminal_width - indent
+ paras = message.split("\n\n")
+
+ paras.map! do |unwrapped|
+ unwrapped.strip.tr("\n", " ").squeeze(" ").gsub(/.{1,#{width}}(?:\s|\Z)/) { ($& + 5.chr).gsub(/\n\005/, "\n").gsub(/\005/, "\n") }
+ end
+
+ paras.each do |para|
+ para.split("\n").each do |line|
+ stdout.puts line.insert(0, " " * indent)
+ end
+ stdout.puts unless para == paras.last
+ end
+ end
+
+ # Deals with file collision and returns true if the file should be
+ # overwritten and false otherwise. If a block is given, it uses the block
+ # response as the content for the diff.
+ #
+ # ==== Parameters
+ # destination<String>:: the destination file to solve conflicts
+ # block<Proc>:: an optional block that returns the value to be used in diff
+ #
+ def file_collision(destination)
+ return true if @always_force
+ options = block_given? ? "[Ynaqdh]" : "[Ynaqh]"
+
+ loop do
+ answer = ask(
+ %[Overwrite #{destination}? (enter "h" for help) #{options}],
+ :add_to_history => false
+ )
+
+ case answer
+ when nil
+ say ""
+ return true
+ when is?(:yes), is?(:force), ""
+ return true
+ when is?(:no), is?(:skip)
+ return false
+ when is?(:always)
+ return @always_force = true
+ when is?(:quit)
+ say "Aborting..."
+ raise SystemExit
+ when is?(:diff)
+ show_diff(destination, yield) if block_given?
+ say "Retrying..."
+ else
+ say file_collision_help
+ end
+ end
+ end
+
+ # This code was copied from Rake, available under MIT-LICENSE
+ # Copyright (c) 2003, 2004 Jim Weirich
+ def terminal_width
+ result = if ENV["THOR_COLUMNS"]
+ ENV["THOR_COLUMNS"].to_i
+ else
+ unix? ? dynamic_width : 80
+ end
+ result < 10 ? 80 : result
+ rescue
+ 80
+ end
+
+ # Called if something goes wrong during the execution. This is used by Bundler::Thor
+ # internally and should not be used inside your scripts. If something went
+ # wrong, you can always raise an exception. If you raise a Bundler::Thor::Error, it
+ # will be rescued and wrapped in the method below.
+ #
+ def error(statement)
+ stderr.puts statement
+ end
+
+ # Apply color to the given string with optional bold. Disabled in the
+ # Bundler::Thor::Shell::Basic class.
+ #
+ def set_color(string, *) #:nodoc:
+ string
+ end
+
+ protected
+
+ def prepare_message(message, *color)
+ spaces = " " * padding
+ spaces + set_color(message.to_s, *color)
+ end
+
+ def can_display_colors?
+ false
+ end
+
+ def lookup_color(color)
+ return color unless color.is_a?(Symbol)
+ self.class.const_get(color.to_s.upcase)
+ end
+
+ def stdout
+ $stdout
+ end
+
+ def stderr
+ $stderr
+ end
+
+ def is?(value) #:nodoc:
+ value = value.to_s
+
+ if value.size == 1
+ /\A#{value}\z/i
+ else
+ /\A(#{value}|#{value[0, 1]})\z/i
+ end
+ end
+
+ def file_collision_help #:nodoc:
+ <<-HELP
+ Y - yes, overwrite
+ n - no, do not overwrite
+ a - all, overwrite this and all others
+ q - quit, abort
+ d - diff, show the differences between the old and the new
+ h - help, show this help
+ HELP
+ end
+
+ def show_diff(destination, content) #:nodoc:
+ diff_cmd = ENV["THOR_DIFF"] || ENV["RAILS_DIFF"] || "diff -u"
+
+ require "tempfile"
+ Tempfile.open(File.basename(destination), File.dirname(destination)) do |temp|
+ temp.write content
+ temp.rewind
+ system %(#{diff_cmd} "#{destination}" "#{temp.path}")
+ end
+ end
+
+ def quiet? #:nodoc:
+ mute? || (base && base.options[:quiet])
+ end
+
+ # Calculate the dynamic width of the terminal
+ def dynamic_width
+ @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput)
+ end
+
+ def dynamic_width_stty
+ `stty size 2>/dev/null`.split[1].to_i
+ end
+
+ def dynamic_width_tput
+ `tput cols 2>/dev/null`.to_i
+ end
+
+ def unix?
+ RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i
+ end
+
+ def truncate(string, width)
+ as_unicode do
+ chars = string.chars.to_a
+ if chars.length <= width
+ chars.join
+ else
+ chars[0, width - 3].join + "..."
+ end
+ end
+ end
+
+ if "".respond_to?(:encode)
+ def as_unicode
+ yield
+ end
+ else
+ def as_unicode
+ old = $KCODE
+ $KCODE = "U"
+ yield
+ ensure
+ $KCODE = old
+ end
+ end
+
+ def ask_simply(statement, color, options)
+ default = options[:default]
+ message = [statement, ("(#{default})" if default), nil].uniq.join(" ")
+ message = prepare_message(message, *color)
+ result = Bundler::Thor::LineEditor.readline(message, options)
+
+ return unless result
+
+ result = result.strip
+
+ if default && result == ""
+ default
+ else
+ result
+ end
+ end
+
+ def ask_filtered(statement, color, options)
+ answer_set = options[:limited_to]
+ correct_answer = nil
+ until correct_answer
+ answers = answer_set.join(", ")
+ answer = ask_simply("#{statement} [#{answers}]", color, options)
+ correct_answer = answer_set.include?(answer) ? answer : nil
+ say("Your response must be one of: [#{answers}]. Please try again.") unless correct_answer
+ end
+ correct_answer
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/shell/color.rb b/lib/bundler/vendor/thor/lib/thor/shell/color.rb
new file mode 100644
index 0000000000..da289cb50c
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/shell/color.rb
@@ -0,0 +1,149 @@
+require "bundler/vendor/thor/lib/thor/shell/basic"
+
+class Bundler::Thor
+ module Shell
+ # Inherit from Bundler::Thor::Shell::Basic and add set_color behavior. Check
+ # Bundler::Thor::Shell::Basic to see all available methods.
+ #
+ class Color < Basic
+ # Embed in a String to clear all previous ANSI sequences.
+ CLEAR = "\e[0m"
+ # The start of an ANSI bold sequence.
+ BOLD = "\e[1m"
+
+ # Set the terminal's foreground ANSI color to black.
+ BLACK = "\e[30m"
+ # Set the terminal's foreground ANSI color to red.
+ RED = "\e[31m"
+ # Set the terminal's foreground ANSI color to green.
+ GREEN = "\e[32m"
+ # Set the terminal's foreground ANSI color to yellow.
+ YELLOW = "\e[33m"
+ # Set the terminal's foreground ANSI color to blue.
+ BLUE = "\e[34m"
+ # Set the terminal's foreground ANSI color to magenta.
+ MAGENTA = "\e[35m"
+ # Set the terminal's foreground ANSI color to cyan.
+ CYAN = "\e[36m"
+ # Set the terminal's foreground ANSI color to white.
+ WHITE = "\e[37m"
+
+ # Set the terminal's background ANSI color to black.
+ ON_BLACK = "\e[40m"
+ # Set the terminal's background ANSI color to red.
+ ON_RED = "\e[41m"
+ # Set the terminal's background ANSI color to green.
+ ON_GREEN = "\e[42m"
+ # Set the terminal's background ANSI color to yellow.
+ ON_YELLOW = "\e[43m"
+ # Set the terminal's background ANSI color to blue.
+ ON_BLUE = "\e[44m"
+ # Set the terminal's background ANSI color to magenta.
+ ON_MAGENTA = "\e[45m"
+ # Set the terminal's background ANSI color to cyan.
+ ON_CYAN = "\e[46m"
+ # Set the terminal's background ANSI color to white.
+ ON_WHITE = "\e[47m"
+
+ # Set color by using a string or one of the defined constants. If a third
+ # option is set to true, it also adds bold to the string. This is based
+ # on Highline implementation and it automatically appends CLEAR to the end
+ # of the returned String.
+ #
+ # Pass foreground, background and bold options to this method as
+ # symbols.
+ #
+ # Example:
+ #
+ # set_color "Hi!", :red, :on_white, :bold
+ #
+ # The available colors are:
+ #
+ # :bold
+ # :black
+ # :red
+ # :green
+ # :yellow
+ # :blue
+ # :magenta
+ # :cyan
+ # :white
+ # :on_black
+ # :on_red
+ # :on_green
+ # :on_yellow
+ # :on_blue
+ # :on_magenta
+ # :on_cyan
+ # :on_white
+ def set_color(string, *colors)
+ if colors.compact.empty? || !can_display_colors?
+ string
+ elsif colors.all? { |color| color.is_a?(Symbol) || color.is_a?(String) }
+ ansi_colors = colors.map { |color| lookup_color(color) }
+ "#{ansi_colors.join}#{string}#{CLEAR}"
+ else
+ # The old API was `set_color(color, bold=boolean)`. We
+ # continue to support the old API because you should never
+ # break old APIs unnecessarily :P
+ foreground, bold = colors
+ foreground = self.class.const_get(foreground.to_s.upcase) if foreground.is_a?(Symbol)
+
+ bold = bold ? BOLD : ""
+ "#{bold}#{foreground}#{string}#{CLEAR}"
+ end
+ end
+
+ protected
+
+ def can_display_colors?
+ stdout.tty?
+ end
+
+ # Overwrite show_diff to show diff with colors if Diff::LCS is
+ # available.
+ #
+ def show_diff(destination, content) #:nodoc:
+ if diff_lcs_loaded? && ENV["THOR_DIFF"].nil? && ENV["RAILS_DIFF"].nil?
+ actual = File.binread(destination).to_s.split("\n")
+ content = content.to_s.split("\n")
+
+ Diff::LCS.sdiff(actual, content).each do |diff|
+ output_diff_line(diff)
+ end
+ else
+ super
+ end
+ end
+
+ def output_diff_line(diff) #:nodoc:
+ case diff.action
+ when "-"
+ say "- #{diff.old_element.chomp}", :red, true
+ when "+"
+ say "+ #{diff.new_element.chomp}", :green, true
+ when "!"
+ say "- #{diff.old_element.chomp}", :red, true
+ say "+ #{diff.new_element.chomp}", :green, true
+ else
+ say " #{diff.old_element.chomp}", nil, true
+ end
+ end
+
+ # Check if Diff::LCS is loaded. If it is, use it to create pretty output
+ # for diff.
+ #
+ def diff_lcs_loaded? #:nodoc:
+ return true if defined?(Diff::LCS)
+ return @diff_lcs_loaded unless @diff_lcs_loaded.nil?
+
+ @diff_lcs_loaded = begin
+ require "diff/lcs"
+ true
+ rescue LoadError
+ false
+ end
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/shell/html.rb b/lib/bundler/vendor/thor/lib/thor/shell/html.rb
new file mode 100644
index 0000000000..83d2054988
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/shell/html.rb
@@ -0,0 +1,126 @@
+require "bundler/vendor/thor/lib/thor/shell/basic"
+
+class Bundler::Thor
+ module Shell
+ # Inherit from Bundler::Thor::Shell::Basic and add set_color behavior. Check
+ # Bundler::Thor::Shell::Basic to see all available methods.
+ #
+ class HTML < Basic
+ # The start of an HTML bold sequence.
+ BOLD = "font-weight: bold"
+
+ # Set the terminal's foreground HTML color to black.
+ BLACK = "color: black"
+ # Set the terminal's foreground HTML color to red.
+ RED = "color: red"
+ # Set the terminal's foreground HTML color to green.
+ GREEN = "color: green"
+ # Set the terminal's foreground HTML color to yellow.
+ YELLOW = "color: yellow"
+ # Set the terminal's foreground HTML color to blue.
+ BLUE = "color: blue"
+ # Set the terminal's foreground HTML color to magenta.
+ MAGENTA = "color: magenta"
+ # Set the terminal's foreground HTML color to cyan.
+ CYAN = "color: cyan"
+ # Set the terminal's foreground HTML color to white.
+ WHITE = "color: white"
+
+ # Set the terminal's background HTML color to black.
+ ON_BLACK = "background-color: black"
+ # Set the terminal's background HTML color to red.
+ ON_RED = "background-color: red"
+ # Set the terminal's background HTML color to green.
+ ON_GREEN = "background-color: green"
+ # Set the terminal's background HTML color to yellow.
+ ON_YELLOW = "background-color: yellow"
+ # Set the terminal's background HTML color to blue.
+ ON_BLUE = "background-color: blue"
+ # Set the terminal's background HTML color to magenta.
+ ON_MAGENTA = "background-color: magenta"
+ # Set the terminal's background HTML color to cyan.
+ ON_CYAN = "background-color: cyan"
+ # Set the terminal's background HTML color to white.
+ ON_WHITE = "background-color: white"
+
+ # Set color by using a string or one of the defined constants. If a third
+ # option is set to true, it also adds bold to the string. This is based
+ # on Highline implementation and it automatically appends CLEAR to the end
+ # of the returned String.
+ #
+ def set_color(string, *colors)
+ if colors.all? { |color| color.is_a?(Symbol) || color.is_a?(String) }
+ html_colors = colors.map { |color| lookup_color(color) }
+ "<span style=\"#{html_colors.join('; ')};\">#{string}</span>"
+ else
+ color, bold = colors
+ html_color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol)
+ styles = [html_color]
+ styles << BOLD if bold
+ "<span style=\"#{styles.join('; ')};\">#{string}</span>"
+ end
+ end
+
+ # Ask something to the user and receives a response.
+ #
+ # ==== Example
+ # ask("What is your name?")
+ #
+ # TODO: Implement #ask for Bundler::Thor::Shell::HTML
+ def ask(statement, color = nil)
+ raise NotImplementedError, "Implement #ask for Bundler::Thor::Shell::HTML"
+ end
+
+ protected
+
+ def can_display_colors?
+ true
+ end
+
+ # Overwrite show_diff to show diff with colors if Diff::LCS is
+ # available.
+ #
+ def show_diff(destination, content) #:nodoc:
+ if diff_lcs_loaded? && ENV["THOR_DIFF"].nil? && ENV["RAILS_DIFF"].nil?
+ actual = File.binread(destination).to_s.split("\n")
+ content = content.to_s.split("\n")
+
+ Diff::LCS.sdiff(actual, content).each do |diff|
+ output_diff_line(diff)
+ end
+ else
+ super
+ end
+ end
+
+ def output_diff_line(diff) #:nodoc:
+ case diff.action
+ when "-"
+ say "- #{diff.old_element.chomp}", :red, true
+ when "+"
+ say "+ #{diff.new_element.chomp}", :green, true
+ when "!"
+ say "- #{diff.old_element.chomp}", :red, true
+ say "+ #{diff.new_element.chomp}", :green, true
+ else
+ say " #{diff.old_element.chomp}", nil, true
+ end
+ end
+
+ # Check if Diff::LCS is loaded. If it is, use it to create pretty output
+ # for diff.
+ #
+ def diff_lcs_loaded? #:nodoc:
+ return true if defined?(Diff::LCS)
+ return @diff_lcs_loaded unless @diff_lcs_loaded.nil?
+
+ @diff_lcs_loaded = begin
+ require "diff/lcs"
+ true
+ rescue LoadError
+ false
+ end
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/util.rb b/lib/bundler/vendor/thor/lib/thor/util.rb
new file mode 100644
index 0000000000..5d03177a28
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/util.rb
@@ -0,0 +1,268 @@
+require "rbconfig"
+
+class Bundler::Thor
+ module Sandbox #:nodoc:
+ end
+
+ # This module holds several utilities:
+ #
+ # 1) Methods to convert thor namespaces to constants and vice-versa.
+ #
+ # Bundler::Thor::Util.namespace_from_thor_class(Foo::Bar::Baz) #=> "foo:bar:baz"
+ #
+ # 2) Loading thor files and sandboxing:
+ #
+ # Bundler::Thor::Util.load_thorfile("~/.thor/foo")
+ #
+ module Util
+ class << self
+ # Receives a namespace and search for it in the Bundler::Thor::Base subclasses.
+ #
+ # ==== Parameters
+ # namespace<String>:: The namespace to search for.
+ #
+ def find_by_namespace(namespace)
+ namespace = "default#{namespace}" if namespace.empty? || namespace =~ /^:/
+ Bundler::Thor::Base.subclasses.detect { |klass| klass.namespace == namespace }
+ end
+
+ # Receives a constant and converts it to a Bundler::Thor namespace. Since Bundler::Thor
+ # commands can be added to a sandbox, this method is also responsable for
+ # removing the sandbox namespace.
+ #
+ # This method should not be used in general because it's used to deal with
+ # older versions of Bundler::Thor. On current versions, if you need to get the
+ # namespace from a class, just call namespace on it.
+ #
+ # ==== Parameters
+ # constant<Object>:: The constant to be converted to the thor path.
+ #
+ # ==== Returns
+ # String:: If we receive Foo::Bar::Baz it returns "foo:bar:baz"
+ #
+ def namespace_from_thor_class(constant)
+ constant = constant.to_s.gsub(/^Bundler::Thor::Sandbox::/, "")
+ constant = snake_case(constant).squeeze(":")
+ constant
+ end
+
+ # Given the contents, evaluate it inside the sandbox and returns the
+ # namespaces defined in the sandbox.
+ #
+ # ==== Parameters
+ # contents<String>
+ #
+ # ==== Returns
+ # Array[Object]
+ #
+ def namespaces_in_content(contents, file = __FILE__)
+ old_constants = Bundler::Thor::Base.subclasses.dup
+ Bundler::Thor::Base.subclasses.clear
+
+ load_thorfile(file, contents)
+
+ new_constants = Bundler::Thor::Base.subclasses.dup
+ Bundler::Thor::Base.subclasses.replace(old_constants)
+
+ new_constants.map!(&:namespace)
+ new_constants.compact!
+ new_constants
+ end
+
+ # Returns the thor classes declared inside the given class.
+ #
+ def thor_classes_in(klass)
+ stringfied_constants = klass.constants.map(&:to_s)
+ Bundler::Thor::Base.subclasses.select do |subclass|
+ next unless subclass.name
+ stringfied_constants.include?(subclass.name.gsub("#{klass.name}::", ""))
+ end
+ end
+
+ # Receives a string and convert it to snake case. SnakeCase returns snake_case.
+ #
+ # ==== Parameters
+ # String
+ #
+ # ==== Returns
+ # String
+ #
+ def snake_case(str)
+ return str.downcase if str =~ /^[A-Z_]+$/
+ str.gsub(/\B[A-Z]/, '_\&').squeeze("_") =~ /_*(.*)/
+ $+.downcase
+ end
+
+ # Receives a string and convert it to camel case. camel_case returns CamelCase.
+ #
+ # ==== Parameters
+ # String
+ #
+ # ==== Returns
+ # String
+ #
+ def camel_case(str)
+ return str if str !~ /_/ && str =~ /[A-Z]+.*/
+ str.split("_").map(&:capitalize).join
+ end
+
+ # Receives a namespace and tries to retrieve a Bundler::Thor or Bundler::Thor::Group class
+ # from it. It first searches for a class using the all the given namespace,
+ # if it's not found, removes the highest entry and searches for the class
+ # again. If found, returns the highest entry as the class name.
+ #
+ # ==== Examples
+ #
+ # class Foo::Bar < Bundler::Thor
+ # def baz
+ # end
+ # end
+ #
+ # class Baz::Foo < Bundler::Thor::Group
+ # end
+ #
+ # Bundler::Thor::Util.namespace_to_thor_class("foo:bar") #=> Foo::Bar, nil # will invoke default command
+ # Bundler::Thor::Util.namespace_to_thor_class("baz:foo") #=> Baz::Foo, nil
+ # Bundler::Thor::Util.namespace_to_thor_class("foo:bar:baz") #=> Foo::Bar, "baz"
+ #
+ # ==== Parameters
+ # namespace<String>
+ #
+ def find_class_and_command_by_namespace(namespace, fallback = true)
+ if namespace.include?(":") # look for a namespaced command
+ pieces = namespace.split(":")
+ command = pieces.pop
+ klass = Bundler::Thor::Util.find_by_namespace(pieces.join(":"))
+ end
+ unless klass # look for a Bundler::Thor::Group with the right name
+ klass = Bundler::Thor::Util.find_by_namespace(namespace)
+ command = nil
+ end
+ if !klass && fallback # try a command in the default namespace
+ command = namespace
+ klass = Bundler::Thor::Util.find_by_namespace("")
+ end
+ [klass, command]
+ end
+ alias_method :find_class_and_task_by_namespace, :find_class_and_command_by_namespace
+
+ # Receives a path and load the thor file in the path. The file is evaluated
+ # inside the sandbox to avoid namespacing conflicts.
+ #
+ def load_thorfile(path, content = nil, debug = false)
+ content ||= File.binread(path)
+
+ begin
+ Bundler::Thor::Sandbox.class_eval(content, path)
+ rescue StandardError => e
+ $stderr.puts("WARNING: unable to load thorfile #{path.inspect}: #{e.message}")
+ if debug
+ $stderr.puts(*e.backtrace)
+ else
+ $stderr.puts(e.backtrace.first)
+ end
+ end
+ end
+
+ def user_home
+ @@user_home ||= if ENV["HOME"]
+ ENV["HOME"]
+ elsif ENV["USERPROFILE"]
+ ENV["USERPROFILE"]
+ elsif ENV["HOMEDRIVE"] && ENV["HOMEPATH"]
+ File.join(ENV["HOMEDRIVE"], ENV["HOMEPATH"])
+ elsif ENV["APPDATA"]
+ ENV["APPDATA"]
+ else
+ begin
+ File.expand_path("~")
+ rescue
+ if File::ALT_SEPARATOR
+ "C:/"
+ else
+ "/"
+ end
+ end
+ end
+ end
+
+ # Returns the root where thor files are located, depending on the OS.
+ #
+ def thor_root
+ File.join(user_home, ".thor").tr('\\', "/")
+ end
+
+ # Returns the files in the thor root. On Windows thor_root will be something
+ # like this:
+ #
+ # C:\Documents and Settings\james\.thor
+ #
+ # If we don't #gsub the \ character, Dir.glob will fail.
+ #
+ def thor_root_glob
+ files = Dir["#{escape_globs(thor_root)}/*"]
+
+ files.map! do |file|
+ File.directory?(file) ? File.join(file, "main.thor") : file
+ end
+ end
+
+ # Where to look for Bundler::Thor files.
+ #
+ def globs_for(path)
+ path = escape_globs(path)
+ ["#{path}/Bundler::Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks/*.thor"]
+ end
+
+ # Return the path to the ruby interpreter taking into account multiple
+ # installations and windows extensions.
+ #
+ def ruby_command
+ @ruby_command ||= begin
+ ruby_name = RbConfig::CONFIG["ruby_install_name"]
+ ruby = File.join(RbConfig::CONFIG["bindir"], ruby_name)
+ ruby << RbConfig::CONFIG["EXEEXT"]
+
+ # avoid using different name than ruby (on platforms supporting links)
+ if ruby_name != "ruby" && File.respond_to?(:readlink)
+ begin
+ alternate_ruby = File.join(RbConfig::CONFIG["bindir"], "ruby")
+ alternate_ruby << RbConfig::CONFIG["EXEEXT"]
+
+ # ruby is a symlink
+ if File.symlink? alternate_ruby
+ linked_ruby = File.readlink alternate_ruby
+
+ # symlink points to 'ruby_install_name'
+ ruby = alternate_ruby if linked_ruby == ruby_name || linked_ruby == ruby
+ end
+ rescue NotImplementedError # rubocop:disable HandleExceptions
+ # just ignore on windows
+ end
+ end
+
+ # escape string in case path to ruby executable contain spaces.
+ ruby.sub!(/.*\s.*/m, '"\&"')
+ ruby
+ end
+ end
+
+ # Returns a string that has had any glob characters escaped.
+ # The glob characters are `* ? { } [ ]`.
+ #
+ # ==== Examples
+ #
+ # Bundler::Thor::Util.escape_globs('[apps]') # => '\[apps\]'
+ #
+ # ==== Parameters
+ # String
+ #
+ # ==== Returns
+ # String
+ #
+ def escape_globs(path)
+ path.to_s.gsub(/[*?{}\[\]]/, '\\\\\\&')
+ end
+ end
+ end
+end
diff --git a/lib/bundler/vendor/thor/lib/thor/version.rb b/lib/bundler/vendor/thor/lib/thor/version.rb
new file mode 100644
index 0000000000..df8f18821a
--- /dev/null
+++ b/lib/bundler/vendor/thor/lib/thor/version.rb
@@ -0,0 +1,3 @@
+class Bundler::Thor
+ VERSION = "0.20.0"
+end