Upgrade to 4.2.8
[usit-rt.git] / sbin / rt-test-dependencies
CommitLineData
84fb5b46
MKG
1#!/usr/bin/perl
2# BEGIN BPS TAGGED BLOCK {{{
3#
4# COPYRIGHT:
5#
3ffc5f4f 6# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC
84fb5b46
MKG
7# <sales@bestpractical.com>
8#
9# (Except where explicitly superseded by other copyright notices)
10#
11#
12# LICENSE:
13#
14# This work is made available to you under the terms of Version 2 of
15# the GNU General Public License. A copy of that license should have
16# been provided with this software, but in any event can be snarfed
17# from www.gnu.org.
18#
19# This work is distributed in the hope that it will be useful, but
20# WITHOUT ANY WARRANTY; without even the implied warranty of
21# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22# General Public License for more details.
23#
24# You should have received a copy of the GNU General Public License
25# along with this program; if not, write to the Free Software
26# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27# 02110-1301 or visit their web page on the internet at
28# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
29#
30#
31# CONTRIBUTION SUBMISSION POLICY:
32#
33# (The following paragraph is not intended to limit the rights granted
34# to you to modify and distribute this software under the terms of
35# the GNU General Public License and is only of importance to you if
36# you choose to contribute your changes and enhancements to the
37# community by submitting them to Best Practical Solutions, LLC.)
38#
39# By intentionally submitting any modifications, corrections or
40# derivatives to this work, or any other work intended for use with
41# Request Tracker, to Best Practical Solutions, LLC, you confirm that
42# you are the copyright holder for those contributions and you grant
43# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
44# royalty-free, perpetual, license to use, copy, create derivative
45# works based on those contributions, and sublicense and distribute
46# those contributions and any derivatives thereof.
47#
48# END BPS TAGGED BLOCK }}}
49#
50# This is just a basic script that checks to make sure that all
51# the modules needed by RT before you can install it.
52#
53
54use strict;
403d7b0b 55use warnings;
84fb5b46
MKG
56no warnings qw(numeric redefine);
57use Getopt::Long;
3ffc5f4f 58use Cwd qw(abs_path);
84fb5b46
MKG
59my %args;
60my %deps;
dab09ea8 61my @orig_argv = @ARGV;
3ffc5f4f
MKG
62# Save our path because installers or tests can change cwd
63my $script_path = abs_path($0);
64
84fb5b46
MKG
65GetOptions(
66 \%args, 'v|verbose',
3ffc5f4f
MKG
67 'install!',
68 'with-MYSQL', 'with-PG', 'with-SQLITE', 'with-ORACLE',
69 'with-FASTCGI', 'with-MODPERL1', 'with-MODPERL2', 'with-STANDALONE',
84fb5b46 70
3ffc5f4f 71 'with-DEVELOPER',
84fb5b46
MKG
72
73 'with-GPG',
74 'with-ICAL',
84fb5b46
MKG
75 'with-GRAPHVIZ',
76 'with-GD',
77 'with-DASHBOARDS',
78 'with-USERLOGO',
dab09ea8 79 'with-HTML-DOC',
84fb5b46 80
84fb5b46
MKG
81 'list-deps',
82 'help|h',
83);
84
85if ( $args{help} ) {
86 require Pod::Usage;
87 Pod::Usage::pod2usage( { verbose => 2 } );
88 exit;
89}
90
91# Set up defaults
92my %default = (
84fb5b46
MKG
93 'with-CORE' => 1,
94 'with-CLI' => 1,
95 'with-MAILGATE' => 1,
3ffc5f4f 96 'with-DEVELOPER' => 0,
84fb5b46 97 'with-GPG' => 0,
3ffc5f4f 98 'with-SMIME' => 1,
84fb5b46 99 'with-ICAL' => 1,
3ffc5f4f
MKG
100 'with-GRAPHVIZ' => 1,
101 'with-GD' => 0,
84fb5b46
MKG
102 'with-DASHBOARDS' => 1,
103 'with-USERLOGO' => 1,
dab09ea8 104 'with-HTML-DOC' => 0,
84fb5b46
MKG
105);
106$args{$_} = $default{$_} foreach grep !exists $args{$_}, keys %default;
107
108{
109 my $section;
110 my %always_show_sections = (
111 perl => 1,
112 users => 1,
113 );
114
115 sub section {
116 my $s = shift;
117 $section = $s;
118 print "$s:\n" unless $args{'list-deps'};
119 }
120
121 sub print_found {
122 my $msg = shift;
123 my $test = shift;
124 my $extra = shift;
125
126 unless ( $args{'list-deps'} ) {
127 if ( $args{'v'} or not $test or $always_show_sections{$section} ) {
128 print "\t$msg ...";
129 print $test ? "found" : "MISSING";
130 print "\n";
131 }
132
133 print "\t\t$extra\n" if defined $extra;
134 }
135 }
136}
137
138sub conclude {
139 my %missing_by_type = @_;
140
141 unless ( $args{'list-deps'} ) {
142 unless ( keys %missing_by_type ) {
143 print "\nAll dependencies have been found.\n";
144 return;
145 }
146
147 print "\nSOME DEPENDENCIES WERE MISSING.\n";
148
149 for my $type ( keys %missing_by_type ) {
150 my $missing = $missing_by_type{$type};
151
152 print "$type missing dependencies:\n";
153 for my $name ( keys %$missing ) {
154 my $module = $missing->{$name};
155 my $version = $module->{version};
156 my $error = $module->{error};
157 print_found( $name . ( $version && !$error ? " >= $version" : "" ),
158 0, $module->{error} );
159 }
160 }
3ffc5f4f
MKG
161
162 print "\nPerl library path for /usr/bin/perl:\n";
163 print " $_\n" for @INC;
164
84fb5b46
MKG
165 exit 1;
166 }
167}
168
169sub text_to_hash {
170 my %hash;
171 for my $line ( split /\n/, $_[0] ) {
172 my($key, $value) = $line =~ /(\S+)\s*(\S*)/;
173 $value ||= '';
174 $hash{$key} = $value;
175 }
176
177 return %hash;
178}
3ffc5f4f
MKG
179sub set_dep {
180 my ($name, $module, $version) = @_;
181 my %list = @{$deps{$name}};
182 $list{$module} = ($version || '');
183 $deps{$name} = [ %list ];
184}
84fb5b46
MKG
185
186$deps{'CORE'} = [ text_to_hash( << '.') ];
3ffc5f4f
MKG
187Apache::Session 1.53
188CGI 3.38
189CGI::Cookie 1.20
190CGI::Emulate::PSGI
191CGI::PSGI 0.12
84fb5b46 192Class::Accessor 0.34
3ffc5f4f
MKG
193Crypt::Eksblowfish
194CSS::Squish 0.06
195Data::GUID
196Date::Extract 0.02
197Date::Manip
84fb5b46 198DateTime 0.44
3ffc5f4f 199DateTime::Format::Natural 0.67
84fb5b46 200DateTime::Locale 0.40
3ffc5f4f
MKG
201DBI 1.37
202DBIx::SearchBuilder 1.65
203Devel::GlobalDestruction
204Devel::StackTrace 1.19
84fb5b46
MKG
205Digest::base
206Digest::MD5 2.27
207Digest::SHA
3ffc5f4f
MKG
208Email::Address 1.897
209Email::Address::List 0.02
210Encode 2.39
211Errno
212File::Glob
84fb5b46
MKG
213File::ShareDir
214File::Spec 0.8
3ffc5f4f
MKG
215File::Temp 0.19
216HTML::Entities
217HTML::FormatText::WithLinks 0.14
218HTML::FormatText::WithLinks::AndTables
219HTML::Mason 1.43
220HTML::Mason::PSGIHandler 0.52
84fb5b46 221HTML::Quoted
3ffc5f4f 222HTML::RewriteAttributes 0.05
84fb5b46 223HTML::Scrubber 0.08
3ffc5f4f
MKG
224HTTP::Message 6.0
225IPC::Run3
226JSON
227LWP::Simple
228List::MoreUtils
84fb5b46 229Locale::Maketext 1.06
3ffc5f4f 230Locale::Maketext::Fuzzy 0.11
84fb5b46 231Locale::Maketext::Lexicon 0.32
3ffc5f4f
MKG
232Log::Dispatch 2.30
233Mail::Header 2.12
84fb5b46 234Mail::Mailer 1.57
3ffc5f4f
MKG
235MIME::Entity 5.504
236Module::Refresh 0.03
84fb5b46 237Module::Versions::Report 1.05
84fb5b46 238Net::CIDR
3ffc5f4f
MKG
239Plack 1.0002
240Plack::Handler::Starlet
241Regexp::Common
84fb5b46
MKG
242Regexp::Common::net::CIDR
243Regexp::IPv6
3ffc5f4f
MKG
244Role::Basic 0.12
245Scalar::Util
84fb5b46 246Storable 2.08
3ffc5f4f
MKG
247Symbol::Global::Name 0.04
248Sys::Syslog 0.16
249Text::Password::Pronounceable
250Text::Quoted 2.07
251Text::Template 1.44
84fb5b46 252Text::WikiFormat 0.76
3ffc5f4f
MKG
253Text::Wrapper
254Time::HiRes
255Time::ParseDate
256Tree::Simple 1.04
257UNIVERSAL::require
258XML::RSS 1.05
84fb5b46 259.
3ffc5f4f
MKG
260set_dep( CORE => 'Symbol::Global::Name' => 0.05 ) if $] >= 5.019003;
261set_dep( CORE => CGI => 4.00 ) if $] > 5.019003;
84fb5b46
MKG
262
263$deps{'MAILGATE'} = [ text_to_hash( << '.') ];
84fb5b46 264Crypt::SSLeay
3ffc5f4f 265Getopt::Long
84fb5b46 266LWP::Protocol::https
3ffc5f4f 267LWP::UserAgent 6.0
84fb5b46 268Mozilla::CA
3ffc5f4f
MKG
269Net::SSL
270Pod::Usage
84fb5b46
MKG
271.
272
273$deps{'CLI'} = [ text_to_hash( << '.') ];
274Getopt::Long 2.24
84fb5b46 275HTTP::Request::Common
3ffc5f4f 276LWP
84fb5b46 277Term::ReadKey
3ffc5f4f
MKG
278Term::ReadLine
279Text::ParseWords
84fb5b46
MKG
280.
281
3ffc5f4f 282$deps{'DEVELOPER'} = [ text_to_hash( << '.') ];
84fb5b46 283Email::Abstract
84fb5b46 284File::Find
3ffc5f4f
MKG
285File::Which
286Locale::PO
84fb5b46 287Log::Dispatch::Perl
3ffc5f4f
MKG
288Mojo::DOM
289Plack::Middleware::Test::StashWarnings 0.08
290Set::Tiny
291String::ShellQuote 0 # needed for gnupg-incoming.t
84fb5b46 292Test::Builder 0.90 # needed for is_passing
3ffc5f4f
MKG
293Test::Deep 0 # needed for shredder tests
294Test::Email
295Test::Expect 0.31
84fb5b46 296Test::LongString
3ffc5f4f 297Test::MockTime
403d7b0b 298Test::NoWarnings
3ffc5f4f
MKG
299Test::Pod
300Test::Warn
301Test::WWW::Mechanize 1.30
302Test::WWW::Mechanize::PSGI
303WWW::Mechanize 1.52
304XML::Simple
84fb5b46
MKG
305.
306
307$deps{'FASTCGI'} = [ text_to_hash( << '.') ];
dab09ea8 308FCGI 0.74
84fb5b46
MKG
309FCGI::ProcManager
310.
311
312$deps{'MODPERL1'} = [ text_to_hash( << '.') ];
84fb5b46 313Apache::DBI 0.92
3ffc5f4f 314Apache::Request
84fb5b46
MKG
315.
316
317$deps{'MODPERL2'} = [ text_to_hash( << '.') ];
318Apache::DBI
84fb5b46
MKG
319.
320
321$deps{'MYSQL'} = [ text_to_hash( << '.') ];
322DBD::mysql 2.1018
323.
324
325$deps{'ORACLE'} = [ text_to_hash( << '.') ];
326DBD::Oracle
327.
328
3ffc5f4f
MKG
329$deps{'PG'} = [ text_to_hash( << '.') ];
330DBIx::SearchBuilder 1.66
84fb5b46
MKG
331DBD::Pg 1.43
332.
333
334$deps{'SQLITE'} = [ text_to_hash( << '.') ];
335DBD::SQLite 1.00
336.
337
338$deps{'GPG'} = [ text_to_hash( << '.') ];
3ffc5f4f 339File::Which
84fb5b46
MKG
340GnuPG::Interface
341PerlIO::eol
342.
343
3ffc5f4f
MKG
344$deps{'SMIME'} = [ text_to_hash( << '.') ];
345Crypt::X509
346File::Which
347String::ShellQuote
84fb5b46
MKG
348.
349
3ffc5f4f
MKG
350$deps{'ICAL'} = [ text_to_hash( << '.') ];
351Data::ICal
84fb5b46
MKG
352.
353
354$deps{'DASHBOARDS'} = [ text_to_hash( << '.') ];
84fb5b46 355MIME::Types
b5747ff2 356URI 1.59
3ffc5f4f 357URI::QueryParam
84fb5b46
MKG
358.
359
360$deps{'GRAPHVIZ'} = [ text_to_hash( << '.') ];
361GraphViz
dab09ea8 362IPC::Run 0.90
84fb5b46
MKG
363.
364
365$deps{'GD'} = [ text_to_hash( << '.') ];
366GD
3ffc5f4f 367GD::Graph 1.47
84fb5b46
MKG
368GD::Text
369.
370
371$deps{'USERLOGO'} = [ text_to_hash( << '.') ];
372Convert::Color
373.
374
dab09ea8 375$deps{'HTML-DOC'} = [ text_to_hash( <<'.') ];
dab09ea8 376HTML::Entities
3ffc5f4f 377Pod::Simple 3.24
dab09ea8
MKG
378.
379
84fb5b46
MKG
380my %AVOID = (
381 'DBD::Oracle' => [qw(1.23)],
403d7b0b 382 'Devel::StackTrace' => [qw(1.28 1.29)],
84fb5b46
MKG
383);
384
385if ($args{'download'}) {
386 download_mods();
387}
388
389
390check_perl_version();
391
392check_users();
393
394my %Missing_By_Type = ();
395foreach my $type (sort grep $args{$_}, keys %args) {
396 next unless ($type =~ /^with-(.*?)$/) and $deps{$1};
397
398 $type = $1;
399 section("$type dependencies");
400
401 my @missing;
402 my @deps = @{ $deps{$type} };
403
404 my %missing = test_deps(@deps);
405
406 if ( $args{'install'} ) {
407 for my $module (keys %missing) {
408 resolve_dep($module, $missing{$module}{version});
409 my $m = $module . '.pm';
410 $m =~ s!::!/!g;
411 if ( delete $INC{$m} ) {
412 my $symtab = $module . '::';
413 no strict 'refs';
414 for my $symbol ( keys %{$symtab} ) {
415 next if substr( $symbol, -2, 2 ) eq '::';
416 delete $symtab->{$symbol};
417 }
418 }
419 delete $missing{$module}
420 if test_dep($module, $missing{$module}{version}, $AVOID{$module});
421 }
422 }
423
424 $Missing_By_Type{$type} = \%missing if keys %missing;
425}
426
dab09ea8 427if ( $args{'install'} && keys %Missing_By_Type ) {
3ffc5f4f 428 exec($script_path, @orig_argv, '--no-install');
dab09ea8
MKG
429}
430else {
431 conclude(%Missing_By_Type);
432}
84fb5b46
MKG
433
434sub test_deps {
435 my @deps = @_;
436
437 my %missing;
438 while(@deps) {
439 my $module = shift @deps;
440 my $version = shift @deps;
441 my($test, $error) = test_dep($module, $version, $AVOID{$module});
442 my $msg = $module . ($version && !$error ? " >= $version" : '');
443 print_found($msg, $test, $error);
444
445 $missing{$module} = { version => $version, error => $error } unless $test;
446 }
447
448 return %missing;
449}
450
451sub test_dep {
452 my $module = shift;
453 my $version = shift;
454 my $avoid = shift;
455
456 if ( $args{'list-deps'} ) {
457 print $module, ': ', $version || 0, "\n";
458 }
459 else {
3ffc5f4f
MKG
460 no warnings 'deprecated';
461 eval "{ local \$ENV{__WARN__}; use $module $version () }";
84fb5b46
MKG
462 if ( my $error = $@ ) {
463 return 0 unless wantarray;
464
465 $error =~ s/\n(.*)$//s;
466 $error =~ s/at \(eval \d+\) line \d+\.$//;
467 undef $error if $error =~ /this is only/;
468
3ffc5f4f
MKG
469 my $path = $module;
470 $path =~ s{::}{/}g;
471 undef $error if defined $error and $error =~ /^Can't locate $path\.pm in \@INC/;
472
84fb5b46
MKG
473 return ( 0, $error );
474 }
475
476 if ( $avoid ) {
477 my $version = $module->VERSION;
478 if ( grep $version eq $_, @$avoid ) {
479 return 0 unless wantarray;
480 return (0, "It's known that there are problems with RT and version '$version' of '$module' module. If it's the latest available version of the module then you have to downgrade manually.");
481 }
482 }
483
484 return 1;
485 }
486}
487
488sub resolve_dep {
489 my $module = shift;
490 my $version = shift;
491
492 print "\nInstall module $module\n";
493
494 my $ext = $ENV{'RT_FIX_DEPS_CMD'} || $ENV{'PERL_PREFER_CPAN_CLIENT'};
495 unless( $ext ) {
496 my $configured = 1;
497 {
498 local @INC = @INC;
499 if ( $ENV{'HOME'} ) {
500 unshift @INC, "$ENV{'HOME'}/.cpan";
501 }
502 $configured = eval { require CPAN::MyConfig } || eval { require CPAN::Config };
503 }
504 unless ( $configured ) {
505 print <<END;
506You haven't configured the CPAN shell yet.
507Please run `/usr/bin/perl -MCPAN -e shell` to configure it.
508END
509 exit(1);
510 }
511 my $rv = eval { require CPAN; CPAN::Shell->install($module) };
512 return $rv unless $@;
513
514 print <<END;
515Failed to load module CPAN.
516
517-------- Error ---------
518$@
519------------------------
520
521When we tried to start installing RT's perl dependencies,
522we were unable to load the CPAN client. This module is usually distributed
523with Perl. This usually indicates that your vendor has shipped an unconfigured
524or incorrectly configured CPAN client.
525The error above may (or may not) give you a hint about what went wrong
526
527You have several choices about how to install dependencies in
528this situatation:
529
5301) use a different tool to install dependencies by running setting the following
531 shell environment variable and rerunning this tool:
532 RT_FIX_DEPS_CMD='/usr/bin/perl -MCPAN -e"install %s"'
5332) Attempt to configure CPAN by running:
534 `/usr/bin/perl -MCPAN -e shell` program from shell.
535 If this fails, you may have to manually upgrade CPAN (see below)
5363) Try to update the CPAN client. Download it from:
537 http://search.cpan.org/dist/CPAN and try again
5384) Install each dependency manually by downloading them one by one from
539 http://search.cpan.org
540
541END
542 exit(1);
543 }
544
545 if( $ext =~ /\%s/) {
546 $ext =~ s/\%s/$module/g; # sprintf( $ext, $module );
547 } else {
548 $ext .= " $module";
549 }
550 print "\t\tcommand: '$ext'\n";
551 return scalar `$ext 1>&2`;
552}
553
84fb5b46
MKG
554sub check_perl_version {
555 section("perl");
3ffc5f4f 556 eval {require 5.010_001};
84fb5b46 557 if ($@) {
3ffc5f4f 558 print_found("5.10.1", 0, sprintf("RT requires Perl v5.10.1 or newer. Your current Perl is v%vd", $^V));
84fb5b46
MKG
559 exit(1);
560 } else {
3ffc5f4f 561 print_found( sprintf(">=5.10.1(%vd)", $^V), 1 );
84fb5b46
MKG
562 }
563}
564
565sub check_users {
566 section("users");
567 print_found("rt group (uio-rt)", defined getgrnam("uio-rt"));
568 print_found("bin owner (root)", defined getpwnam("root"));
569 print_found("libs owner (root)", defined getpwnam("root"));
570 print_found("libs group (bin)", defined getgrnam("bin"));
571 print_found("web owner (httpd)", defined getpwnam("httpd"));
572 print_found("web group (httpd)", defined getgrnam("httpd"));
573}
574
5751;
576
577__END__
578
579=head1 NAME
580
581rt-test-dependencies - test rt's dependencies
582
583=head1 SYNOPSIS
584
585 rt-test-dependencies
586 rt-test-dependencies --install
587 rt-test-dependencies --with-mysql --with-fastcgi
588
589=head1 DESCRIPTION
590
591by default, C<rt-test-dependencies> determines whether you have installed all
592the perl modules RT needs to run.
593
594the "RT_FIX_DEPS_CMD" environment variable, if set, will be used instead of
595the standard CPAN shell by --install to install any required modules. it will
596be called with the module name, or, if "RT_FIX_DEPS_CMD" contains a "%s", will
597replace the "%s" with the module name before calling the program.
598
599=head1 OPTIONS
600
601=over
602
603=item install
604
605 install missing modules
606
607=item verbose
608
609list the status of all dependencies, rather than just the missing ones.
610
611-v is equal to --verbose
612
613=item specify dependencies
614
615=over
616
617=item --with-mysql
618
3ffc5f4f
MKG
619database interface for mysql
620
621=item --with-pg
84fb5b46 622
3ffc5f4f 623database interface for postgresql
84fb5b46 624
3ffc5f4f 625=item --with-oracle
84fb5b46 626
3ffc5f4f 627database interface for oracle
84fb5b46 628
3ffc5f4f 629=item --with-sqlite
84fb5b46 630
3ffc5f4f 631database interface and driver for sqlite (unsupported)
84fb5b46 632
3ffc5f4f 633=item --with-fastcgi
84fb5b46 634
3ffc5f4f 635libraries needed to support the fastcgi handler
84fb5b46 636
3ffc5f4f 637=item --with-modperl1
84fb5b46 638
3ffc5f4f 639libraries needed to support the modperl 1 handler
84fb5b46 640
3ffc5f4f 641=item --with-modperl2
84fb5b46 642
3ffc5f4f 643libraries needed to support the modperl 2 handler
84fb5b46 644
3ffc5f4f 645=item --with-developer
84fb5b46 646
3ffc5f4f 647tools needed for RT development
84fb5b46
MKG
648
649=back
650
651=back
652