From 14bcdce1dc6029c3676c3640d8148c83c14692e5 Mon Sep 17 00:00:00 2001 From: Dylan William Hardison Date: Mon, 12 Sep 2016 16:22:17 -0400 Subject: Revert "Bug 1283930 - Add Makefile.PL & local/lib/perl5 support to bmo/master + local symlink to data/ directory" This reverts commit e6bf4cacb10f86077fe898349485f5c7ab9fb4b6. --- Bugzilla/Install/CPAN.pm | 351 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 351 insertions(+) create mode 100644 Bugzilla/Install/CPAN.pm (limited to 'Bugzilla/Install/CPAN.pm') diff --git a/Bugzilla/Install/CPAN.pm b/Bugzilla/Install/CPAN.pm new file mode 100644 index 000000000..e7556526c --- /dev/null +++ b/Bugzilla/Install/CPAN.pm @@ -0,0 +1,351 @@ +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# The Initial Developer of the Original Code is Everything Solved, Inc. +# Portions created by Everything Solved are Copyright (C) 2007 +# Everything Solved, Inc. All Rights Reserved. +# +# Contributor(s): Max Kanat-Alexander + +package Bugzilla::Install::CPAN; +use strict; +use base qw(Exporter); +our @EXPORT = qw( + BZ_LIB + + check_cpan_requirements + set_cpan_config + install_module +); + +use Bugzilla::Constants; +use Bugzilla::Install::Requirements qw(have_vers); +use Bugzilla::Install::Util qw(bin_loc install_string); + +use Config; +use CPAN; +use Cwd qw(abs_path); +use File::Path qw(rmtree); + +# These are required for install-module.pl to be able to install +# all modules properly. +use constant REQUIREMENTS => ( + { + module => 'CPAN', + package => 'CPAN', + version => '1.81', + }, + { + # When Module::Build isn't installed, the YAML module allows + # CPAN to read META.yml to determine that Module::Build first + # needs to be installed to compile a module. + module => 'YAML', + package => 'YAML', + version => 0, + }, + { + # Many modules on CPAN are now built with Dist::Zilla, which + # unfortunately means they require this version of EU::MM to install. + module => 'ExtUtils::MakeMaker', + package => 'ExtUtils-MakeMaker', + version => '6.31', + }, +); + +# We need the absolute path of ext_libpath, because CPAN chdirs around +# and so we can't use a relative directory. +# +# We need it often enough (and at compile time, in install-module.pl) so +# we make it a constant. +use constant BZ_LIB => abs_path(bz_locations()->{ext_libpath}); + +# CPAN requires nearly all of its parameters to be set, or it will start +# asking questions to the user. We want to avoid that, so we have +# defaults here for most of the required parameters we know about, in case +# any of them aren't set. The rest are handled by set_cpan_defaults(). +use constant CPAN_DEFAULTS => { + auto_commit => 0, + # We always force builds, so there's no reason to cache them. + build_cache => 0, + build_requires_install_policy => 'yes', + cache_metadata => 1, + colorize_output => 1, + colorize_print => 'bold', + index_expire => 1, + scan_cache => 'atstart', + + inhibit_startup_message => 1, + + bzip2 => bin_loc('bzip2'), + curl => bin_loc('curl'), + gzip => bin_loc('gzip'), + links => bin_loc('links'), + lynx => bin_loc('lynx'), + make => bin_loc('make'), + pager => bin_loc('less'), + tar => bin_loc('tar'), + unzip => bin_loc('unzip'), + wget => bin_loc('wget'), + + urllist => ['http://www.cpan.org/'], +}; + +sub check_cpan_requirements { + my ($original_dir, $original_args) = @_; + + _require_compiler(); + + my @install; + foreach my $module (REQUIREMENTS) { + my $installed = have_vers($module, 1); + push(@install, $module) if !$installed; + } + + return if !@install; + + my $restart_required; + foreach my $module (@install) { + $restart_required = 1 if $module->{module} eq 'CPAN'; + install_module($module->{module}, 1); + } + + if ($restart_required) { + chdir $original_dir; + exec($^X, $0, @$original_args); + } +} + +sub _require_compiler { + my @errors; + + my $cc_name = $Config{cc}; + my $cc_exists = bin_loc($cc_name); + + if (!$cc_exists) { + push(@errors, install_string('install_no_compiler')); + } + + my $make_name = $CPAN::Config->{make}; + my $make_exists = bin_loc($make_name); + + if (!$make_exists) { + push(@errors, install_string('install_no_make')); + } + + die @errors if @errors; +} + +sub install_module { + my ($name, $test) = @_; + my $bzlib = BZ_LIB; + + # Make Module::AutoInstall install all dependencies and never prompt. + local $ENV{PERL_AUTOINSTALL} = '--alldeps'; + # This makes Net::SSLeay not prompt the user, if it gets installed. + # It also makes any other MakeMaker prompts accept their defaults. + local $ENV{PERL_MM_USE_DEFAULT} = 1; + + # Certain modules require special stuff in order to not prompt us. + my $original_makepl = $CPAN::Config->{makepl_arg}; + # This one's a regex in case we're doing Template::Plugin::GD and it + # pulls in Template-Toolkit as a dependency. + if ($name =~ /^Template/) { + $CPAN::Config->{makepl_arg} .= " TT_ACCEPT=y TT_EXTRAS=n"; + } + elsif ($name eq 'XML::Twig') { + $CPAN::Config->{makepl_arg} = "-n $original_makepl"; + } + elsif ($name eq 'SOAP::Lite') { + $CPAN::Config->{makepl_arg} .= " --noprompt"; + } + + my $module = CPAN::Shell->expand('Module', $name); + if (!$module) { + die install_string('no_such_module', { module => $name }) . "\n"; + } + my $version = $module->cpan_version; + my $module_name = $name; + + if ($name eq 'LWP::UserAgent' && $^V lt v5.8.8) { + # LWP 6.x requires Perl 5.8.8 or newer. + # As PAUSE only indexes the very last version of each module, + # we have to specify the path to the tarball ourselves. + $name = 'GAAS/libwww-perl-5.837.tar.gz'; + # This tarball contains LWP::UserAgent 5.835. + $version = '5.835'; + } + + print install_string('install_module', + { module => $module_name, version => $version }) . "\n"; + + if ($test) { + CPAN::Shell->force('install', $name); + } + else { + CPAN::Shell->notest('install', $name); + } + + # If it installed any binaries in the Bugzilla directory, delete them. + if (-d "$bzlib/bin") { + File::Path::rmtree("$bzlib/bin"); + } + + $CPAN::Config->{makepl_arg} = $original_makepl; +} + +sub set_cpan_config { + my $do_global = shift; + my $bzlib = BZ_LIB; + + # We set defaults before we do anything, otherwise CPAN will + # start asking us questions as soon as we load its configuration. + eval { require CPAN::Config; }; + _set_cpan_defaults(); + + # Calling a senseless autoload that does nothing makes us + # automatically load any existing configuration. + # We want to avoid the "invalid command" message. + open(my $saveout, ">&", "STDOUT"); + open(STDOUT, '>', '/dev/null'); + eval { CPAN->ignore_this_error_message_from_bugzilla; }; + undef $@; + close(STDOUT); + open(STDOUT, '>&', $saveout); + + my $dir = $CPAN::Config->{cpan_home}; + if (!defined $dir || !-w $dir) { + # If we can't use the standard CPAN build dir, we try to make one. + $dir = "$ENV{HOME}/.cpan"; + mkdir $dir; + + # If we can't make one, we finally try to use the Bugzilla directory. + if (!-w $dir) { + print STDERR install_string('cpan_bugzilla_home'), "\n"; + $dir = "$bzlib/.cpan"; + } + } + $CPAN::Config->{cpan_home} = $dir; + $CPAN::Config->{build_dir} = "$dir/build"; + # We always force builds, so there's no reason to cache them. + $CPAN::Config->{keep_source_where} = "$dir/source"; + # This is set both here and in defaults so that it's always true. + $CPAN::Config->{inhibit_startup_message} = 1; + # Automatically install dependencies. + $CPAN::Config->{prerequisites_policy} = 'follow'; + + # Unless specified, we install the modules into the Bugzilla directory. + if (!$do_global) { + require Config; + + $CPAN::Config->{makepl_arg} .= " LIB=\"$bzlib\"" + . " INSTALLMAN1DIR=\"$bzlib/man/man1\"" + . " INSTALLMAN3DIR=\"$bzlib/man/man3\"" + # The bindirs are here because otherwise we'll try to write to + # the system binary dirs, and that will cause CPAN to die. + . " INSTALLBIN=\"$bzlib/bin\"" + . " INSTALLSCRIPT=\"$bzlib/bin\"" + # INSTALLDIRS=perl is set because that makes sure that MakeMaker + # always uses the directories we've specified here. + . " INSTALLDIRS=perl"; + $CPAN::Config->{mbuild_arg} = " --install_base \"$bzlib\"" + . " --install_path lib=\"$bzlib\"" + . " --install_path arch=\"$bzlib/$Config::Config{archname}\""; + $CPAN::Config->{mbuild_install_arg} = $CPAN::Config->{mbuild_arg}; + + # When we're not root, sometimes newer versions of CPAN will + # try to read/modify things that belong to root, unless we set + # certain config variables. + $CPAN::Config->{histfile} = "$dir/histfile"; + $CPAN::Config->{use_sqlite} = 0; + $CPAN::Config->{prefs_dir} = "$dir/prefs"; + + # Unless we actually set PERL5LIB, some modules can't install + # themselves, like DBD::mysql, DBD::Pg, and XML::Twig. + my $current_lib = $ENV{PERL5LIB} ? $ENV{PERL5LIB} . ':' : ''; + $ENV{PERL5LIB} = $current_lib . $bzlib; + } +} + +sub _set_cpan_defaults { + # If CPAN hasn't been configured, we try to use some reasonable defaults. + foreach my $key (keys %{CPAN_DEFAULTS()}) { + $CPAN::Config->{$key} = CPAN_DEFAULTS->{$key} + if !defined $CPAN::Config->{$key}; + } + + my @missing; + # In newer CPANs, this is in HandleConfig. In older CPANs, it's in + # Config. + if (eval { require CPAN::HandleConfig }) { + @missing = CPAN::HandleConfig->missing_config_data; + } + else { + @missing = CPAN::Config->missing_config_data; + } + + foreach my $key (@missing) { + $CPAN::Config->{$key} = ''; + } +} + +1; + +__END__ + +=head1 NAME + +Bugzilla::Install::CPAN - Routines to install Perl modules from CPAN. + +=head1 SYNOPSIS + + use Bugzilla::Install::CPAN; + + set_cpan_config(); + install_module('Module::Name'); + +=head1 DESCRIPTION + +This is primarily used by L to do the "hard work" of +installing CPAN modules. + +=head1 SUBROUTINES + +=over + +=item C + +Sets up the configuration of CPAN for this session. Must be called +before L. Takes one boolean parameter. If true, +L will install modules globally instead of to the +local F directory. On most systems, you have to be root to do that. + +=item C + +Installs a module from CPAN. Takes two arguments: + +=over + +=item C<$name> - The name of the module, just like you'd pass to the +C command in the CPAN shell. + +=item C<$test> - If true, we run tests on this module before installing, +but we still force the install if the tests fail. This is only used +when we internally install a newer CPAN module. + +=back + +Note that calling this function prints a B of information to +STDOUT and STDERR. + +=back -- cgit v1.2.3-24-g4f1b