Initial release
[manu/RT-Extension-ImportCustomFieldValues.git] / inc / Module / Install / RTx.pm
1 #line 1
2 package Module::Install::RTx;
3
4 use 5.008;
5 use strict;
6 use warnings;
7 no warnings 'once';
8
9 use Module::Install::Base;
10 use base 'Module::Install::Base';
11 our $VERSION = '0.39';
12
13 use FindBin;
14 use File::Glob     ();
15 use File::Basename ();
16
17 my @DIRS = qw(etc lib html static bin sbin po var);
18 my @INDEX_DIRS = qw(lib bin sbin);
19
20 sub RTx {
21     my ( $self, $name, $extra_args ) = @_;
22     $extra_args ||= {};
23
24     # Set up names
25     my $fname = $name;
26     $fname =~ s!-!/!g;
27
28     $self->name( $name )
29         unless $self->name;
30     $self->all_from( "lib/$fname.pm" )
31         unless $self->version;
32     $self->abstract("$name Extension")
33         unless $self->abstract;
34     unless ( $extra_args->{no_readme_generation} ) {
35         $self->readme_from( "lib/$fname.pm",
36                             { options => [ quotes => "none" ] } );
37     }
38     $self->add_metadata("x_module_install_rtx_version", $VERSION );
39
40     my $installdirs = $ENV{INSTALLDIRS};
41     for ( @ARGV ) {
42         if ( /INSTALLDIRS=(.*)/ ) {
43             $installdirs = $1;
44         }
45     }
46
47     # Try to find RT.pm
48     my @prefixes = qw( /opt /usr/local /home /usr /sw /usr/share/request-tracker4);
49     $ENV{RTHOME} =~ s{/RT\.pm$}{} if defined $ENV{RTHOME};
50     $ENV{RTHOME} =~ s{/lib/?$}{}  if defined $ENV{RTHOME};
51     my @try = $ENV{RTHOME} ? ($ENV{RTHOME}, "$ENV{RTHOME}/lib") : ();
52     while (1) {
53         my @look = @INC;
54         unshift @look, grep {defined and -d $_} @try;
55         push @look, grep {defined and -d $_}
56             map { ( "$_/rt4/lib", "$_/lib/rt4", "$_/lib" ) } @prefixes;
57         last if eval {local @INC = @look; require RT; $RT::LocalLibPath};
58
59         warn
60             "Cannot find the location of RT.pm that defines \$RT::LocalPath in: @look\n";
61         my $given = $self->prompt("Path to directory containing your RT.pm:") or exit;
62         $given =~ s{/RT\.pm$}{};
63         $given =~ s{/lib/?$}{};
64         @try = ($given, "$given/lib");
65     }
66
67     print "Using RT configuration from $INC{'RT.pm'}:\n";
68
69     my $local_lib_path = $RT::LocalLibPath;
70     unshift @INC, $local_lib_path;
71     my $lib_path = File::Basename::dirname( $INC{'RT.pm'} );
72     unshift @INC, $lib_path;
73
74     # Set a baseline minimum version
75     unless ( $extra_args->{deprecated_rt} ) {
76         $self->requires_rt('4.0.0');
77     }
78
79     # Installation locations
80     my %path;
81     my $plugin_path;
82     if ( $installdirs && $installdirs eq 'vendor' ) {
83         $plugin_path = $RT::PluginPath;
84     } else {
85         $plugin_path = $RT::LocalPluginPath;
86     }
87     $path{$_} = $plugin_path . "/$name/$_"
88         foreach @DIRS;
89
90     # Copy RT 4.2.0 static files into NoAuth; insufficient for
91     # images, but good enough for css and js.
92     $path{static} = "$path{html}/NoAuth/"
93         unless $RT::StaticPath;
94
95     # Delete the ones we don't need
96     delete $path{$_} for grep {not -d "$FindBin::Bin/$_"} keys %path;
97
98     my %index = map { $_ => 1 } @INDEX_DIRS;
99     $self->no_index( directory => $_ ) foreach grep !$index{$_}, @DIRS;
100
101     my $args = join ', ', map "q($_)", map { ($_, "\$(DESTDIR)$path{$_}") }
102         sort keys %path;
103
104     printf "%-10s => %s\n", $_, $path{$_} for sort keys %path;
105
106     if ( my @dirs = map { ( -D => $_ ) } grep $path{$_}, qw(bin html sbin etc) ) {
107         my @po = map { ( -o => $_ ) }
108             grep -f,
109             File::Glob::bsd_glob("po/*.po");
110         $self->postamble(<< ".") if @po;
111 lexicons ::
112 \t\$(NOECHO) \$(PERL) -MLocale::Maketext::Extract::Run=xgettext -e \"xgettext(qw(@dirs @po))\"
113 .
114     }
115
116     my $remove_files;
117     if( $extra_args->{'remove_files'} ){
118         $self->include('Module::Install::RTx::Remove');
119         our @remove_files;
120         eval { require "etc/upgrade/remove_files" }
121           or print "No remove file located, no files to remove\n";
122         $remove_files = join ",", map {"q(\$(DESTDIR)$plugin_path/$name/$_)"} @remove_files;
123     }
124
125     $self->include('Module::Install::RTx::Runtime') if $self->admin;
126     $self->include_deps( 'YAML::Tiny', 0 ) if $self->admin;
127     my $postamble = << ".";
128 install ::
129 \t\$(NOECHO) \$(PERL) -Ilib -I"$local_lib_path" -I"$lib_path" -Iinc -MModule::Install::RTx::Runtime -e"RTxPlugin()"
130 .
131
132     if( $remove_files ){
133         $postamble .= << ".";
134 \t\$(NOECHO) \$(PERL) -MModule::Install::RTx::Remove -e \"RTxRemove([$remove_files])\"
135 .
136     }
137
138     $postamble .= << ".";
139 \t\$(NOECHO) \$(PERL) -MExtUtils::Install -e \"install({$args})\"
140 .
141
142     if ( $path{var} and -d $RT::MasonDataDir ) {
143         my ( $uid, $gid ) = ( stat($RT::MasonDataDir) )[ 4, 5 ];
144         $postamble .= << ".";
145 \t\$(NOECHO) chown -R $uid:$gid $path{var}
146 .
147     }
148
149     my %has_etc;
150     if ( File::Glob::bsd_glob("$FindBin::Bin/etc/schema.*") ) {
151         $has_etc{schema}++;
152     }
153     if ( File::Glob::bsd_glob("$FindBin::Bin/etc/acl.*") ) {
154         $has_etc{acl}++;
155     }
156     if ( -e 'etc/initialdata' ) { $has_etc{initialdata}++; }
157     if ( grep { /\d+\.\d+\.\d+.*$/ } glob('etc/upgrade/*.*.*') ) {
158         $has_etc{upgrade}++;
159     }
160
161     $self->postamble("$postamble\n");
162     if ( $path{lib} ) {
163         $self->makemaker_args( INSTALLSITELIB => $path{'lib'} );
164         $self->makemaker_args( INSTALLARCHLIB => $path{'lib'} );
165         $self->makemaker_args( INSTALLVENDORLIB => $path{'lib'} )
166     } else {
167         $self->makemaker_args( PM => { "" => "" }, );
168     }
169
170     $self->makemaker_args( INSTALLSITEMAN1DIR => "$RT::LocalPath/man/man1" );
171     $self->makemaker_args( INSTALLSITEMAN3DIR => "$RT::LocalPath/man/man3" );
172     $self->makemaker_args( INSTALLSITEARCH => "$RT::LocalPath/man" );
173
174     # INSTALLDIRS=vendor should install manpages into /usr/share/man.
175     # That is the default path in most distributions. Need input from
176     # Redhat, Centos etc.
177     $self->makemaker_args( INSTALLVENDORMAN1DIR => "/usr/share/man/man1" );
178     $self->makemaker_args( INSTALLVENDORMAN3DIR => "/usr/share/man/man3" );
179     $self->makemaker_args( INSTALLVENDORARCH => "/usr/share/man" );
180
181     if (%has_etc) {
182         print "For first-time installation, type 'make initdb'.\n";
183         my $initdb = '';
184         $initdb .= <<"." if $has_etc{schema};
185 \t\$(NOECHO) \$(PERL) -Ilib -I"$local_lib_path" -I"$lib_path" -Iinc -MModule::Install::RTx::Runtime -e"RTxDatabase(qw(schema \$(NAME) \$(VERSION)))"
186 .
187         $initdb .= <<"." if $has_etc{acl};
188 \t\$(NOECHO) \$(PERL) -Ilib -I"$local_lib_path" -I"$lib_path" -Iinc -MModule::Install::RTx::Runtime -e"RTxDatabase(qw(acl \$(NAME) \$(VERSION)))"
189 .
190         $initdb .= <<"." if $has_etc{initialdata};
191 \t\$(NOECHO) \$(PERL) -Ilib -I"$local_lib_path" -I"$lib_path" -Iinc -MModule::Install::RTx::Runtime -e"RTxDatabase(qw(insert \$(NAME) \$(VERSION)))"
192 .
193         $self->postamble("initdb ::\n$initdb\n");
194         $self->postamble("initialize-database ::\n$initdb\n");
195         if ($has_etc{upgrade}) {
196             print "To upgrade from a previous version of this extension, use 'make upgrade-database'\n";
197             my $upgradedb = qq|\t\$(NOECHO) \$(PERL) -Ilib -I"$local_lib_path" -I"$lib_path" -Iinc -MModule::Install::RTx::Runtime -e"RTxDatabase(qw(upgrade \$(NAME) \$(VERSION)))"\n|;
198             $self->postamble("upgrade-database ::\n$upgradedb\n");
199             $self->postamble("upgradedb ::\n$upgradedb\n");
200         }
201     }
202
203 }
204
205 sub requires_rt {
206     my ($self,$version) = @_;
207
208     _load_rt_handle();
209
210     if ($self->is_admin) {
211         $self->add_metadata("x_requires_rt", $version);
212         my @sorted = sort RT::Handle::cmp_version $version,'4.0.0';
213         $self->perl_version('5.008003') if $sorted[0] eq '4.0.0'
214             and (not $self->perl_version or '5.008003' > $self->perl_version);
215         @sorted = sort RT::Handle::cmp_version $version,'4.2.0';
216         $self->perl_version('5.010001') if $sorted[0] eq '4.2.0'
217             and (not $self->perl_version or '5.010001' > $self->perl_version);
218     }
219
220     # if we're exactly the same version as what we want, silently return
221     return if ($version eq $RT::VERSION);
222
223     my @sorted = sort RT::Handle::cmp_version $version,$RT::VERSION;
224
225     if ($sorted[-1] eq $version) {
226         die <<"EOT";
227
228 **** Error: This extension requires RT $version. Your installed version
229             of RT ($RT::VERSION) is too old.
230
231 EOT
232     }
233 }
234
235 sub requires_rt_plugin {
236     my $self = shift;
237     my ( $plugin ) = @_;
238
239     if ($self->is_admin) {
240         my $plugins = $self->Meta->{values}{"x_requires_rt_plugins"} || [];
241         push @{$plugins}, $plugin;
242         $self->add_metadata("x_requires_rt_plugins", $plugins);
243     }
244
245     my $path = $plugin;
246     $path =~ s{\:\:}{-}g;
247     $path = "$RT::LocalPluginPath/$path/lib";
248     if ( -e $path ) {
249         unshift @INC, $path;
250     } else {
251         my $name = $self->name;
252         warn <<"EOT";
253
254 **** Warning: $name requires that the $plugin plugin be installed and
255               enabled; it does not appear to be installed.
256
257 EOT
258     }
259     $self->requires(@_);
260 }
261
262 sub rt_too_new {
263     my ($self,$version,$msg) = @_;
264     my $name = $self->name;
265     $msg ||= <<EOT;
266
267 **** Error: Your installed version of RT (%s) is too new; this extension
268             only works with versions older than %s.
269
270 EOT
271     $self->add_metadata("x_rt_too_new", $version) if $self->is_admin;
272
273     _load_rt_handle();
274     my @sorted = sort RT::Handle::cmp_version $version,$RT::VERSION;
275
276     if ($sorted[0] eq $version) {
277         die sprintf($msg,$RT::VERSION,$version);
278     }
279 }
280
281 # RT::Handle runs FinalizeDatabaseType which calls RT->Config->Get
282 # On 3.8, this dies.  On 4.0/4.2 ->Config transparently runs LoadConfig.
283 # LoadConfig requires being able to read RT_SiteConfig.pm (root) so we'd
284 # like to avoid pushing that on users.
285 # Fake up just enough Config to let FinalizeDatabaseType finish, and
286 # anyone later calling LoadConfig will overwrite our shenanigans.
287 sub _load_rt_handle {
288     unless ($RT::Config) {
289         require RT::Config;
290         $RT::Config = RT::Config->new;
291         RT->Config->Set('DatabaseType','mysql');
292     }
293     require RT::Handle;
294 }
295
296 1;
297
298 __END__
299
300 #line 468