vagrant/test/acceptance/helpers/isolated_environment.rb

85 lines
2.7 KiB
Ruby
Raw Normal View History

require "fileutils"
require "log4r"
require "posix-spawn"
require File.expand_path("../tempdir", __FILE__)
module Acceptance
# This class manages an isolated environment for Vagrant to
# run in. It creates a temporary directory to act as the
# working directory as well as sets a custom home directory.
class IsolatedEnvironment
include POSIX::Spawn
attr_reader :homedir
attr_reader :workdir
# Initializes an isolated environment. You can pass in some
# options here to configure runing custom applications in place
# of others as well as specifying environmental variables.
#
# @param [Hash] apps A mapping of application name (such as "vagrant")
# to an alternate full path to the binary to run.
# @param [Hash] env Additional environmental variables to inject
# into the execution environments.
def initialize(apps=nil, env=nil)
@logger = Log4r::Logger.new("acceptance::isolated_environment")
@apps = apps || {}
@env = env || {}
# Create a temporary directory for our work
@tempdir = Tempdir.new("vagrant")
@logger.info("Initialize isolated environment: #{@tempdir.path}")
# Setup the home and working directories
@homedir = File.join(@tempdir.path, "home")
@workdir = File.join(@tempdir.path, "work")
FileUtils.mkdir(@homedir)
FileUtils.mkdir(@workdir)
@env["HOME"] = @homedir
end
# Executes a command in the context of this isolated environment.
# Any command executed will therefore see our temporary directory
# as the home directory.
def execute(command, *argN)
command = @apps[command] if @apps.has_key?(command)
# Execute in a separate process, wait for it to complete, and
# return the IO streams.
@logger.info("Executing: #{command} #{argN.inspect}")
pid, stdin, stdout, stderr = popen4(@env, command, *argN, :chdir => @tempdir.path)
_pid, status = Process.waitpid2(pid)
@logger.info("Exit status: #{status.exitstatus}")
return ExecuteProcess.new(status.exitstatus, stdout, stderr)
end
# Closes the environment, cleans up the temporary directories, etc.
def close
# Delete the temporary directory
FileUtils.rm_rf(@tempdir.path)
end
end
# This class represents a process which has run via the IsolatedEnvironment.
# This is a readonly structure that can be used to inspect the exit status,
# stdout, stderr, etc. from the process which ran.
class ExecuteProcess
attr_reader :exit_status
attr_reader :stdout
attr_reader :stderr
def initialize(exit_status, stdout, stderr)
@exit_status = exit_status
@stdout = stdout
@stderr = stderr
end
end
end