252 lines
8.0 KiB
Perl
252 lines
8.0 KiB
Perl
# -*- 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 <mkanat@bugzilla.org>
|
|
|
|
package Bugzilla::Install::CPAN;
|
|
use strict;
|
|
use base qw(Exporter);
|
|
our @EXPORT = qw(set_cpan_config install_module BZ_LIB);
|
|
|
|
use Bugzilla::Constants;
|
|
use Bugzilla::Install::Util qw(bin_loc install_string);
|
|
|
|
use CPAN;
|
|
use Cwd qw(abs_path);
|
|
use File::Path qw(rmtree);
|
|
use List::Util qw(shuffle);
|
|
|
|
# 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,
|
|
cache_metadata => 1,
|
|
index_expire => 1,
|
|
scan_cache => 'atstart',
|
|
|
|
inhibit_startup_message => 1,
|
|
mbuild_install_build_command => './Build',
|
|
|
|
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 => [shuffle qw(
|
|
http://cpan.pair.com/
|
|
http://mirror.hiwaay.net/CPAN/
|
|
ftp://ftp.dc.aleron.net/pub/CPAN/
|
|
http://perl.secsup.org/
|
|
http://mirrors.kernel.org/cpan/)],
|
|
};
|
|
|
|
sub install_module {
|
|
my ($name, $notest) = @_;
|
|
my $bzlib = BZ_LIB;
|
|
|
|
# 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 'Net::LDAP') {
|
|
$CPAN::Config->{makepl_arg} .= " --skipdeps";
|
|
}
|
|
elsif ($name eq 'SOAP::Lite') {
|
|
$CPAN::Config->{makepl_arg} .= " --noprompt";
|
|
}
|
|
|
|
my $module = CPAN::Shell->expand('Module', $name);
|
|
print install_string('install_module',
|
|
{ module => $name, version => $module->cpan_version }) . "\n";
|
|
if ($notest) {
|
|
CPAN::Shell->notest('install', $name);
|
|
}
|
|
else {
|
|
CPAN::Shell->force('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 "WARNING: Using the Bugzilla directory as the CPAN 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) {
|
|
$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\"";
|
|
|
|
# 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', 1);
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
This is primarily used by L<install-module> to do the "hard work" of
|
|
installing CPAN modules.
|
|
|
|
=head1 SUBROUTINES
|
|
|
|
=over
|
|
|
|
=item C<set_cpan_config>
|
|
|
|
Sets up the configuration of CPAN for this session. Must be called
|
|
before L</install_module>. Takes one boolean parameter. If true,
|
|
L</install_module> will install modules globally instead of to the
|
|
local F<lib/> directory. On most systems, you have to be root to do that.
|
|
|
|
=item C<install_module>
|
|
|
|
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<install> command in the CPAN shell.
|
|
|
|
=item C<$notest> - If true, we skip running tests on this module. This
|
|
can greatly speed up the installation time.
|
|
|
|
=back
|
|
|
|
Note that calling this function prints a B<lot> of information to
|
|
STDOUT and STDERR.
|
|
|
|
=back
|