class PhusionPassenger::AbstractInstaller

Abstract base class for text mode installers. Used by passenger-install-apache2-module and passenger-install-nginx-module.

Subclasses must at least implement the run_steps method which handles the installation itself.

Usage:

installer = ConcereteInstallerClass.new(options...)
installer.run

Constants

PASSENGER_WEBSITE
PHUSION_WEBSITE

Public Class Methods

new(options = {}) click to toggle source

Create an AbstractInstaller. All options will be stored as instance variables, for example:

installer = AbstractInstaller.new(:foo => "bar")
installer.instance_variable_get(:"@foo")   # => "bar"
# File lib/phusion_passenger/abstract_installer.rb, line 59
def initialize(options = {})
        @stdout = STDOUT
        @stderr = STDERR
        @auto   = !STDIN.tty?
        @colors = Utils::AnsiColors.new(options[:colorize] || :auto)
        options.each_pair do |key, value|
                instance_variable_set(:"@#{key}", value)
        end
end

Public Instance Methods

run() click to toggle source

Start the installation by calling the install! method.

# File lib/phusion_passenger/abstract_installer.rb, line 70
def run
        before_install
        run_steps
        return true
rescue Abort
        puts
        return false
rescue SignalException, SystemExit
        raise
rescue PlatformInfo::RuntimeError => e
        new_screen
        puts "<red>An error occurred</red>"
        puts
        puts e.message
        exit 1
rescue Exception => e
        show_support_options_for_installer_bug(e)
        exit 2
ensure
        after_install
end

Protected Instance Methods

after_install() click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 117
def after_install
        STDOUT.write(@colors.reset)
        STDOUT.flush
end
before_install() click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 109
def before_install
        if STDOUT.respond_to?(:set_encoding)
                STDOUT.set_encoding("UTF-8")
        end
        STDOUT.write(@colors.default_terminal_color)
        STDOUT.flush
end
check_dependencies(show_new_screen = true) click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 134
def check_dependencies(show_new_screen = true)
        new_screen if show_new_screen
        puts "<banner>Checking for required software...</banner>"
        puts

        PhusionPassenger.require_passenger_lib 'platform_info/depcheck'
        specs, ids = dependencies
        runner = PlatformInfo::Depcheck::ConsoleRunner.new

        specs.each do |spec|
                PlatformInfo::Depcheck.load(spec)
        end
        ids.each do |id|
                runner.add(id)
        end

        if runner.check_all
                return true
        else
                puts
                puts "<red>Some required software is not installed.</red>"
                puts "But don't worry, this installer will tell you how to install them.\n"
                puts "<b>Press Enter to continue, or Ctrl-C to abort.</b>"
                if PhusionPassenger.originally_packaged?
                        wait
                else
                        wait(10)
                end

                line
                puts
                puts "<banner>Installation instructions for required software</banner>"
                puts
                runner.missing_dependencies.each do |dep|
                        puts " * To install <yellow>#{dep.name}</yellow>:"
                        puts "   #{dep.install_instructions}"
                        puts
                end
                puts "If the aforementioned instructions didn't solve your problem, then please take"
                puts "a look at the Users Guide:"
                puts
                puts "  <yellow>#{users_guide_path}</yellow>"
                puts "  <yellow>#{users_guide_url}</yellow>"
                return false
        end
end
check_directory_accessible_by_web_server() click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 205
def check_directory_accessible_by_web_server
        return true if PhusionPassenger.natively_packaged?
        inaccessible_directories = []
        list_parent_directories(PhusionPassenger.build_system_dir).each do |path|
                if !world_executable?(path)
                        inaccessible_directories << path
                end
        end
        if !inaccessible_directories.empty?
                new_screen
                render_template 'installer_common/world_inaccessible_directories',
                        :directories => inaccessible_directories
                wait
        end
end
check_gem_install_permission_problems() click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 185
def check_gem_install_permission_problems
        return true if PhusionPassenger.natively_packaged?
        begin
                require 'rubygems'
        rescue LoadError
                return true
        end

        if Process.uid != 0 &&
           PhusionPassenger.build_system_dir =~ /^#{Regexp.escape home_dir}\// &&
           PhusionPassenger.build_system_dir =~ /^#{Regexp.escape Gem.dir}\// &&
           File.stat(PhusionPassenger.build_system_dir).uid == 0
                new_screen
                render_template 'installer_common/gem_install_permission_problems'
                return false
        else
                return true
        end
end
check_whether_os_is_broken() click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 181
def check_whether_os_is_broken
        # No known broken OSes at the moment.
end
check_whether_system_has_enough_ram(required = 1024) click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 221
def check_whether_system_has_enough_ram(required = 1024)
        begin
                meminfo = File.read("/proc/meminfo")
                if meminfo =~ /^MemTotal: *(\d+) kB$/
                        ram_mb = $1.to_i / 1024
                        if meminfo =~ /^SwapTotal: *(\d+) kB$/
                                swap_mb = $1.to_i / 1024
                        else
                                swap_mb = 0
                        end
                end
        rescue Errno::ENOENT, Errno::EACCES
                # Don't do anything on systems without memory information.
                ram_mb = nil
                swap_mb = nil
        end
        if ram_mb && swap_mb && ram_mb + swap_mb < required
                new_screen
                render_template 'installer_common/low_amount_of_memory_warning',
                        :required => required,
                        :current => ram_mb + swap_mb,
                        :ram => ram_mb,
                        :swap => swap_mb,
                        :doc_path => users_guide_path,
                        :doc_url => users_guide_url
                wait
        end
end
dependencies() click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 130
def dependencies
        return [[], []]
