class Isolate::Sandbox
An isolated environment.
Public Class Methods
Create a new Isolate::Sandbox
instance. See Isolate.now!
for the most common use of the API. You probably don’t want to use this constructor directly.
# File lib/isolate/sandbox.rb, line 33 def initialize options = {}, &block @enabled = false @entries = [] @environments = [] @files = [] @options = options path, name = options.values_at :path, :name raise ArgumentError, "can't specify both name and path!" if name && path options[:path] = File.expand_path("~/.gem/repos/#{name}") if name user = File.expand_path "~/.isolate/user.rb" load user if File.exist? user file, local = nil unless FalseClass === options[:file] file = options[:file] || Dir["{Isolate,config/isolate.rb}"].first local = "#{file}.local" if file end load file if file if block_given? files << (block.to_s[/ (\/.+):\d+/, 1] || "inline block") instance_eval(&block) end load local if local && File.exist?(local) end
Public Instance Methods
Activate this set of isolated entries, respecting an optional environment
. Points RubyGems to a separate repository, messes with paths, auto-installs gems (if necessary), activates everything, and removes any superfluous gem (again, if necessary). If environment
isn’t specified, ISOLATE_ENV
, RAILS_ENV
, and RACK_ENV
are checked before falling back to "development"
.
# File lib/isolate/sandbox.rb, line 73 def activate environment = nil enable unless enabled? env = (environment || Isolate.env).to_s install env if install? entries.each do |e| e.activate if e.matches? env end cleanup if cleanup? self end
# File lib/isolate/sandbox.rb, line 99 def cleanup? install? and @options.fetch(:cleanup, true) end
# File lib/isolate/sandbox.rb, line 103 def disable return self unless enabled? ENV.replace @old_env $LOAD_PATH.replace @old_load_path @enabled = false Isolate.refresh if block_given? then begin return yield ensure enable end end self end
# File lib/isolate/sandbox.rb, line 177 def enabled? @enabled end
Restricts gem
calls inside block
to a set of environments
.
# File lib/isolate/sandbox.rb, line 183 def environment *environments, &block old = @environments @environments = @environments.dup.concat environments.map { |e| e.to_s } instance_eval(&block) ensure @environments = old end
Express a gem dependency. Works pretty much like RubyGems’ gem
method, but respects environment
and doesn’t activate ‘til later.
# File lib/isolate/sandbox.rb, line 198 def gem name, *requirements entry = entries.find { |e| e.name == name } return entry.update(*requirements) if entry entries << entry = Entry.new(self, name, *requirements) entry end
# File lib/isolate/sandbox.rb, line 213 def install_missing environment installable = entries.select do |e| !e.specification && e.matches?(environment) end unless installable.empty? padding = Math.log10(installable.size).to_i + 1 format = "[%0#{padding}d/%s] Isolating %s (%s)." installable.each_with_index do |entry, i| log format % [i + 1, installable.size, entry.name, entry.requirement] entry.install end Gem::Specification.reset end end
# File lib/isolate/sandbox.rb, line 265 def multiruby? @options.fetch :multiruby, false end
# File lib/isolate/sandbox.rb, line 269 def options options = nil @options.merge! options if options @options end
# File lib/isolate/sandbox.rb, line 274 def path base = @options.fetch :path, DEFAULT_PATH if multiruby? then suffix = "#{Gem.ruby_engine}-#{RbConfig::CONFIG['ruby_version']}" base = File.join(base, suffix) unless base =~ /#{suffix}/ end File.expand_path base end
# File lib/isolate/sandbox.rb, line 231 def rebuild_extensions broken = entries.find_all { |e| e.specification && e.specification.missing_extensions? } unless broken.empty? padding = Math.log10(broken.size).to_i + 1 format = "[%0#{padding}d/%d] Building extensions for %s (ruby v%s)." broken.each_with_index do |e, i| spec = e.specification log format % [i + 1, broken.size, e.name, RUBY_VERSION] builder = Gem::Ext::Builder.new spec builder.build_extensions end Gem::Specification.reset end end
# File lib/isolate/sandbox.rb, line 285 def remove(*extra) unless extra.empty? padding = Math.log10(extra.size).to_i + 1 format = "[%0#{padding}d/%s] Nuking %s." extra.each_with_index do |e, i| log format % [i + 1, extra.size, e.full_name] Gem::DefaultUserInteraction.use_ui Gem::SilentUI.new do uninstaller = Gem::Uninstaller.new(e.name, :version => e.version, :ignore => true, :executables => true, :install_dir => e.base_dir) uninstaller.uninstall end end end end
# File lib/isolate/sandbox.rb, line 306 def system? @options.fetch :system, true end
# File lib/isolate/sandbox.rb, line 310 def verbose? @options.fetch :verbose, true end
Private Instance Methods
Returns a list of Gem::Specification instances that 1. exist in the isolated gem path, and 2. are allowed to be there. Used in cleanup. It’s only an external method ‘cause recursion is easier.
# File lib/isolate/sandbox.rb, line 321 def legitimize! deps = entries specs = [] deps.flatten.each do |dep| spec = case dep when Gem::Dependency then begin dep.to_spec rescue Gem::LoadError nil end when Isolate::Entry then dep.specification else raise "unknown dep: #{dep.inspect}" end if spec then specs.concat legitimize!(spec.runtime_dependencies) specs << spec end end specs.uniq end