SafeCatch provides a mechanism to safely deepen the stack, performing stack-unrolling similar to catch/throw, but using Fiber or Thread to avoid deepening the stack too quickly.
The API is the same as that of catch/throw: SafeCatch#safe_catch takes a “tag” to be rescued when some code deeper in the process raises it. If the catch block completes successfully, that value is returned. If the tag is “thrown” by safe_throw, the tag’s value is returned. Other exceptions propagate out as normal.
The implementation, however, uses fibers or threads along with raise/rescue to handle “deepening” the stack and unrolling it. On implementations where Fiber is available, it will be used. If Fiber is not available, Thread will be used. If neither of these classes are available, Proc will be used, effectively deepening the stack for each recursion as in normal catch/throw.
In order to avoid causing a new issue of creating too many fibers or threads, especially on implementations where fibers are actually backed by native threads, the “safe” recursion mechanism is only used every 20 recursions. Based on experiments with JRuby (which seems to suffer the most from excessively deep stacks), this appears to be a sufficient granularity to prevent stack overflow without spinning up excessive numbers of fibers or threads. This value can be adjusted with the BUNDLER_SAFE_RECURSE_EVERY env var; setting it to zero effectively disables safe recursion.
Some versions of the Bundler 1.1 RC series introduced corrupted lockfiles. There were two major problems:
multiple copies of the same GIT section appeared in the lockfile
when this happened, those sections got multiple copies of gems in those sections.
As a result, Bundler 1.1 contains code that fixes the earlier corruption. We will remove this fix-up code in Bundler 1.2.
We’re doing this because we might write tests that deal with other versions of bundler and we are unsure how to handle this better.
# File lib/bundler.rb, line 197 def app_cache root.join("vendor/cache") end
# File lib/bundler.rb, line 191 def app_config_path ENV['BUNDLE_APP_CONFIG'] ? Pathname.new(ENV['BUNDLE_APP_CONFIG']).expand_path(root) : root.join('.bundle') end
Returns absolute location of where binstubs are installed to.
# File lib/bundler.rb, line 102 def bin_path @bin_path ||= begin path = settings[:bin] || "bin" path = Pathname.new(path).expand_path(root).expand_path FileUtils.mkdir_p(path) path end end
Returns absolute path of where gems are installed on the filesystem.
# File lib/bundler.rb, line 97 def bundle_path @bundle_path ||= Pathname.new(settings.path).expand_path(root) end
# File lib/bundler.rb, line 183 def cache bundle_path.join("cache/bundler") end
# File lib/bundler.rb, line 237 def clean_exec(*args) with_clean_env { Kernel.exec(*args) } end
# File lib/bundler.rb, line 233 def clean_system(*args) with_clean_env { Kernel.system(*args) } end
# File lib/bundler.rb, line 352 def clear_gemspec_cache @gemspec_cache = {} end
# File lib/bundler.rb, line 88 def configure @configured ||= configure_gem_home_and_path end
Returns current version of Ruby
@return [CurrentRuby] Current version of Ruby
# File lib/bundler/current_ruby.rb, line 5 def self.current_ruby @current_ruby ||= CurrentRuby.new end
# File lib/bundler.rb, line 241 def default_gemfile SharedHelpers.default_gemfile end
# File lib/bundler.rb, line 245 def default_lockfile SharedHelpers.default_lockfile end
Returns an instance of Bundler::Definition for given Gemfile and lockfile
@param unlock [Hash, Boolean, nil] Gems that have been requested
to be updated or true if all gems should be updated
@return [Bundler::Definition]
# File lib/bundler.rb, line 147 def definition(unlock = nil) @definition = nil if unlock @definition ||= begin configure upgrade_lockfile Definition.build(default_gemfile, default_lockfile, unlock) end end
# File lib/bundler.rb, line 138 def environment Bundler::Environment.new(root, definition) end
# File lib/bundler.rb, line 356 def git_present? return @git_present if defined?(@git_present) @git_present = Bundler.which("git") || Bundler.which("git.exe") end
# File lib/bundler.rb, line 171 def home bundle_path.join("bundler") end
# File lib/bundler.rb, line 175 def install_path home.join("gems") end
# File lib/bundler.rb, line 134 def load @load ||= Runtime.new(root, definition) end
# File lib/bundler.rb, line 329 def load_gemspec(file) @gemspec_cache ||= {} key = File.expand_path(file) spec = ( @gemspec_cache[key] ||= load_gemspec_uncached(file) ) # Protect against caching side-effected gemspecs by returning a # new instance each time. spec.dup if spec end
# File lib/bundler.rb, line 338 def load_gemspec_uncached(file) path = Pathname.new(file) # Eval the gemspec from its parent directory, because some gemspecs # depend on "./" relative paths. SharedHelpers.chdir(path.dirname.to_s) do contents = path.read if contents[0..2] == "---" # YAML header eval_yaml_gemspec(path, contents) else eval_gemspec(path, contents) end end end
# File lib/bundler.rb, line 323 def load_marshal(data) Marshal.load(data) rescue => e raise MarshalError, "#{e.class}: #{e.message}" end
# File lib/bundler.rb, line 156 def locked_gems @locked_gems ||= begin lock = Bundler.read_file(Bundler.default_lockfile) LockfileParser.new(lock) end end
# File lib/bundler.rb, line 284 def mkdir_p(path) if requires_sudo? sudo "mkdir -p '#{path}'" unless File.exist?(path) else FileUtils.mkdir_p(path) end end
# File lib/bundler/gem_path_manipulation.rb, line 2 def self.preserve_gem_path original_gem_path = ENV["_ORIGINAL_GEM_PATH"] gem_path = ENV["GEM_PATH"] ENV["_ORIGINAL_GEM_PATH"] = gem_path if original_gem_path.nil? || original_gem_path == "" ENV["GEM_PATH"] = original_gem_path if gem_path.nil? || gem_path == "" end
# File lib/bundler.rb, line 319 def read_file(file) File.open(file, "rb") { |f| f.read } end
# File lib/bundler.rb, line 130 def require(*groups) setup(*groups).require(*groups) end
# File lib/bundler.rb, line 258 def requires_sudo? return @requires_sudo if defined?(@requires_sudo_ran) if settings.allow_sudo? sudo_present = which "sudo" end if sudo_present # the bundle path and subdirectories need to be writable for Rubygems # to be able to unpack and install gems without exploding path = bundle_path path = path.parent until path.exist? # bins are written to a different location on OS X bin_dir = Pathname.new(Bundler.system_bindir) bin_dir = bin_dir.parent until bin_dir.exist? # if any directory is not writable, we need sudo dirs = [path, bin_dir] | Dir[path.join('*').to_s] sudo_needed = dirs.find{|d| !File.writable?(d) } end @requires_sudo_ran = true @requires_sudo = settings.allow_sudo? && sudo_present && sudo_needed end
# File lib/bundler.rb, line 187 def root default_gemfile.dirname.expand_path end
# File lib/bundler.rb, line 163 def ruby_scope "#{Bundler.rubygems.ruby_engine}/#{Gem::ConfigMap[:ruby_version]}" end
# File lib/bundler.rb, line 361 def ruby_version @ruby_version ||= SystemRubyVersion.new end
# File lib/bundler.rb, line 205 def settings @settings ||= begin Settings.new(app_config_path) rescue GemfileNotFound Settings.new end end
# File lib/bundler.rb, line 111 def setup(*groups) # Just return if all groups are already loaded return @setup if defined?(@setup) definition.validate_ruby! if groups.empty? # Load all groups, but only once @setup = load.setup else @completed_groups ||= [] # Figure out which groups haven't been loaded yet unloaded = groups - @completed_groups # Record groups that are now loaded @completed_groups = groups unloaded.any? ? load.setup(*groups) : load end end
# File lib/bundler.rb, line 179 def specs_path bundle_path.join("specifications") end
# File lib/bundler.rb, line 303 def sudo(str) prompt = "\n\n" + Your user account isn't allowed to install to the system Rubygems. You can cancel this installation and run: bundle install --path vendor/bundle to install the gems into ./vendor/bundle/, or you can enter your password and install the bundled gems to Rubygems using sudo. Password:.gsub(/^ {6}/, '').strip + " " `sudo -p "#{prompt}" #{str}` end
# File lib/bundler.rb, line 249 def system_bindir # Gem.bindir doesn't always return the location that Rubygems will install # system binaries. If you put '-n foo' in your .gemrc, Rubygems will # install binstubs there instead. Unfortunately, Rubygems doesn't expose # that directory at all, so rather than parse .gemrc ourselves, we allow # the directory to be set as well, via `bundle config bindir foo`. Bundler.settings[:system_bindir] || Bundler.rubygems.gem_bindir end
# File lib/bundler.rb, line 201 def tmp user_bundle_path.join("tmp", Process.pid.to_s) end
# File lib/bundler.rb, line 167 def user_bundle_path Pathname.new(Bundler.rubygems.user_home).join(".bundler") end
# File lib/bundler.rb, line 292 def which(executable) if File.file?(executable) && File.executable?(executable) executable elsif ENV['PATH'] path = ENV['PATH'].split(File::PATH_SEPARATOR).find do |p| File.executable?(File.join(p, executable)) end path && File.expand_path(executable, path) end end
# File lib/bundler.rb, line 221 def with_clean_env with_original_env do ENV['MANPATH'] = ENV['BUNDLE_ORIG_MANPATH'] ENV.delete_if { |k,_| k[0,7] == 'BUNDLE_' } if ENV.has_key? 'RUBYOPT' ENV['RUBYOPT'] = ENV['RUBYOPT'].sub '-rbundler/setup', '' ENV['RUBYOPT'] = ENV['RUBYOPT'].sub "-I#{File.expand_path('..', __FILE__)}", '' end yield end end
# File lib/bundler/friendly_errors.rb, line 4 def self.with_friendly_errors yield rescue Bundler::BundlerError => e Bundler.ui.error e.message, :wrap => true Bundler.ui.trace e exit e.status_code rescue Thor::AmbiguousTaskError => e Bundler.ui.error e.message exit 15 rescue Thor::UndefinedTaskError => e Bundler.ui.error e.message exit 15 rescue Thor::Error => e Bundler.ui.error e.message exit 1 rescue LoadError => e raise e unless e.message =~ /cannot load such file -- openssl|openssl.so|libcrypto.so/ Bundler.ui.error "\nCould not load OpenSSL." Bundler.ui.warn You must recompile Ruby with OpenSSL support or change the sources in your \ Gemfile from 'https' to 'http'. Instructions for compiling with OpenSSL \ using RVM are available at rvm.io/packages/openssl., :wrap => true Bundler.ui.trace e exit 1 rescue Interrupt => e Bundler.ui.error "\nQuitting..." Bundler.ui.trace e exit 1 rescue SystemExit => e exit e.status rescue Exception => e Bundler.ui.error Unfortunately, a fatal error has occurred. Please see the Bundler \ troubleshooting documentation at http://bit.ly/bundler-issues. Thanks!, :wrap => true raise e end
Generated with the Darkfish Rdoc Generator 2.