end
download(url, output, options = {}) click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 424
def download(url, output, options = {})
        options[:logger] ||= begin
                logger = Logger.new(STDOUT)
                logger.level = Logger::WARN
                logger.formatter = proc { |severity, datetime, progname, msg| "*** #{msg}\n" }
                logger
        end
        return PhusionPassenger::Utils::Download.download(url, output, options)
end
home_dir() click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 382
def home_dir
        Etc.getpwuid(Process.uid).dir
end
interactive?() click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 100
def interactive?
        return !@auto
end
line() click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 313
def line
        puts "--------------------------------------------"
end
list_parent_directories(dir) click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 434
def list_parent_directories(dir)
        dirs = []
        components = File.expand_path(dir).split(File::SEPARATOR)
        components.shift # Remove leading /
        components.size.times do |i|
                dirs << File::SEPARATOR + components[0 .. i].join(File::SEPARATOR)
        end
        return dirs.reverse
end
new_screen() click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 307
def new_screen
        puts
        line
        puts
end
non_interactive?() click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 104
def non_interactive?
        return !interactive?
end
print(text) click to toggle source
prompt(message, default_value = nil) { |result| ... } click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 317
def prompt(message, default_value = nil)
        done = false
        while !done
                print "#{message}: "

                if non_interactive? && default_value
                        puts default_value
                        return default_value
                end

                begin
                        result = STDIN.readline
                rescue EOFError
                        exit 2
                end
                result.strip!
                if result.empty?
                        if default_value
                                result = default_value
                                done = true
                        else
                                done = !block_given? || yield(result)
                        end
                else
                        done = !block_given? || yield(result)
                end
        end
        return result
rescue Interrupt
        raise Abort
end
prompt_confirmation(message) click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 349
def prompt_confirmation(message)
        result = prompt("#{message} [y/n]") do |value|
                if value.downcase == 'y' || value.downcase == 'n'
                        true
                else
                        puts_error "Invalid input '#{value}'; please enter either 'y' or 'n'."
                        false
                end
        end
        return result.downcase == 'y'
rescue Interrupt
        raise Abort
end
puts(text = nil) click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 288
def puts(text = nil)
        if text
                @stdout.puts(@colors.ansi_colorize(text.to_s))
        else
                @stdout.puts
        end
        @stdout.flush
end
puts_error(text) click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 297
def puts_error(text)
        @stderr.puts(@colors.ansi_colorize("<red>#{text}</red>"))
        @stderr.flush
end
rake(*args) click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 406
def rake(*args)
        PhusionPassenger.require_passenger_lib 'platform_info/ruby'
        if !PlatformInfo.rake_command
                puts_error 'Cannot find Rake.'
                raise Abort
        end
        sh("#{PlatformInfo.rake_command} #{args.join(' ')}")
end
rake!(*args) click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 415
def rake!(*args)
        PhusionPassenger.require_passenger_lib 'platform_info/ruby'
        if !PlatformInfo.rake_command
                puts_error 'Cannot find Rake.'
                raise Abort
        end
        sh!("#{PlatformInfo.rake_command} #{args.join(' ')}")
end
render_template(name, options = {}) click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 302
def render_template(name, options = {})
        options.merge!(:colors => @colors)
        puts ConsoleTextTemplate.new({ :file => name }, options).result
end
sh(*args) click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 387
def sh(*args)
        puts "# #{args.join(' ')}"
        result = system(*args)
        if result
                return true
        elsif $?.signaled? && $?.termsig == Signal.list["INT"]
                raise Interrupt
        else
                return false
        end
end
sh!(*args) click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 399
def sh!(*args)
        if !sh(*args)
                puts_error "*** Command failed: #{args.join(' ')}"
                raise CommandError
        end
end
show_support_options_for_installer_bug(e) click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 250
def show_support_options_for_installer_bug(e)
        # We do not use template rendering here. Since we've determined that there's
        # a bug, *anything* may be broken, so we use the safest codepath to ensure that
        # the user sees the proper messages.
        begin
                line
                @stderr.puts "*** EXCEPTION: #{e} (#{e.class})\n    " +
                        e.backtrace.join("\n    ")
                new_screen
                puts '<red>Oops, something went wrong :-(</red>'
                puts
                puts "We're sorry, but it looks like this installer ran into an unexpected problem.\n" +
                        "Please visit the following website for support. We'll do our best to help you.\n\n" +
                        "  <b>#{SUPPORT_URL}</b>\n\n" +
                        "When submitting a support inquiry, please copy and paste the entire installer\n" +
                        "output."
        rescue Exception => e2
                # Raise original exception so that it doesn't get lost.
                raise e
        end
end
use_stderr() { || ... } click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 273
def use_stderr
        old_stdout = @stdout
        begin
                @stdout = @stderr
                yield
        ensure
                @stdout = old_stdout
        end
end
users_guide_path() click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 122
def users_guide_path
        return PhusionPassenger.index_doc_path
end
users_guide_url() click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 126
def users_guide_url
        return INDEX_DOC_URL
end
wait(timeout = nil) click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 363
def wait(timeout = nil)
        if interactive?
                if timeout
                        require 'timeout' unless defined?(Timeout)
                        begin
                                Timeout.timeout(timeout) do
                                        STDIN.readline
                                end
                        rescue Timeout::Error
                                # Do nothing.
                        end
                else
                        STDIN.readline
                end
        end
rescue Interrupt
        raise Abort
end
world_executable?(dir) click to toggle source
# File lib/phusion_passenger/abstract_installer.rb, line 444
def world_executable?(dir)
        begin
                stat = File.stat(dir)
        rescue Errno::EACCESS
                return false
        end
        return stat.mode & 0000001 != 0
end