#!/usr/bin/perl
# cpanel - installruby Copyright(c) 2011 cPanel, Inc.
# All rights Reserved.
# copyright@cpanel.net http://cpanel.net
# This code is subject to the cpanel license. Unauthorized copying is prohibited
BEGIN { unshift @INC, '/usr/local/cpanel'; }
use Cpanel::FileUtils ();
use Cpanel::FindBin ();
use Cpanel::Logger ();
use Cpanel::OSSys ();
use Cpanel::SafeRun ();
use Cpanel::SysPkgs ();
use Cpanel::Tar ();
use Cpanel::Update ();
use Cpanel::Version::Compare ();
# Allow disabling of ruby
Cpanel::Update::init_UP_update('ruby');
my %install = (
'ruby' => '1.8.7-p334',
'rubygems' => '1.3.7',
);
my $force = @ARGV && grep( /^--force$/, @ARGV ) ? 1 : 0;
my $just_rails = @ARGV && grep( /^--just-rails$/, @ARGV ) ? 1 : 0;
my $src_dir = '/usr/local/cpanel/src/3rdparty/ruby';
my $system = Cpanel::OSSys::get_system();
my $prefix = $system eq 'freebsd' ? '/usr/local' : '/usr';
my $gem_bin = -x $prefix . '/bin/gem' ? $prefix . '/bin/gem' : '/usr/bin/gem';
my $ruby_bin = -x $prefix . '/bin/ruby' ? $prefix . '/bin/ruby' : '/usr/bin/ruby';
my $ruby_version_file = '/var/cpanel/version/ruby';
my %archive_types = (
'.tar.gz' => '-z',
'.tar.bz2' => '-j',
'.tgz' => '-z',
);
my $exit_code = system '/usr/local/cpanel/scripts/checkccompiler';
if ($exit_code) {
print "C compiler appears to be broken. Ruby cannot be installed until this is resolved!\n";
exit 1;
}
my $logger = Cpanel::Logger->new();
system '/usr/local/cpanel/scripts/installsqlite3', '--source';
if ( !$just_rails ) {
my $needs_gem = -x $gem_bin && !$force ? 0 : 1;
if ( !$needs_gem ) {
# Gem 0.8.5+ can self update, cPanel started with 1.1
my $gem_version = `$gem_bin -v`;
if ( !$gem_version ) {
$needs_gem = 1;
}
else {
chomp $gem_version;
if ( $gem_version =~ m/^0/ ) {
$needs_gem = 1;
}
}
}
my $needs_ruby = ( !-e $ruby_version_file || $force ) ? 1 : 0;
my $ruby_version = `$ruby_bin -v`;
chomp $ruby_version;
# check version in file
if ( !$needs_ruby ) {
if ( !$ruby_version ) {
$needs_ruby = 1;
}
else {
if ( open my $vers_fh, '<', $ruby_version_file ) {
my $vers = readline $vers_fh;
close $vers_fh;
chomp $vers;
if ( !$vers ) {
$needs_ruby = 1;
}
elsif ( $vers ne $install{'ruby'} ) {
my ( $new_version_number, $new_patch_level ) = split( /-/, $install{'ruby'} );
my ( $installed_version_number, $installed_patch_level ) = split( /-/, $vers );
if ( $new_version_number > $installed_version_number ) {
$needs_ruby = 1;
}
elsif ( $new_version_number eq $installed_version_number ) {
my ($new_patch) = $new_patch_level =~ m/(\d+)/;
my ($installed_patch) = $installed_patch_level =~ m/(\d+)/;
if ($new_patch) { # if we distribute a patched version
if ( !$installed_patch ) { # they don't have a patched version
$needs_ruby = 1;
}
elsif ( $new_patch > $installed_patch ) { # our patch is greater than theirs
$needs_ruby = 1;
}
}
}
}
}
else {
$logger->warn("Failed to check version file: $!");
$needs_ruby = 1;
}
}
}
if ( $system eq 'freebsd' ) {
my @install = ('ruby18');
if ($needs_gem) {
push @install, 'ruby-gems';
}
my $syspkgs = Cpanel::SysPkgs->new();
if ( !$syspkgs ) { die print "Could not create SysPkgs object\n"; }
$syspkgs->ensure( 'pkglist' => \@install );
}
else {
my $tarcfg = Cpanel::Tar::load_tarcfg();
my @install;
if ($needs_ruby) {
@install = ('ruby');
}
if ($needs_gem) {
push @install, 'rubygems';
}
INSTALL:
foreach my $app (@install) {
my $basedir = '/home/cp' . $app . 'build';
eval {
system 'rm', '-rf', $basedir;
system 'mkdir', $basedir;
chdir $basedir or $logger->die("Unable to chdir $basedir: $!");
print "Installing $app version: $install{$app}\n";
my $app_source_base = $app . '-' . $install{$app};
my $app_source;
my $decompression_flag;
foreach my $archive_extension ( keys %archive_types ) {
if ( -e $src_dir . '/' . $app_source_base . $archive_extension ) {
$app_source = $app_source_base . $archive_extension;
$decompression_flag = $archive_types{$archive_extension};
last;
}
}
if ( !$app_source ) {
$logger->warn("Unable to locate source for $app");
die;
}
system $tarcfg->{'bin'}, '-x', '-p', $tarcfg->{'no_same_owner'}, $decompression_flag, '-C', $basedir, '-f', $src_dir . '/' . $app_source;
if ( !-d $basedir . '/' . $app_source_base ) {
$logger->warn("Failed to decompress source for $app");
die;
}
print "Using Dir: $basedir/$app_source_base\n";
if ( !chdir( $basedir . '/' . $app_source_base ) ) {
$logger->warn("Unable to chdir to $basedir/$app_source_base failed.");
die;
}
if ( $app ne 'ruby' ) {
print "Setting up $app ...\n";
system $ruby_bin, 'setup.rb';
}
else {
if ($ruby_version) {
print "\nUpdating $ruby_version with $install{$app}\n\n";
}
# Rubygems installation says you should do this manually????
if ( $app eq 'rubygems' && -e $gem_bin ) {
unlink $gem_bin;
}
unlink $ruby_version_file;
my @CONF = ( './configure', '--prefix=' . $prefix, '--enable-shared' );
system @CONF;
system 'gmake';
system 'gmake', 'install';
if ( open my $vers_fh, '>', $ruby_version_file ) {
print {$vers_fh} $install{$app};
close $vers_fh;
}
else {
$logger->warn("Unable to update version file $ruby_version_file: $!");
die;
}
}
};
print "Removing source directory $basedir\n";
chdir '/';
system 'rm', '-rf', $basedir;
}
}
}
$gem_bin = -x '/usr/local/bin/gem' ? '/usr/local/bin/gem' : '/usr/bin/gem';
if ( !-x $gem_bin ) {
$logger->warn("gem installation failed. Unable to locate gem binary.");
}
else {
print "gem system update ...\n";
system $prefix . '/bin/gem', 'update', '--system';
print "gem system update complete.\n";
}
my $rails_bin = Cpanel::FindBin::findbin('rails');
if ( -x $rails_bin ) {
my $rails_version = Cpanel::SafeRun::saferun( 'rails', '--version' );
chomp($rails_version);
($rails_version) = ( split( ' ', $rails_version, 2 ) )[1];
if ( Cpanel::Version::Compare::compare( $rails_version, '>=', '3.0.0' ) ) {
my $warning_msg = "\n" . 'Rails 3 has been detected on your system. Rails 3 is not supported at this time.';
if ( -t STDIN ) {
print $warning_msg . ' Would you like to remove it and install a supported version of rails? ';
my $choice;
while ( !defined $choice ) {
$choice = <STDIN>;
chomp($choice);
if ( $choice =~ /^y(?:es)?$/i ) {
$choice = 1;
}
elsif ( $choice =~ /^n(?:o)?$/ ) {
$choice = 0;
}
else {
$choice = undef;
}
}
if ($choice) {
uninstallrails3();
}
else {
exit 1;
}
}
else {
print $warning_msg . ' Uninstalling rails 3.' . "\n";
uninstallrails3();
}
}
}
my @rails = ( 'rails', '-v=2.3.14' );
my @install = ( 'mongrel', 'sqlite3' );
my @sqlite3_args = ( '--with-sqlite3-include=/usr/local/include', '--with-sqlite3-lib=/usr/local/lib' );
my $hasperlexpect = 0;
eval {
require IO::Tty;
require Expect;
$hasperlexpect = 1;
};
print "\nInstalling rails...\n\n";
Cpanel::SafeRun::saferunnoerrordynamic( $gem_bin, 'install', @rails, );
if ($hasperlexpect) {
if ( my $pid = fork() ) {
waitpid( $pid, 0 );
}
else {
local $SIG{'ALRM'} = sub { die "Timeout\n"; };
alarm( 20 * 60 );
my $exp = Expect->spawn( $gem_bin, 'install', @install, '--', @sqlite3_args ) or die "Cannot spawn gem installer: $!";
my $expect_pid = $exp->pid();
my $mongrel_number = 0;
my $fastthread_number = 0;
while ( waitpid( $expect_pid, 1 ) != -1 ) {
$exp->expect(
300,
[ 'Select which gem', sub { return Expect::exp_continue() } ],
[
qr/^\s*\d\.\smongrel\s.*/,
sub {
if ( $exp->match =~ /\(ruby\)/ ) {
if ( !$mongrel_number ) {
($mongrel_number) = $exp->match =~ /\s*(\d+)/;
}
}
else {
return Expect::exp_continue();
}
}
],
[
qr/^\s*\d\.\sfastthread\s.*/,
sub {
if ( $exp->match =~ /\(ruby\)/ ) {
if ( !$fastthread_number ) {
($fastthread_number) = $exp->match =~ /\s*(\d+)/;
}
}
else {
return Expect::exp_continue();
}
}
],
[
'>',
sub {
my $number = 0;
if ($mongrel_number) {
$number = $mongrel_number;
$mongrel_number = 0;
}
elsif ($fastthread_number) {
$number = $fastthread_number;
$fastthread_number = 0;
}
$exp->send( $number . "\r" );
}
],
[ 'timeout', sub { $exp->send("\r"); } ],
);
}
$exp->soft_close();
exit;
}
}
else {
foreach my $app (@install) {
system $gem_bin, 'install', $app, '--include-dependencies';
}
}
if ( !-e '/etc/init.d/ror' && !-e '/usr/local/etc/rc.d/ror.sh' ) {
system('/usr/local/cpanel/bin/ror_setup');
}
print "Ruby - & - Rails Installed\n";
system '/usr/local/cpanel/scripts/magicloader';
system '/usr/local/cpanel/bin/updatemongrel';
exit;
sub uninstallrails3 {
Cpanel::SafeRun::saferunnoerrordynamic( 'gem', 'uninstall', '-I', '-x', '-v', '>= 3.0.0', 'rails' );
Cpanel::SafeRun::saferunnoerrordynamic( 'gem', 'uninstall', '-I', '-x', '-v', '>= 3.0.0', 'actionmailer' );
Cpanel::SafeRun::saferunnoerrordynamic( 'gem', 'uninstall', '-I', '-x', '-v', '>= 3.0.0', 'activemodel' );
Cpanel::SafeRun::saferunnoerrordynamic( 'gem', 'uninstall', '-I', '-x', '-v', '>= 3.0.0', 'actionpack' );
Cpanel::SafeRun::saferunnoerrordynamic( 'gem', 'uninstall', '-I', '-x', '-v', '>= 3.0.0', 'activerecord' );
Cpanel::SafeRun::saferunnoerrordynamic( 'gem', 'uninstall', '-I', '-x', '-v', '>= 3.0.0', 'activeresource' );
Cpanel::SafeRun::saferunnoerrordynamic( 'gem', 'uninstall', '-I', '-x', '-v', '>= 3.0.0', 'activesupport' );
Cpanel::SafeRun::saferunnoerrordynamic( 'gem', 'uninstall', '-I', '-x', '-v', '>= 3.0.0', 'railties' );
}