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