Dev to 4.0.11
[usit-rt.git] / sbin / rt-test-dependencies
CommitLineData
84fb5b46
MKG
1#!/usr/bin/perl
2# BEGIN BPS TAGGED BLOCK {{{
3#
4# COPYRIGHT:
5#
403d7b0b 6# This software is Copyright (c) 1996-2013 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;
58my %args;
59my %deps;
dab09ea8 60my @orig_argv = @ARGV;
84fb5b46
MKG
61GetOptions(
62 \%args, 'v|verbose',
dab09ea8 63 'install!', 'with-MYSQL',
84fb5b46
MKG
64 'with-POSTGRESQL|with-pg|with-pgsql', 'with-SQLITE',
65 'with-ORACLE', 'with-FASTCGI',
66 'with-MODPERL1', 'with-MODPERL2',
67 'with-STANDALONE',
68
69 'with-DEV',
70
71 'with-GPG',
72 'with-ICAL',
73 'with-SMTP',
74 'with-GRAPHVIZ',
75 'with-GD',
76 'with-DASHBOARDS',
77 'with-USERLOGO',
78 'with-SSL-MAILGATE',
dab09ea8 79 'with-HTML-DOC',
84fb5b46
MKG
80
81 'download=s',
82 'repository=s',
83 'list-deps',
84 'help|h',
85);
86
87if ( $args{help} ) {
88 require Pod::Usage;
89 Pod::Usage::pod2usage( { verbose => 2 } );
90 exit;
91}
92
93# Set up defaults
94my %default = (
95 'with-MASON' => 1,
96 'with-PSGI' => 1,
97 'with-CORE' => 1,
98 'with-CLI' => 1,
99 'with-MAILGATE' => 1,
100 'with-DEV' => 0,
101 'with-GPG' => 0,
102 'with-ICAL' => 1,
103 'with-SMTP' => 1,
104 'with-GRAPHVIZ' => 0,
105 'with-GD' => 1,
106 'with-DASHBOARDS' => 1,
107 'with-USERLOGO' => 1,
108 'with-SSL-MAILGATE' => 0,
dab09ea8 109 'with-HTML-DOC' => 0,
84fb5b46
MKG
110);
111$args{$_} = $default{$_} foreach grep !exists $args{$_}, keys %default;
112
113{
114 my $section;
115 my %always_show_sections = (
116 perl => 1,
117 users => 1,
118 );
119
120 sub section {
121 my $s = shift;
122 $section = $s;
123 print "$s:\n" unless $args{'list-deps'};
124 }
125
126 sub print_found {
127 my $msg = shift;
128 my $test = shift;
129 my $extra = shift;
130
131 unless ( $args{'list-deps'} ) {
132 if ( $args{'v'} or not $test or $always_show_sections{$section} ) {
133 print "\t$msg ...";
134 print $test ? "found" : "MISSING";
135 print "\n";
136 }
137
138 print "\t\t$extra\n" if defined $extra;
139 }
140 }
141}
142
143sub conclude {
144 my %missing_by_type = @_;
145
146 unless ( $args{'list-deps'} ) {
147 unless ( keys %missing_by_type ) {
148 print "\nAll dependencies have been found.\n";
149 return;
150 }
151
152 print "\nSOME DEPENDENCIES WERE MISSING.\n";
153
154 for my $type ( keys %missing_by_type ) {
155 my $missing = $missing_by_type{$type};
156
157 print "$type missing dependencies:\n";
158 for my $name ( keys %$missing ) {
159 my $module = $missing->{$name};
160 my $version = $module->{version};
161 my $error = $module->{error};
162 print_found( $name . ( $version && !$error ? " >= $version" : "" ),
163 0, $module->{error} );
164 }
165 }
166 exit 1;
167 }
168}
169
170sub text_to_hash {
171 my %hash;
172 for my $line ( split /\n/, $_[0] ) {
173 my($key, $value) = $line =~ /(\S+)\s*(\S*)/;
174 $value ||= '';
175 $hash{$key} = $value;
176 }
177
178 return %hash;
179}
180
181$deps{'CORE'} = [ text_to_hash( << '.') ];
182Class::Accessor 0.34
183DateTime 0.44
184DateTime::Locale 0.40
185Digest::base
186Digest::MD5 2.27
187Digest::SHA
188DBI 1.37
189Class::ReturnValue 0.40
190DBIx::SearchBuilder 1.59
191Text::Template 1.44
192File::ShareDir
193File::Spec 0.8
194HTML::Quoted
195HTML::Scrubber 0.08
b5747ff2
MKG
196HTML::TreeBuilder
197HTML::FormatText
84fb5b46
MKG
198Log::Dispatch 2.23
199Sys::Syslog 0.16
200Locale::Maketext 1.06
201Locale::Maketext::Lexicon 0.32
202Locale::Maketext::Fuzzy
203MIME::Entity 5.425
204Mail::Mailer 1.57
205Email::Address
206Text::Wrapper
207Time::ParseDate
208Time::HiRes
209File::Temp 0.19
210Text::Quoted 2.02
211Tree::Simple 1.04
212UNIVERSAL::require
213Regexp::Common
214Scalar::Util
215Module::Versions::Report 1.05
216Cache::Simple::TimedExpiry
217Encode 2.39
218CSS::Squish 0.06
219File::Glob
220Devel::StackTrace 1.19
221Text::Password::Pronounceable
222Devel::GlobalDestruction
223List::MoreUtils
224Net::CIDR
225Regexp::Common::net::CIDR
226Regexp::IPv6
227.
228
229$deps{'MASON'} = [ text_to_hash( << '.') ];
230HTML::Mason 1.43
231Errno
232Digest::MD5 2.27
233CGI::Cookie 1.20
234Storable 2.08
235Apache::Session 1.53
236XML::RSS 1.05
237Text::WikiFormat 0.76
238CSS::Squish 0.06
239Devel::StackTrace 1.19
240JSON
241IPC::Run3
242.
243
244$deps{'PSGI'} = [ text_to_hash( << '.') ];
245CGI 3.38
246CGI::PSGI 0.12
247HTML::Mason::PSGIHandler 0.52
248Plack 0.9971
249Plack::Handler::Starlet
250CGI::Emulate::PSGI
251.
252
253$deps{'MAILGATE'} = [ text_to_hash( << '.') ];
84fb5b46
MKG
254Getopt::Long
255LWP::UserAgent
256Pod::Usage
257.
258
259$deps{'SSL-MAILGATE'} = [ text_to_hash( << '.') ];
260Crypt::SSLeay
261Net::SSL
262LWP::UserAgent 6.0
263LWP::Protocol::https
264Mozilla::CA
265.
266
267$deps{'CLI'} = [ text_to_hash( << '.') ];
268Getopt::Long 2.24
269LWP
270HTTP::Request::Common
271Text::ParseWords
272Term::ReadLine
273Term::ReadKey
274.
275
276$deps{'DEV'} = [ text_to_hash( << '.') ];
277Email::Abstract
278Test::Email
279HTML::Form
280HTML::TokeParser
281WWW::Mechanize 1.52
282Test::WWW::Mechanize 1.30
283Module::Refresh 0.03
284Test::Expect 0.31
285XML::Simple
286File::Find
287Test::Deep 0 # needed for shredder tests
288String::ShellQuote 0 # needed for gnupg-incoming.t
289Log::Dispatch::Perl
290Test::Warn
291Test::Builder 0.90 # needed for is_passing
292Test::MockTime
293Log::Dispatch::Perl
294Test::WWW::Mechanize::PSGI
b5747ff2 295Plack::Middleware::Test::StashWarnings 0.06
84fb5b46 296Test::LongString
403d7b0b 297Test::NoWarnings
84fb5b46
MKG
298.
299
300$deps{'FASTCGI'} = [ text_to_hash( << '.') ];
dab09ea8 301FCGI 0.74
84fb5b46
MKG
302FCGI::ProcManager
303.
304
305$deps{'MODPERL1'} = [ text_to_hash( << '.') ];
306Apache::Request
307Apache::DBI 0.92
308.
309
310$deps{'MODPERL2'} = [ text_to_hash( << '.') ];
311Apache::DBI
312HTML::Mason 1.36
313.
314
315$deps{'MYSQL'} = [ text_to_hash( << '.') ];
316DBD::mysql 2.1018
317.
318
319$deps{'ORACLE'} = [ text_to_hash( << '.') ];
320DBD::Oracle
321.
322
323$deps{'POSTGRESQL'} = [ text_to_hash( << '.') ];
324DBD::Pg 1.43
325.
326
327$deps{'SQLITE'} = [ text_to_hash( << '.') ];
328DBD::SQLite 1.00
329.
330
331$deps{'GPG'} = [ text_to_hash( << '.') ];
332GnuPG::Interface
333PerlIO::eol
334.
335
336$deps{'ICAL'} = [ text_to_hash( << '.') ];
337Data::ICal
338.
339
340$deps{'SMTP'} = [ text_to_hash( << '.') ];
341Net::SMTP
342.
343
344$deps{'DASHBOARDS'} = [ text_to_hash( << '.') ];
403d7b0b 345HTML::RewriteAttributes 0.05
84fb5b46 346MIME::Types
b5747ff2 347URI 1.59
84fb5b46
MKG
348.
349
350$deps{'GRAPHVIZ'} = [ text_to_hash( << '.') ];
351GraphViz
dab09ea8 352IPC::Run 0.90
84fb5b46
MKG
353.
354
355$deps{'GD'} = [ text_to_hash( << '.') ];
356GD
357GD::Graph
358GD::Text
359.
360
361$deps{'USERLOGO'} = [ text_to_hash( << '.') ];
362Convert::Color
363.
364
dab09ea8 365$deps{'HTML-DOC'} = [ text_to_hash( <<'.') ];
c36a7e1d 366Pod::Simple 3.24
dab09ea8
MKG
367HTML::Entities
368.
369
84fb5b46
MKG
370my %AVOID = (
371 'DBD::Oracle' => [qw(1.23)],
dab09ea8 372 'Email::Address' => [qw(1.893 1.894)],
403d7b0b 373 'Devel::StackTrace' => [qw(1.28 1.29)],
84fb5b46
MKG
374);
375
376if ($args{'download'}) {
377 download_mods();
378}
379
380
381check_perl_version();
382
383check_users();
384
385my %Missing_By_Type = ();
386foreach my $type (sort grep $args{$_}, keys %args) {
387 next unless ($type =~ /^with-(.*?)$/) and $deps{$1};
388
389 $type = $1;
390 section("$type dependencies");
391
392 my @missing;
393 my @deps = @{ $deps{$type} };
394
395 my %missing = test_deps(@deps);
396
397 if ( $args{'install'} ) {
398 for my $module (keys %missing) {
399 resolve_dep($module, $missing{$module}{version});
400 my $m = $module . '.pm';
401 $m =~ s!::!/!g;
402 if ( delete $INC{$m} ) {
403 my $symtab = $module . '::';
404 no strict 'refs';
405 for my $symbol ( keys %{$symtab} ) {
406 next if substr( $symbol, -2, 2 ) eq '::';
407 delete $symtab->{$symbol};
408 }
409 }
410 delete $missing{$module}
411 if test_dep($module, $missing{$module}{version}, $AVOID{$module});
412 }
413 }
414
415 $Missing_By_Type{$type} = \%missing if keys %missing;
416}
417
dab09ea8
MKG
418if ( $args{'install'} && keys %Missing_By_Type ) {
419 exec($0, @orig_argv, '--no-install');
420}
421else {
422 conclude(%Missing_By_Type);
423}
84fb5b46
MKG
424
425sub test_deps {
426 my @deps = @_;
427
428 my %missing;
429 while(@deps) {
430 my $module = shift @deps;
431 my $version = shift @deps;
432 my($test, $error) = test_dep($module, $version, $AVOID{$module});
433 my $msg = $module . ($version && !$error ? " >= $version" : '');
434 print_found($msg, $test, $error);
435
436 $missing{$module} = { version => $version, error => $error } unless $test;
437 }
438
439 return %missing;
440}
441
442sub test_dep {
443 my $module = shift;
444 my $version = shift;
445 my $avoid = shift;
446
447 if ( $args{'list-deps'} ) {
448 print $module, ': ', $version || 0, "\n";
449 }
450 else {
451 eval "use $module $version ()";
452 if ( my $error = $@ ) {
453 return 0 unless wantarray;
454
455 $error =~ s/\n(.*)$//s;
456 $error =~ s/at \(eval \d+\) line \d+\.$//;
457 undef $error if $error =~ /this is only/;
458
459 return ( 0, $error );
460 }
461
462 if ( $avoid ) {
463 my $version = $module->VERSION;
464 if ( grep $version eq $_, @$avoid ) {
465 return 0 unless wantarray;
466 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.");
467 }
468 }
469
470 return 1;
471 }
472}
473
474sub resolve_dep {
475 my $module = shift;
476 my $version = shift;
477
478 print "\nInstall module $module\n";
479
480 my $ext = $ENV{'RT_FIX_DEPS_CMD'} || $ENV{'PERL_PREFER_CPAN_CLIENT'};
481 unless( $ext ) {
482 my $configured = 1;
483 {
484 local @INC = @INC;
485 if ( $ENV{'HOME'} ) {
486 unshift @INC, "$ENV{'HOME'}/.cpan";
487 }
488 $configured = eval { require CPAN::MyConfig } || eval { require CPAN::Config };
489 }
490 unless ( $configured ) {
491 print <<END;
492You haven't configured the CPAN shell yet.
493Please run `/usr/bin/perl -MCPAN -e shell` to configure it.
494END
495 exit(1);
496 }
497 my $rv = eval { require CPAN; CPAN::Shell->install($module) };
498 return $rv unless $@;
499
500 print <<END;
501Failed to load module CPAN.
502
503-------- Error ---------
504$@
505------------------------
506
507When we tried to start installing RT's perl dependencies,
508we were unable to load the CPAN client. This module is usually distributed
509with Perl. This usually indicates that your vendor has shipped an unconfigured
510or incorrectly configured CPAN client.
511The error above may (or may not) give you a hint about what went wrong
512
513You have several choices about how to install dependencies in
514this situatation:
515
5161) use a different tool to install dependencies by running setting the following
517 shell environment variable and rerunning this tool:
518 RT_FIX_DEPS_CMD='/usr/bin/perl -MCPAN -e"install %s"'
5192) Attempt to configure CPAN by running:
520 `/usr/bin/perl -MCPAN -e shell` program from shell.
521 If this fails, you may have to manually upgrade CPAN (see below)
5223) Try to update the CPAN client. Download it from:
523 http://search.cpan.org/dist/CPAN and try again
5244) Install each dependency manually by downloading them one by one from
525 http://search.cpan.org
526
527END
528 exit(1);
529 }
530
531 if( $ext =~ /\%s/) {
532 $ext =~ s/\%s/$module/g; # sprintf( $ext, $module );
533 } else {
534 $ext .= " $module";
535 }
536 print "\t\tcommand: '$ext'\n";
537 return scalar `$ext 1>&2`;
538}
539
540sub download_mods {
541 my %modules;
542 use CPAN;
543
544 foreach my $key (keys %deps) {
545 my @deps = (@{$deps{$key}});
546 while (@deps) {
547 my $mod = shift @deps;
548 my $ver = shift @deps;
549 next if ($mod =~ /^(DBD-|Apache-Request)/);
550 $modules{$mod} = $ver;
551 }
552 }
553 my @mods = keys %modules;
554 CPAN::get();
555 my $moddir = $args{'download'};
556 foreach my $mod (@mods) {
557 $CPAN::Config->{'build_dir'} = $moddir;
558 CPAN::get($mod);
559 }
560
561 opendir(DIR, $moddir);
562 while ( my $dir = readdir(DIR)) {
563 print "Dir is $dir\n";
564 next if ( $dir =~ /^\.\.?$/);
565
566 # Skip things we've previously tagged
567 my $out = `svn ls $args{'repository'}/tags/$dir`;
568 next if ($out);
569
570 if ($dir =~ /^(.*)-(.*?)$/) {
571 `svn_load_dirs -no_user_input -t tags/$dir -v $args{'repository'} dists/$1 $moddir/$dir`;
572 `rm -rf $moddir/$dir`;
573
574 }
575
576 }
577 closedir(DIR);
578 exit;
579}
580
581sub check_perl_version {
582 section("perl");
583 eval {require 5.008003};
584 if ($@) {
585 print_found("5.8.3", 0,"RT is known to be non-functional on versions of perl older than 5.8.3. Please upgrade to 5.8.3 or newer.");
586 exit(1);
587 } else {
588 print_found( sprintf(">=5.8.3(%vd)", $^V), 1 );
589 }
590}
591
592sub check_users {
593 section("users");
594 print_found("rt group (uio-rt)", defined getgrnam("uio-rt"));
595 print_found("bin owner (root)", defined getpwnam("root"));
596 print_found("libs owner (root)", defined getpwnam("root"));
597 print_found("libs group (bin)", defined getgrnam("bin"));
598 print_found("web owner (httpd)", defined getpwnam("httpd"));
599 print_found("web group (httpd)", defined getgrnam("httpd"));
600}
601
6021;
603
604__END__
605
606=head1 NAME
607
608rt-test-dependencies - test rt's dependencies
609
610=head1 SYNOPSIS
611
612 rt-test-dependencies
613 rt-test-dependencies --install
614 rt-test-dependencies --with-mysql --with-fastcgi
615
616=head1 DESCRIPTION
617
618by default, C<rt-test-dependencies> determines whether you have installed all
619the perl modules RT needs to run.
620
621the "RT_FIX_DEPS_CMD" environment variable, if set, will be used instead of
622the standard CPAN shell by --install to install any required modules. it will
623be called with the module name, or, if "RT_FIX_DEPS_CMD" contains a "%s", will
624replace the "%s" with the module name before calling the program.
625
626=head1 OPTIONS
627
628=over
629
630=item install
631
632 install missing modules
633
634=item verbose
635
636list the status of all dependencies, rather than just the missing ones.
637
638-v is equal to --verbose
639
640=item specify dependencies
641
642=over
643
644=item --with-mysql
645
646 database interface for mysql
647
648=item --with-postgresql
649
650 database interface for postgresql
651
652=item with-oracle
653
654 database interface for oracle
655
656=item with-sqlite
657
658 database interface and driver for sqlite (unsupported)
659
660=item with-fastcgi
661
662 libraries needed to support the fastcgi handler
663
664=item with-modperl1
665
666 libraries needed to support the modperl 1 handler
667
668=item with-modperl2
669
670 libraries needed to support the modperl 2 handler
671
672=item with-dev
673
674 tools needed for RT development
675
676=back
677
678=back
679