import rt 3.6.4
[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-2007 Best Practical Solutions, LLC 
7 #                                          <jesse@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/copyleft/gpl.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 GetOptions(
60     \%args,                               'v|verbose',
61     'install',                            'with-MYSQL',
62     'with-POSTGRESQL|with-pg|with-pgsql', 'with-SQLITE',
63     'with-ORACLE',                        'with-FASTCGI',
64     'with-SPEEDYCGI',                     'with-MODPERL1',
65     'with-MODPERL2',                      'with-DEV',
66     'with-STANDALONE',
67     'download=s',
68     'repository=s'
69 );
70
71 unless (keys %args) {
72     help();
73     exit(0);
74 }
75 # Set up defaults
76 my %default = (
77     'with-MASON' => 1,
78     'with-CORE' => 1,
79     'with-CLI' => 1,
80     'with-MAILGATE' => 1, 
81     'with-DEV' => @RT_DEVEL_MODE@, 
82     'with-STANDALONE' => @RT_STANDALONE@,
83 );
84 $args{$_} = $default{$_} foreach grep !exists $args{$_}, keys %default;
85
86 use Data::Dumper;
87 print Dumper( \%args );
88
89 {
90   my $section;
91   my %always_show_sections = (
92     perl => 1,
93     users => 1,
94   );
95
96   sub section {
97     my $s = shift;
98     $section = $s;
99     print "$s:\n";
100   }
101
102   my $any_missing = 0;
103   sub found {
104     my $msg = shift;
105     my $test = shift;
106     my $extra = shift;
107   
108     $any_missing = 1 unless $test;
109     if ($args{'v'} or not $test or $always_show_sections{$section}) {
110       print "\t$msg...";
111       print $test ? "found" : "MISSING";
112       print "\n";
113     }
114     
115     print "\t\t$extra\n" if defined $extra;
116   }
117
118   sub conclude {
119     if ($any_missing) {
120       print "\nSOMETHING WAS MISSING!\n";
121     } else {
122       print "\nEverything was found.\n";
123     }
124   }
125 }
126
127 sub help {
128
129     print <<'.';
130
131 By default, testdeps determine whether you have 
132 installed all the perl modules RT needs to run.
133
134         --install               Install missing modules
135
136 The following switches will tell the tool to check for specific dependencies
137
138         --with-mysql            Database interface for MySQL
139         --with-postgresql       Database interface for PostgreSQL 
140         --with-sqlite           Database interface and driver for SQLite (unsupported)
141         --with-oracle           Database interface for oracle (unsupported)
142
143         --with-standalone       Libraries needed to support the standalone simple pure perl server
144         --with-fastcgi          Libraries needed to support the fastcgi handler
145         --with-speedycgi        Libraries needed to support the speedycgi handler
146         --with-modperl1         Libraries needed to support the modperl 1 handler
147         --with-modperl2         Libraries needed to support the modperl 2 handler
148
149         --with-dev              Tools needed for RT development
150
151 You can also specify -v or --verbose to list the status of all dependencies,
152 rather than just the missing ones.
153
154 The "RT_FIX_DEPS_CMD" environment variable, if set, will be used
155 instead of the standard CPAN shell by --install to install any
156 required modules.  It will be called with the module name, or, if
157 "RT_FIX_DEPS_CMD" contains a "%s", will replace the "%s" with the
158 module name before calling the program.
159 .
160 }
161
162
163 sub text_to_hash {
164     my %hash;
165     for my $line ( split /\n/, $_[0] ) {
166         my($key, $value) = $line =~ /(\S+)\s*(\S*)/;
167         $value ||= '';
168         $hash{$key} = $value;
169     }
170
171     return %hash;
172 }
173
174 $deps{'CORE'} = [ text_to_hash( << '.') ];
175 Digest::base
176 Digest::MD5 2.27
177 DBI 1.37
178 Class::ReturnValue 0.40
179 Date::Format
180 DBIx::SearchBuilder 1.48
181 Text::Template
182 File::Spec 0.8
183 HTML::Entities 
184 HTML::Scrubber 0.08
185 Log::Dispatch 2.0
186 Locale::Maketext 1.06
187 Locale::Maketext::Lexicon 0.32
188 Locale::Maketext::Fuzzy
189 MIME::Entity 5.108
190 Mail::Mailer 1.57
191 Net::SMTP
192 Text::Wrapper 
193 Time::ParseDate
194 Time::HiRes 
195 File::Temp
196 Text::Autoformat
197 Text::Quoted 2.02
198 Tree::Simple 1.04
199 Regexp::Common
200 Scalar::Util
201 Module::Versions::Report 1.03
202 Cache::Simple::TimedExpiry
203 UNIVERSAL::require
204 Calendar::Simple
205 .
206
207 $deps{'MASON'} = [ text_to_hash( << '.') ];
208 HTML::Mason 1.23
209 Errno
210 Digest::MD5 2.27
211 CGI::Cookie 1.20
212 Storable 2.08
213 Apache::Session 1.53
214 XML::RSS 1.05
215 GD
216 GD::Graph
217 GD::Text
218 Text::WikiFormat 0.76
219 .
220
221 $deps{'STANDALONE'} = [ text_to_hash( << '.') ];
222 HTTP::Server::Simple 0.07
223 HTTP::Server::Simple::Mason 0.09
224 .
225
226 $deps{'MAILGATE'} = [ text_to_hash( << '.') ];
227 HTML::TreeBuilder
228 HTML::FormatText
229 Getopt::Long
230 LWP::UserAgent
231 Pod::Usage
232 .
233
234 $deps{'CLI'} = [ text_to_hash( << '.') ];
235 Getopt::Long 2.24
236 LWP
237 HTTP::Request::Common
238 Text::ParseWords
239 Term::ReadLine
240 Term::ReadKey
241 .
242
243 $deps{'DEV'} = [ text_to_hash( << '.') ];
244 Test::Inline 
245 Apache::Test
246 HTML::Form
247 HTML::TokeParser
248 WWW::Mechanize
249 Test::WWW::Mechanize 1.04
250 Module::Refresh 0.03
251 Test::Expect 0.30
252 XML::Simple
253 File::Find
254 .
255
256 $deps{'FASTCGI'} = [ text_to_hash( << '.') ];
257 CGI 2.92
258 FCGI
259 CGI::Fast 
260 .
261
262 $deps{'SPEEDYCGI'} = [ text_to_hash( << '.') ];
263 CGI 2.92
264 CGI::SpeedyCGI
265 .
266
267
268 $deps{'MODPERL1'} = [ text_to_hash( << '.') ];
269 CGI 2.92
270 Apache::Request
271 Apache::DBI 0.92
272 .
273
274 $deps{'MODPERL2'} = [ text_to_hash( << '.') ];
275 CGI 2.92
276 Apache::DBI
277 HTML::Mason 1.31
278 .
279
280 $deps{'MYSQL'} = [ text_to_hash( << '.') ];
281 DBD::mysql 2.1018
282 .
283 $deps{'ORACLE'} = [ text_to_hash( << '.') ];
284 DBD::Oracle
285 .
286 $deps{'POSTGRESQL'} = [ text_to_hash( << '.') ];
287 DBD::Pg 1.43
288 .
289
290 $deps{'SQLITE'} = [ text_to_hash( << '.') ];
291 DBD::SQLite 1.00
292 .
293
294 if ($args{'download'}) {
295
296     download_mods();
297 }
298
299
300 check_perl_version();
301
302 check_users();
303
304
305 foreach my $type (sort grep $args{$_}, keys %args) {
306     next unless ($type =~ /^with-(.*?)$/);
307
308     $type = $1;
309     section("$type dependencies");
310
311     my @missing;
312     my @deps = @{ $deps{$type} };
313     while (@deps) {
314         my $module = shift @deps;
315         my $version = shift @deps;
316         my $ret = test_dep($module, $version);
317
318         push @missing, $module, $version unless $ret;
319     }
320     if ( $args{'install'} ) {
321         while( @missing ) {
322             resolve_dep(shift @missing, shift @missing);
323         }
324     }
325 }
326
327 conclude();
328
329 sub test_dep {
330     my $module = shift;
331     my $version = shift;
332
333     eval "use $module $version ()";
334     if ($@) {
335         my $error = $@;
336         $error =~ s/\n(.*)$//s;
337         undef $error unless $error =~ /this is only/;
338         found("$module $version", 0, $error);
339
340         return undef;
341     } else {
342         my $msg = "$module";
343         $msg .= " >=$version" if $version;
344         found($msg, 1);
345         return 1;
346     }
347 }
348
349 sub resolve_dep {
350     my $module = shift;
351     my $version = shift;
352
353     print "\nInstall module $module\n";
354
355     my $ext = $ENV{'RT_FIX_DEPS_CMD'};
356     unless( $ext ) {
357         my $configured = 1;
358         {
359             local @INC = @INC;
360             if ( $ENV{'HOME'} ) {
361                 unshift @INC, "$ENV{'HOME'}/.cpan";
362             }
363             $configured = eval { require CPAN::MyConfig } || eval { require CPAN::Config };
364         }
365         unless ( $configured ) {
366             print <<END;
367 You didn't configure CPAN shell yet.
368 Please run `@PERL@ -MCPAN -e shell` tool and configure it.
369 END
370             exit(1);
371         }
372         my $rv = eval { require CPAN; CPAN::Shell->install($module) };
373         return $rv unless $@;
374
375         print <<END;
376 Failed to load module CPAN.
377
378 -------- Error ---------
379 $@
380 ------------------------
381
382 When we tried to start installing RT's perl dependencies, 
383 we were unable to load the CPAN client. This module is usually distributed
384 with Perl. This usually indicates that your vendor has shipped an unconfigured
385 or incorrectly configured CPAN client.
386 The error above may (or may not) give you a hint about what went wrong
387
388 You have several choices about how to install dependencies in 
389 this situatation:
390
391 1) use a different tool to install dependencies by running setting the following
392    shell environment variable and rerunning this tool:
393     RT_FIX_DEPS_CMD='@PERL@ -MCPAN -e"install %s"'
394 2) Attempt to configure CPAN by running:
395    `@PERL@ -MCPAN -e shell` program from shell.
396    If this fails, you may have to manually upgrade CPAN (see below)
397 3) Try to update the CPAN client. Download it from:
398    http://search.cpan.org/dist/CPAN and try again
399 4) Install each dependency manually by downloading them one by one from
400    http://search.cpan.org
401
402 END
403         exit(1);
404     }
405
406     if( $ext =~ /\%s/) {
407         $ext =~ s/\%s/$module/g; # sprintf( $ext, $module );
408     } else {
409         $ext .= " $module";
410     }
411     print "\t\tcommand: '$ext'\n";
412     return scalar `$ext 1>&2`;
413 }
414
415 sub download_mods {
416     my %modules;
417     use CPAN;
418     
419     foreach my $key (keys %deps) {
420         my @deps = (@{$deps{$key}});
421         while (@deps) {
422             my $mod = shift @deps;
423             my $ver = shift @deps;
424             next if ($mod =~ /^(DBD-|Apache-Request)/);
425             $modules{$mod} = $ver;
426         }
427     }
428     my @mods = keys %modules;
429     CPAN::get();
430     my $moddir = $args{'download'};
431     foreach my $mod (@mods) {
432         $CPAN::Config->{'build_dir'} = $moddir;
433         CPAN::get($mod);
434     }
435
436     opendir(DIR, $moddir);
437     while ( my $dir = readdir(DIR)) {
438         print "Dir is $dir\n";
439         next if ( $dir =~ /^\.\.?$/);
440
441         # Skip things we've previously tagged
442         my $out = `svn ls $args{'repository'}/tags/$dir`;
443         next if ($out);
444
445         if ($dir =~ /^(.*)-(.*?)$/) {
446             `svn_load_dirs -no_user_input -t tags/$dir -v $args{'repository'} dists/$1 $moddir/$dir`;
447             `rm -rf $moddir/$dir`;
448
449         }
450
451     }
452     closedir(DIR);
453     exit;
454 }
455
456 sub check_perl_version {
457   section("perl");
458   eval {require 5.008003};
459   if ($@) {
460     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.");
461     exit(1);
462   } else {
463     found( ">=5.8.3($])", 1);
464   }
465 }
466
467 sub check_users {
468   section("users");
469   found("rt group (@RTGROUP@)",      defined getgrnam("@RTGROUP@"));
470   found("bin owner (@BIN_OWNER@)",   defined getpwnam("@BIN_OWNER@"));
471   found("libs owner (@LIBS_OWNER@)", defined getpwnam("@LIBS_OWNER@"));
472   found("libs group (@LIBS_GROUP@)", defined getgrnam("@LIBS_GROUP@"));
473   found("web owner (@WEB_USER@)",    defined getpwnam("@WEB_USER@"));
474   found("web group (@WEB_GROUP@)",   defined getgrnam("@WEB_GROUP@"));
475 }
476
477
478
479 1;