????

Your IP : 3.15.195.18


Current Path : /scripts/
Upload File :
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;
}