module PhusionPassenger::Config::InstallationUtils
def self.included(klass)
def self.included(klass) # When included into another class, make sure that Utils # methods are made private. public_instance_methods(false).each do |method_name| klass.send(:private, method_name) end end
def check_for_download_tool!
def check_for_download_tool! PlatformInfo::Depcheck.load('depcheck_specs/utilities') result = PlatformInfo::Depcheck.find('download-tool').check # Don't output anything if there is a download tool. # We want to be as quiet as possible. return if result && result[:found] colors = @colors || Utils::AnsiColors.new puts colors.ansi_colorize("<banner>Checking for basic prerequities...</banner>") puts runner = PlatformInfo::Depcheck::ConsoleRunner.new runner.add('download-tool') result = runner.check_all puts if !result puts "---------------------------------------" puts render_template 'installation_utils/download_tool_missing', :runner => runner abort end end
def create_user_support_binaries_dir!
def create_user_support_binaries_dir! dir = PhusionPassenger.user_support_binaries_dir begin mkdir_p_preserve_parent_owner(dir) rescue Errno::EACCES print_installation_error_header render_template 'installation_utils/cannot_create_user_support_binaries_dir', :dir => dir, :myself => myself abort rescue SystemCallError print_installation_error_header render_template 'installation_utils/unexpected_filesystem_problem', :dir => dir, :exception => result abort end end
def directory_writable?(path)
don't always work right with ACLs. Instead of we use 'real'
We can't use File.writable() and friends here because they
def directory_writable?(path) filename = "#{path}/.__test_#{object_id}__.txt" @logger.debug "Checking whether we can write to #{path}..." if @logger begin File.new(filename, "w").close @logger.debug "Yes" if @logger return true rescue Errno::EACCES @logger.debug "No" if @logger return false rescue SystemCallError => e @logger.warn "Unable to check whether we can write to #{path}: #{e}" if @logger return e ensure File.unlink(filename) rescue nil end end
def find_or_create_writable_support_binaries_dir!
def find_or_create_writable_support_binaries_dir! if File.exist?(PhusionPassenger.support_binaries_dir) result = directory_writable?(PhusionPassenger.support_binaries_dir) if result == true # return value can be a SystemCallError return PhusionPassenger.support_binaries_dir end if Process.euid == 0 if result == false print_installation_error_header render_template 'installation_utils/support_binaries_dir_not_writable_despite_running_as_root', :dir => PhusionPassenger.support_binaries_dir, :myself => myself else render_template 'installation_utils/unexpected_filesystem_problem', :dir => PhusionPassenger.support_binaries_dir, :exception => result end abort else return find_or_create_writable_user_support_binaries_dir! end else if Process.euid == 0 mkdir_p_preserve_parent_owner(PhusionPassenger.support_binaries_dir) return PhusionPassenger.support_binaries_dir else return find_or_create_writable_user_support_binaries_dir! end end end
def find_or_create_writable_user_support_binaries_dir!
def find_or_create_writable_user_support_binaries_dir! if !File.exist?(PhusionPassenger.user_support_binaries_dir) create_user_support_binaries_dir! end result = directory_writable?(PhusionPassenger.user_support_binaries_dir) case result when true return PhusionPassenger.user_support_binaries_dir when false print_installation_error_header render_template 'installation_utils/user_support_binaries_dir_not_writable' abort else print_installation_error_header render_template 'installation_utils/unexpected_filesystem_problem', :dir => PhusionPassenger.support_binaries_dir, :exception => result abort end end
def mkdir_p_preserve_parent_owner(path)
with sudo privileged, even though Phusion Passenger isn't installed as root,
parent directory's UID and GID. This way, running `passenger-config compile-agent`
When creating PhusionPassenger.support_binaries_dir, preserve the
def mkdir_p_preserve_parent_owner(path) Pathname.new(path).descend do |subpath| if !subpath.exist? stat = subpath.parent.stat Dir.mkdir(subpath.to_s) if Process.euid == 0 File.chown(stat.uid, stat.gid, subpath.to_s) end end end end
def myself
def myself return `whoami`.strip end
def print_installation_error_header
def print_installation_error_header if @colors red = @colors.red reset = @colors.reset else red = nil reset = nil end @logger.warn "------------------------------------------" if @logger puts "#{red}Cannot proceed with installation#{reset}" puts end
def rake
def rake return "env NOEXEC_DISABLE=1 #{PlatformInfo.rake_command}" end
def render_template(name, options = {})
def render_template(name, options = {}) options.merge!(:colors => @colors || PhusionPassenger::Utils::AnsiColors.new) puts ConsoleTextTemplate.new({ :file => "config/#{name}" }, options).result end
def run_rake_task!(target)
def run_rake_task!(target) total_lines = `#{rake} #{target} --dry-run STDERR_TO_STDOUT=1`.split("\n").size - 1 backlog = "" command = "#{rake} #{target} --trace STDERR_TO_STDOUT=1" IO.popen(command, "rb") do |io| progress = 1 while !io.eof? line = io.readline yield(progress, total_lines) if line =~ /^\*\* / backlog.replace("") progress += 1 else backlog << line end end end if $?.exitstatus != 0 stderr = @stderr || STDERR stderr.puts stderr.puts "*** ERROR: the following command failed:" stderr.puts(backlog) exit 1 end end