Silence the warning "Can't locate auto/POSIX/autosplit.ix in @INC"
[p5sagit/p5-mst-13.2.git] / lib / CPANPLUS / Internals / Extract.pm
CommitLineData
6aaee015 1package CPANPLUS::Internals::Extract;
2
3use strict;
4
5use CPANPLUS::Error;
6use CPANPLUS::Internals::Constants;
7
8use File::Spec ();
9use File::Basename ();
10use Archive::Extract;
11use IPC::Cmd qw[run];
12use Params::Check qw[check];
13use Module::Load::Conditional qw[can_load check_install];
14use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext';
15
16local $Params::Check::VERBOSE = 1;
17
18=pod
19
20=head1 NAME
21
22CPANPLUS::Internals::Extract
23
24=head1 SYNOPSIS
25
26 ### for source files ###
27 $self->_gunzip( file => 'foo.gz', output => 'blah.txt' );
28
29 ### for modules/packages ###
30 $dir = $self->_extract( module => $modobj,
31 extractdir => '/some/where' );
32
33=head1 DESCRIPTION
34
35CPANPLUS::Internals::Extract extracts compressed files for CPANPLUS.
36It can do this by either a pure perl solution (preferred) with the
37use of C<Archive::Tar> and C<Compress::Zlib>, or with binaries, like
38C<gzip> and C<tar>.
39
40The flow looks like this:
41
42 $cb->_extract
43 Delegate to Archive::Extract
44
45=head1 METHODS
46
47=head2 $dir = _extract( module => $modobj, [perl => '/path/to/perl', extractdir => '/path/to/extract/to', prefer_bin => BOOL, verbose => BOOL, force => BOOL] )
48
49C<_extract> will take a module object and extract it to C<extractdir>
50if provided, or the default location which is obtained from your
51config.
52
53The file name is obtained by looking at C<< $modobj->status->fetch >>
54and will be parsed to see if it's a tar or zip archive.
55
56If it's a zip archive, C<__unzip> will be called, otherwise C<__untar>
57will be called. In the unlikely event the file is of neither format,
58an error will be thrown.
59
60C<_extract> takes the following options:
61
62=over 4
63
64=item module
65
66A C<CPANPLUS::Module> object. This is required.
67
68=item extractdir
69
70The directory to extract the archive to. By default this looks
71something like:
72 /CPANPLUS_BASE/PERL_VERSION/BUILD/MODULE_NAME
73
74=item prefer_bin
75
76A flag indicating whether you prefer a pure perl solution, ie
77C<Archive::Tar> or C<Archive::Zip> respectively, or a binary solution
78like C<unzip> and C<tar>.
79
80=item perl
81
82The path to the perl executable to use for any perl calls. Also used
83to determine the build version directory for extraction.
84
85=item verbose
86
87Specifies whether to be verbose or not. Defaults to your corresponding
88config entry.
89
90=item force
91
92Specifies whether to force the extraction or not. Defaults to your
93corresponding config entry.
94
95=back
96
97All other options are passed on verbatim to C<__unzip> or C<__untar>.
98
99Returns the directory the file was extracted to on success and false
100on failure.
101
102=cut
103
104sub _extract {
105 my $self = shift;
106 my $conf = $self->configure_object;
107 my %hash = @_;
108
109 local $Params::Check::ALLOW_UNKNOWN = 1;
110
111 my( $mod, $verbose, $force );
112 my $tmpl = {
113 force => { default => $conf->get_conf('force'),
114 store => \$force },
115 verbose => { default => $conf->get_conf('verbose'),
116 store => \$verbose },
117 prefer_bin => { default => $conf->get_conf('prefer_bin') },
118 extractdir => { default => $conf->get_conf('extractdir') },
119 module => { required => 1, allow => IS_MODOBJ, store => \$mod },
120 perl => { default => $^X },
121 };
122
123 my $args = check( $tmpl, \%hash ) or return;
124
125 ### did we already extract it ? ###
126 my $loc = $mod->status->extract();
127
128 if( $loc && !$force ) {
129 msg(loc("Already extracted '%1' to '%2'. ".
130 "Won't extract again without force",
131 $mod->module, $loc), $verbose);
132 return $loc;
133 }
134
135 ### did we already fetch the file? ###
136 my $file = $mod->status->fetch();
137 unless( -s $file ) {
138 error( loc( "File '%1' has zero size: cannot extract", $file ) );
139 return;
140 }
141
142 ### the dir to extract to ###
143 my $to = $args->{'extractdir'} ||
144 File::Spec->catdir(
145 $conf->get_conf('base'),
146 $self->_perl_version( perl => $args->{'perl'} ),
147 $conf->_get_build('moddir'),
148 );
149
150 ### delegate to Archive::Extract ###
151 ### set up some flags for archive::extract ###
152 local $Archive::Extract::PREFER_BIN = $args->{'prefer_bin'};
153 local $Archive::Extract::DEBUG = $conf->get_conf('debug');
154 local $Archive::Extract::WARN = $verbose;
155
156 my $ae = Archive::Extract->new( archive => $file );
157
158 unless( $ae->extract( to => $to ) ) {
159 error( loc( "Unable to extract '%1' to '%2': %3",
160 $file, $to, $ae->error ) );
161 return;
162 }
163
164 ### if ->files is not filled, we dont know what the hell was
165 ### extracted.. try to offer a suggestion and bail :(
166 unless ( $ae->files ) {
167 error( loc( "'%1' was not able to determine extracted ".
168 "files from the archive. Instal '%2' and ensure ".
169 "it works properly and try again",
170 $ae->is_zip ? 'Archive::Zip' : 'Archive::Tar' ) );
171 return;
172 }
173
174
175 ### print out what files we extracted ###
176 msg(loc("Extracted '%1'",$_),$verbose) for @{$ae->files};
177
178 ### set them all to be +w for the owner, so we don't get permission
179 ### denied for overwriting files that are just +r
180
181 ### this is to rigurous -- just change to +w for the owner [cpan #13358]
182 #chmod 0755, map { File::Spec->rel2abs( File::Spec->catdir($to, $_) ) }
183 # @{$ae->files};
184
185 for my $file ( @{$ae->files} ) {
186 my $path = File::Spec->rel2abs( File::Spec->catdir($to, $file) );
187
188 $self->_mode_plus_w( file => $path );
189 }
190
191 ### check the return value for the extracted path ###
192 ### Make an educated guess if we didn't get an extract_path
193 ### back
194 ### XXX apparently some people make their own dists and they
195 ### pack up '.' which means the leading directory is '.'
196 ### and only the second directory is the actual module directory
197 ### so, we'll have to check if our educated guess exists first,
198 ### then see if the extract path works.. and if nothing works...
199 ### well, then we really don't know.
200
201 my $dir;
202 for my $try ( File::Spec->rel2abs( File::Spec->catdir(
203 $to, $mod->package_name .'-'. $mod->package_version ) ),
204 File::Spec->rel2abs( $ae->extract_path ),
205 ) {
206 ($dir = $try) && last if -d $try;
207 }
208
209 ### test if the dir exists ###
210 unless( $dir && -d $dir ) {
211 error(loc("Unable to determine extract dir for '%1'",$mod->module));
212 return;
213
214 } else {
215 msg(loc("Extracted '%1' to '%2'", $mod->module, $dir), $verbose);
216
217 ### register where we extracted the files to,
218 ### also store what files were extracted
219 $mod->status->extract( $dir );
220 $mod->status->files( $ae->files );
221 }
222
223 ### also, figure out what kind of install we're dealing with ###
224 $mod->get_installer_type();
225
226 return $mod->status->extract();
227}
228
2291;
230
231# Local variables:
232# c-indentation-style: bsd
233# c-basic-offset: 4
234# indent-tabs-mode: nil
235# End:
236# vim: expandtab shiftwidth=4: