class PhusionPassenger::Standalone::RuntimeInstaller

Installs the Phusion Passenger Standalone runtime by downloading and compiling Nginx, compiling the Phusion Passenger support binaries, and storing the results in the designated directories. This installer is entirely non-interactive.

The following option must be given:

If you want RuntimeInstaller to compile and install Nginx, then you must specify these options:

If you want RuntimeInstaller to compile and install the Phusion Passenger support files, then you must specify these:

Other optional options:

Please note that RuntimeInstaller will try to avoid compiling/installing things that don't need to be compiled/installed. This is done by checking whether some key files exist, and concluding that something doesn't need to be compiled/installed if they do. This quick check is of course not perfect; if you want to force a recompilation/reinstall then you should remove nginx_dir and support_dir before starting this installer.

Protected Instance Methods

after_install() click to toggle source
# File lib/phusion_passenger/standalone/runtime_installer.rb, line 172
def after_install
        super
        FileUtils.remove_entry_secure(@working_dir) if @working_dir
        @plugin.call_hook(:runtime_installer_cleanup) if @plugin
end
before_install() click to toggle source
# File lib/phusion_passenger/standalone/runtime_installer.rb, line 164
def before_install
        super
        @plugin.call_hook(:runtime_installer_start, self) if @plugin
        @working_dir = Dir.mktmpdir("passenger.")
        @download_binaries = true if !defined?(@download_binaries)
        @binaries_url_root ||= STANDALONE_BINARIES_URL_ROOT
end
dependencies() click to toggle source
# File lib/phusion_passenger/standalone/runtime_installer.rb, line 78
def dependencies
        result = [
                Dependencies::GCC,
                Dependencies::GnuMake,
                Dependencies::DownloadTool,
                Dependencies::Ruby_DevHeaders,
                Dependencies::Ruby_OpenSSL,
                Dependencies::RubyGems,
                Dependencies::Rake,
                Dependencies::Rack,
                Dependencies::Curl_Dev,
                Dependencies::OpenSSL_Dev,
                Dependencies::Zlib_Dev,
                Dependencies::Daemon_Controller,
        ]
        if Dependencies.fastthread_required?
                result << Dependencies::FastThread
        end
        if Dependencies.mizuho_required?
                result << Dependencies::Mizuho
        end
        return result
end
install!() click to toggle source
# File lib/phusion_passenger/standalone/runtime_installer.rb, line 106
def install!
        if @support_dir && @nginx_dir
                show_welcome_screen
        end
        check_dependencies(false) || exit(1)
        puts
        if passenger_support_files_need_to_be_installed?
                check_whether_we_can_write_to(@support_dir) || exit(1)
        end
        if nginx_needs_to_be_installed?
                check_whether_we_can_write_to(@nginx_dir) || exit(1)
        end
        
        if passenger_support_files_need_to_be_installed? && should_download_binaries?
                download_and_extract_passenger_binaries(@support_dir) do |progress, total|
                        show_progress(progress, total, 1, 1, "Extracting Passenger binaries...")
                end
                puts
                puts
        end
        if nginx_needs_to_be_installed? && should_download_binaries?
                download_and_extract_nginx_binaries(@nginx_dir) do |progress, total|
                        show_progress(progress, total, 1, 1, "Extracting Nginx binaries...")
                end
                puts
                puts
        end
        
        if nginx_needs_to_be_installed?
                nginx_source_dir = download_and_extract_nginx_sources do |progress, total|
                        show_progress(progress, total, 1, 7, "Extracting...")
                end
                if nginx_source_dir.nil?
                        puts
                        show_possible_solutions_for_download_and_extraction_problems
                        exit(1)
                end
        end
        if passenger_support_files_need_to_be_installed?
                install_passenger_support_files do |progress, total, phase, status_text|
                        if phase == 1
                                show_progress(progress, total, 2, 7, status_text)
                        else
                                show_progress(progress, total, 3..5, 7, status_text)
                        end
                end
        end
        if nginx_needs_to_be_installed?
                install_nginx_from_source(nginx_source_dir) do |progress, total, status_text|
                        show_progress(progress, total, 6..7, 7, status_text)
                end
        end
        
        puts
        color_puts "<green><b>All done!</b></green>"
        puts
end
users_guide() click to toggle source
# File lib/phusion_passenger/standalone/runtime_installer.rb, line 102
def users_guide
        return "#{DOCDIR}/Users guide Standalone.html"
end

Private Instance Methods

begin_progress_bar() click to toggle source
# File lib/phusion_passenger/standalone/runtime_installer.rb, line 237
def begin_progress_bar
        if !@begun
                @begun = true
                color_puts "<banner>Installing Phusion Passenger Standalone...</banner>"
        end
end
check_whether_we_can_write_to(dir) click to toggle source
# File lib/phusion_passenger/standalone/runtime_installer.rb, line 198
def check_whether_we_can_write_to(dir)
        FileUtils.mkdir_p(dir)
        File.new("#{dir}/__test__.txt", "w").close
        return true
rescue
        new_screen
        if Process.uid == 0
                render_template 'standalone/cannot_write_to_dir', :dir => dir
        else
                render_template 'standalone/run_installer_as_root', :dir => dir
        end
        return false
ensure
        File.unlink("#{dir}/__test__.txt") rescue nil
end
copy_files(files, target) { |i| ... } click to toggle source
# File lib/phusion_passenger/standalone/runtime_installer.rb, line 303
def copy_files(files, target)
        FileUtils.mkdir_p(target)
        files.each_with_index do |filename, i|
                next if File.directory?(filename)
                dir = "#{target}/#{File.dirname(filename)}"
                if !File.directory?(dir)
                        FileUtils.mkdir_p(dir)
                end
                FileUtils.install(filename, "#{target}/#{filename}", :mode => File.stat(filename).mode)
                yield(i + 1, files.size)
        end
end
download_and_extract_nginx_binaries(target, &block) click to toggle source
# File lib/phusion_passenger/standalone/runtime_installer.rb, line 363
def download_and_extract_nginx_binaries(target, &block)
        color_puts "<banner>Downloading Nginx binaries for your platform, if available...</banner>"
        basename = "nginx-#{@version}.tar.gz"
        url      = "#{@binaries_url_root}/#{runtime_version_string}/#{basename}"
        tarball  = "#{@working_dir}/#{basename}"
        if !download(url, tarball)
                color_puts "<b>Looks like it's not. But don't worry, the " +
                        "necessary binaries will be compiled from source instead.</b>"
                return nil
        end

        FileUtils.mkdir_p(target)
        Dir.chdir(target) do
                return extract_tarball(tarball, &block)
        end
rescue Interrupt
        exit 2
end
download_and_extract_nginx_sources(&block) click to toggle source
# File lib/phusion_passenger/standalone/runtime_installer.rb, line 382
def download_and_extract_nginx_sources(&block)
        if @tarball
                tarball  = @tarball
        else
                color_puts "<banner>Downloading Nginx...</banner>"
                basename = "nginx-#{@version}.tar.gz"
                tarball  = "#{@working_dir}/#{basename}"
                if !download("http://nginx.org/download/#{basename}", tarball)
                        return nil
                end
        end
        nginx_sources_name = "nginx-#{@version}"
        
        Dir.chdir(@working_dir) do
                begin_progress_bar
                if extract_tarball(tarball, &block)
                        return "#{@working_dir}/#{nginx_sources_name}"
                else
                        return nil
                end
        end
rescue Interrupt
        exit 2
end
download_and_extract_passenger_binaries(target, &block) click to toggle source
# File lib/phusion_passenger/standalone/runtime_installer.rb, line 345
def download_and_extract_passenger_binaries(target, &block)
        color_puts "<banner>Downloading Passenger binaries for your platform, if available...</banner>"
        url     = "#{@binaries_url_root}/#{runtime_version_string}/support.tar.gz"
        tarball = "#{@working_dir}/support.tar.gz"
        if !download(url, tarball)
                color_puts "<b>Looks like it's not. But don't worry, the " +
                        "necessary binaries will be compiled from source instead.</b>"
                return nil
        end
        
        FileUtils.mkdir_p(target)
        Dir.chdir(target) do
                return extract_tarball(tarball, &block)
        end
rescue Interrupt
        exit 2
end
extract_tarball(filename) { |bytes_read, total_size| ... } click to toggle source
# File lib/phusion_passenger/standalone/runtime_installer.rb, line 250
def extract_tarball(filename)
        File.open(filename, 'rb') do |f|
                IO.popen("tar xzf -", "wb") do |io|
                        buffer = ''
                        buffer = buffer.force_encoding('binary') if buffer.respond_to?(:force_encoding)
                        total_size = File.size(filename)
                        bytes_read = 0
                        yield(bytes_read, total_size)
                        begin
                                doing_our_io = true
                                while !f.eof?
                                        f.read(1024 * 8, buffer)
                                        io.write(buffer)
                                        io.flush
                                        bytes_read += buffer.size
                                        doing_our_io = false
                                        yield(bytes_read, total_size)
                                        doing_our_io = true
                                end
                        rescue Errno::EPIPE
                                if doing_our_io
                                        return false
                                else
                                        raise
                                end
                        end
                end
                if $?.exitstatus != 0
                        return false
                end
        end
        return true
end
install_nginx_from_source(source_dir) { |0, 1, status_text| ... } click to toggle source
# File lib/phusion_passenger/standalone/runtime_installer.rb, line 429
def install_nginx_from_source(source_dir)
        require 'phusion_passenger/platform_info/compiler'
        Dir.chdir(source_dir) do
                # RPM thinks it's being smart by scanning binaries for
                # paths and refusing to create package if it detects any
                # hardcoded thats that point to /usr or other important
                # locations. For Phusion Passenger Standalone we do not
                # care at all what the Nginx configured prefix is because
                # we pass it its resource locations during runtime, so
                # work around the problem by configure Nginx with prefix
                # /tmp.
                command = "sh ./configure --prefix=/tmp " <<
                        "--with-cc-opt='-Wno-error' " <<
                        "--without-pcre " <<
                        "--without-http_rewrite_module " <<
                        "--without-http_fastcgi_module " <<
                        "'--add-module=#{@support_dir}/ext/nginx'"
                run_command_with_throbber(command, "Preparing Nginx...") do |status_text|
                        yield(0, 1, status_text)
                end
                
                backlog = ""
                total_lines = %x#{PlatformInfo.gnu_make} --dry-run`.split("\n").size
                IO.popen("#{PlatformInfo.gnu_make} 2>&1", "r") do |io|
                        progress = 1
                        while !io.eof?
                                line = io.readline
                                backlog << line
                                yield(progress, total_lines, "Compiling Nginx core...")
                                progress += 1
                        end
                end
                if $?.exitstatus != 0
                        STDERR.puts
                        STDERR.puts "*** ERROR: unable to compile Nginx."
                        STDERR.puts backlog
                        exit 1
                end
                
                yield(1, 1, 'Copying files...')
                if !system("mkdir -p '#{@nginx_dir}/sbin'") ||
                   !system("cp -pR objs/nginx '#{@nginx_dir}/sbin/'")
                        STDERR.puts
                        STDERR.puts "*** ERROR: unable to copy Nginx binaries."
                        exit 1
                end
        end
end
install_passenger_support_files() { |0, 1, 1, "Preparing Phusion Passenger..."| ... } click to toggle source
# File lib/phusion_passenger/standalone/runtime_installer.rb, line 407
def install_passenger_support_files
        begin_progress_bar
        
        # Copy Phusion Passenger sources to designated directory if necessary.
        yield(0, 1, 1, "Preparing Phusion Passenger...")
        FileUtils.rm_rf(@support_dir)
        Dir.chdir(@source_root) do
                files = %x#{rake} package:filelist --silent`.split("\n")
                copy_files(files, @support_dir) do |progress, total|
                        yield(progress, total, 1, "Copying files...")
                end
        end
        
        # Then compile it.
        yield(0, 1, 2, "Preparing Phusion Passenger...")
        Dir.chdir(@support_dir) do
                run_rake_task!("nginx RELEASE=yes") do |progress, total|
                        yield(progress, total, 2, "Compiling Phusion Passenger...")
                end
        end
end
myself() click to toggle source
# File lib/phusion_passenger/standalone/runtime_installer.rb, line 233
def myself
        return %xwhoami`.strip
end
nginx_needs_to_be_installed?() click to toggle source
# File lib/phusion_passenger/standalone/runtime_installer.rb, line 179
def nginx_needs_to_be_installed?
        return @nginx_dir && !File.exist?("#{@nginx_dir}/sbin/nginx")
end
passenger_support_files_need_to_be_installed?() click to toggle source
# File lib/phusion_passenger/standalone/runtime_installer.rb, line 183
def passenger_support_files_need_to_be_installed?
        return @support_dir && !File.exist?("#{@support_dir}/Rakefile")
end
rake() click to toggle source
# File lib/phusion_passenger/standalone/runtime_installer.rb, line 316
def rake
        return PlatformInfo.rake_command
end
run_command_with_throbber(command, status_text) { |"| ... } click to toggle source
# File lib/phusion_passenger/standalone/runtime_installer.rb, line 284
def run_command_with_throbber(command, status_text)
        backlog = ""
        IO.popen("#{command} 2>&1", "r") do |io|
                throbbers = ['-', '\', '|', '/']
                index = 0
                while !io.eof?
                        backlog << io.readline
                        yield("#{status_text} #{throbbers[index]}")
                        index = (index + 1) % throbbers.size
                end
        end
        if $?.exitstatus != 0
                STDERR.puts
                STDERR.puts backlog
                STDERR.puts "*** ERROR: command failed: #{command}"
                exit 1
        end
end
run_rake_task!(target) { |progress, total_lines| ... } click to toggle source
# File lib/phusion_passenger/standalone/runtime_installer.rb, line 320
def run_rake_task!(target)
        total_lines = %x#{rake} #{target} --dry-run STDERR_TO_STDOUT=1`.split("\n").size - 1
        backlog = ""
        
        IO.popen("#{rake} #{target} --trace STDERR_TO_STDOUT=1", "r") do |io|
                progress = 1
                while !io.eof?
                        line = io.readline
                        if line =~ /^\*\* /
                                yield(progress, total_lines)
                                backlog.replace("")
                                progress += 1
                        else
                                backlog << line
                        end
                end
        end
        if $?.exitstatus != 0
                STDERR.puts
                STDERR.puts "*** ERROR: the following command failed:"
                STDERR.puts(backlog)
                exit 1
        end
end
should_download_binaries?() click to toggle source
# File lib/phusion_passenger/standalone/runtime_installer.rb, line 187
def should_download_binaries?
        return @download_binaries && @binaries_url_root
end
show_possible_solutions_for_download_and_extraction_problems() click to toggle source
# File lib/phusion_passenger/standalone/runtime_installer.rb, line 244
def show_possible_solutions_for_download_and_extraction_problems
        new_screen
        render_template "standalone/possible_solutions_for_download_and_extraction_problems"
        puts
end
show_progress(progress, total, phase, total_phases, status_text = "") click to toggle source
# File lib/phusion_passenger/standalone/runtime_installer.rb, line 214
def show_progress(progress, total, phase, total_phases, status_text = "")
        if !phase.is_a?(Range)
                phase = phase..phase
        end
        total_progress = (phase.first - 1).to_f / total_phases
        total_progress += (progress.to_f / total) * ((phase.last - phase.first + 1).to_f / total_phases)
        
        max_width = 79
        progress_bar_width = 45
        text = sprintf("[%-#{progress_bar_width}s] %s",
                '*' * (progress_bar_width * total_progress).to_i,
                status_text)
        text = text.ljust(max_width)
        text = text[0 .. max_width - 1]
        STDOUT.write("#{text}\r")
        STDOUT.flush
        @plugin.call_hook(:runtime_installer_progress, total_progress, status_text) if @plugin
end
show_welcome_screen() click to toggle source
# File lib/phusion_passenger/standalone/runtime_installer.rb, line 191
def show_welcome_screen
        render_template 'standalone/welcome',
                :version => @version,
                :dir => @nginx_dir
        puts
end