????
Current Path : /scripts/ |
Current File : //scripts/installruby |
#!/usr/local/cpanel/3rdparty/bin/perl # cpanel - scripts/installruby Copyright 2020 cPanel, L.L.C. # All rights reserved. # copyright@cpanel.net http://cpanel.net # This code is subject to the cPanel license. Unauthorized copying is prohibited package scripts::installruby; use strict; use warnings; use Cpanel::FindBin (); use Cpanel::Logger (); use Cpanel::Locale (); use Cpanel::Patch (); use Cpanel::RoR (); use Cpanel::SafeFile (); use Cpanel::SafeRun::Dynamic (); use Cpanel::SysPkgs (); use Cpanel::TempFile (); use Cpanel::Update (); use Cpanel::Version::Compare (); use Cpanel::GenSysInfo (); use Cpanel::LoadFile (); use Cpanel::SafeRun::Simple (); use Cpanel::ServerTasks (); my $logger = Cpanel::Logger->new(); my %installsrc = ( 'ruby' => '1.8.7', 'rubygems' => '1.3.7', ); my %archive_types = ( '.tar.gz' => '-z', '.tar.bz2' => '-j', '.tgz' => '-z', ); my $src_dir = '/usr/local/cpanel/src/3rdparty/ruby'; my $prefix = '/usr'; my $gem_bin = which_gem(); my $ruby_bin = which_ruby(); my $ruby_version_file = '/var/cpanel/version/ruby'; my $ruby_version; exit( run(@ARGV) ) unless caller(); # update that version when new patches are available sub cpanel_rubygemsversion { return $Cpanel::RoR::rails_version . '.cp5' } sub run { ## no critic(ProhibitExcessComplexity) my @args = @_; my $msg = "This script is deprecated and will be removed in a future version. Please use the EasyApache 4 Ruby instead."; $logger->deprecated($msg); print STDERR "$msg\n"; sleep(5); my $tf = Cpanel::TempFile->new(); $ENV{TMP} = $ENV{TMPDIR} = $ENV{TEMP} = $ENV{USERPROFILE} = $tf->dir() || die("Couldn't create temp dir"); # Case 67573: For 'tmpdir', which would default to /tmp if nothing better were found. # Allow disabling of ruby Cpanel::Update::init_UP_update('ruby'); my $force = @args && grep( /^--force$/, @args ) ? 1 : 0; my $just_rails = @args && grep( /^--just-rails$/, @args ) ? 1 : 0; my $patch = @args && grep( /^--patch(-gems)?$/, @args ) ? 1 : 0; my $ruby_only = check_system_version($just_rails); if ($patch) { _patch_gems( force => $force ); exit; } 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; } system('/usr/local/cpanel/scripts/installsqlite3') == 0 or $logger->die('Failed to install sqlite3'); if ( !$just_rails ) { _install_ruby(); } return 0 if $ruby_only; $gem_bin = which_gem(); # should leave when gem cannot be find unless ($gem_bin) { $logger->warn("Unable to find a valid gem binary."); exit(1); } # Checking if a rails version >= 3.0 exists and ask confirmation before removing it. my $rails_bin = Cpanel::FindBin::findbin('rails'); if ( -x $rails_bin ) { my $rails_version = Cpanel::SafeRun::Simple::saferun( $rails_bin, '--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 @install = ( 'mongrel', 'sqlite3' ); my @sqlite3_args = ( '--with-sqlite3-include=/usr/local/include', '--with-sqlite3-lib=/usr/local/lib' ); print "\nInstalling sqlite3 gem...\n\n"; _install_gem( 'sqlite3', '-v=1.3.6' ); _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) { _install_gem($app); } } if ( !-e '/etc/init.d/ror' && !-e '/usr/local/etc/rc.d/ror.sh' ) { system('/usr/local/cpanel/bin/ror_setup'); } # Patching gems. We have to force this because otherwise our versions don't # get used. _patch_gems( force => 1 ); print "Ruby - & - Rails Installed\n"; system '/usr/local/cpanel/scripts/magicloader'; Cpanel::ServerTasks::schedule_task( ['CpDBTasks'], 5, 'build_global_cache' ); return 0; } sub _hasperlexpect { my $hasperlexpect = 0; eval { require IO::Tty; require Expect; $hasperlexpect = 1; }; return $hasperlexpect; } sub _install_rails { print "\nInstalling rails...\n\n"; my $rails_version = $Cpanel::RoR::rails_version; my @rails = ( 'rails', '-v=' . $rails_version ); Cpanel::SafeRun::Dynamic::saferunnoerrordynamic( $gem_bin, 'install', @rails ); return; } sub _install_ruby { my @install = qw/ruby ruby-devel rubygems ruby-libs ruby-irb rubygem-rake/; my %exclude_options = ( 'kernel' => 1, 'ruby' => 0, 'bind-chroot' => 1, ); my $syspkgobj = Cpanel::SysPkgs->new( exclude_options => \%exclude_options ); if ( !$syspkgobj ) { die "Could not create SysPkgs object\n"; } $syspkgobj->check(); # Ensure Ruby is both installed and unmodified. reinstall will not install # it if it is missing. $syspkgobj->install( 'pkglist' => \@install ); $syspkgobj->reinstall( 'pkglist' => \@install ); # Required for cPanel to display the gem installer. Cpanel::ServerTasks::schedule_task( ['CpDBTasks'], 5, 'build_global_cache' ); return; } sub check_system_version { my ($just_rails) = @_; if ( Cpanel::GenSysInfo::get_rpm_distro_version() != 6 ) { my $lh = Cpanel::Locale->get_handle(); print "\n"; if ($just_rails) { print $lh->maketext('[output,strong,Error]: This script can only install Rails on [asis,Red Hat 6], [asis,CentOS 6], and [asis,CloudLinux 6].'), "\n\n"; } else { print $lh->maketext('[output,strong,Note]: This script can only install Rails on [asis,Red Hat 6], [asis,CentOS 6], and [asis,CloudLinux 6].'), "\n"; print $lh->maketext('Only Ruby will be installed.'); print "\n\n"; } exit 1 if $just_rails; return 1; } return 0; } sub ask_question { my ($question) = @_; # cannot ask the question without STDIN being available return 2 unless -t STDIN; my $ask = $question . " Yes/No: "; print $ask; while (1) { my $choice = <STDIN>; chomp($choice); return 1 if ( $choice =~ /^y(?:es)?$/i ); return 0 if ( $choice =~ /^n(?:o)?$/ ); $choice = undef; print "Cannot understand your answer, you should answer by 'yes' or 'no'.\n"; print $ask; } # never reached return; } sub which_gem { return _which_bin('gem'); } sub which_ruby { return _which_bin('ruby'); } sub _which_bin { my $name = shift or return; for my $d (qw{/usr/local/bin /usr/bin}) { my $bin = $d . '/' . $name; return $bin if -x $bin; } $logger->warn("Unable to locate $name binary."); return; } sub gem_version { my $bin = shift || which_gem(); return unless $bin && -x $bin; my $version = `$bin -v`; return unless $version; chomp $version; return $version; } sub _version_file { return '/var/cpanel/version/cpgrubygems'; } sub _check_patch_version { my $current = Cpanel::LoadFile::loadfile( _version_file() ) || 0; $current =~ s/\s+//g; return $current ne cpanel_rubygemsversion(); } sub _patch_gems { my (%opts) = @_; $opts{force} ||= 0; my $logger = Cpanel::Logger->new(); # check that gem exists my $gem_bin = which_gem(); unless ($gem_bin) { $logger->warn("Cannot find gem binary."); return; } my $gems_src = '/usr/local/cpanel/src/3rdparty/ruby/gems'; # cpanel_version if ( !$opts{force} && !_check_patch_version() ) { $logger->info("Gems are already up-to-date with latest patches."); return; } my $rails_version = $Cpanel::RoR::rails_version; my @gems_to_patch = ( { name => 'mongrel', version => '1.1.5', }, { name => 'rack', version => '1.1.6', uninstall => '<1.1.6', }, ); foreach my $gem (@gems_to_patch) { my $name = ucfirst( $gem->{name} ) . " v" . $gem->{version}; $logger->info("Gem $name"); # check if the gem is installed unless ( system( $gem_bin, 'list', $gem->{name}, '-i', '-v', '=' . $gem->{version} ) == 0 ) { $logger->warn( $name . " is not installed." ); next unless $gem->{uninstall}; } # uninstall the unpatched gem and more if specified if ( $gem->{uninstall} ) { _uninstall_gem( $gem->{name}, '-a', '-v' => $gem->{uninstall} ); } chdir $gems_src or $logger->die( 'Unable to chdir: ' . $! ); my $src = $gem->{name} . '-' . $gem->{version}; my $gemfile = $src . '.gem'; my $patch = $gems_src . '/../patch/gems/' . $src; unless ( -e $gemfile && -d $patch ) { $logger->warn( "Cannot patch " . $name . " ( gem or patch are missing )" ); next; } # clean previous installation system( 'rm', '-rf', $src ) if ( -e $src ); my @cmds; push @cmds, [ $gem_bin, 'unpack', $gemfile ]; foreach my $cmd (@cmds) { system(@$cmd) == 0 or $logger->die( "Failed command: " . join( ' ', @$cmd ) ); } # apply patch if ( !Cpanel::Patch::apply_patchset( $patch, $src ) ) { $logger->die("Failed to patch $name."); } # build and install gem chdir($src) or $logger->die( 'Unable to chdir: ' . $! ); @cmds = (); push @cmds, [ $gem_bin, 'build', "$gem->{name}.gemspec" ]; push @cmds, [ $gem_bin, 'install', $gemfile, '--local' ]; foreach my $cmd (@cmds) { system(@$cmd) == 0 or $logger->die( "Failed command: " . join( ' ', @$cmd ) ); } $logger->info("Successfully patched and installed $name."); } # update the lock file my $lock = Cpanel::SafeFile::safeopen( \*VERSION, ">", _version_file() ) || do { $logger->die( "Cannot open " . _version_file() . " " . $! ); }; print VERSION cpanel_rubygemsversion(); Cpanel::SafeFile::safeclose( \*VERSION, $lock ) if $lock; return; } sub _uninstall_gem { my ( $gem, @opts ) = @_; Cpanel::SafeRun::Dynamic::saferunnoerrordynamic( which_gem(), 'uninstall', '-I', '-x', @opts, $gem ); return; } sub _install_gem { my ( $gem, @opts ) = @_; my $gem_version = gem_version(); push @opts, '--no-ri', '--no-rdoc'; push @opts, '--include-dependencies' if ( $gem_version && Cpanel::Version::Compare::compare( $gem_version, '<', '2.0' ) ); Cpanel::SafeRun::Simple::saferun( which_gem(), 'install', $gem, @opts ); return; } sub uninstallrails3 { for my $gem (qw(rails actionmailer activemodel actionpack activerecord activeresource activesupport railties)) { _uninstall_gem( $gem, '-v' => '>=3.0.0' ); } # remove patch version unlink _version_file(); return; }