📄 extract.pm
字号:
return 1;}################################### Unzip code##################################### unzip wrapper... goes to either Archive::Zip or /bin/unzip### depending on $PREFER_BINsub _unzip { my $self = shift; my @methods = qw[_unzip_az _unzip_bin]; @methods = reverse @methods if $PREFER_BIN; for my $method (@methods) { $self->_extractor($method) && return 1 if $self->$method(); } return $self->_error(loc("Unable to gunzip file '%1'", $self->archive));}sub _unzip_bin { my $self = shift; ### check for /bin/gzip if we need it ### return $self->_error(loc("No '%1' program found", '/bin/unzip')) unless $self->bin_unzip; ### first, get the files.. it must be 2 different commands with 'unzip' :( { ### on VMS, capital letter options have to be quoted. This is ### peported by John Malmberg on P5P Tue 21 Aug 2007 05:05:11 ### Subject: [patch@31735]Archive Extract fix on VMS. my $opt = ON_VMS ? '"-Z"' : '-Z'; my $cmd = [ $self->bin_unzip, $opt, '-1', $self->archive ]; my $buffer = ''; unless( scalar run( command => $cmd, verbose => $DEBUG, buffer => \$buffer ) ) { return $self->_error(loc("Unable to unzip '%1': %2", $self->archive, $buffer)); } ### no buffers available? if( !IPC::Cmd->can_capture_buffer and !$buffer ) { $self->_error( $self->_no_buffer_files( $self->archive ) ); } else { $self->files( [split $/, $buffer] ); } } ### now, extract the archive ### { my $cmd = [ $self->bin_unzip, '-qq', '-o', $self->archive ]; my $buffer; unless( scalar run( command => $cmd, verbose => $DEBUG, buffer => \$buffer ) ) { return $self->_error(loc("Unable to unzip '%1': %2", $self->archive, $buffer)); } if( scalar @{$self->files} ) { my $files = $self->files; my $dir = $self->__get_extract_dir( $files ); $self->extract_path( $dir ); } } return 1;}sub _unzip_az { my $self = shift; my $use_list = { 'Archive::Zip' => '0.0' }; unless( can_load( modules => $use_list ) ) { return $self->_error(loc("You do not have '%1' installed - Please " . "install it as soon as possible.", 'Archive::Zip')); } my $zip = Archive::Zip->new(); unless( $zip->read( $self->archive ) == &Archive::Zip::AZ_OK ) { return $self->_error(loc("Unable to read '%1'", $self->archive)); } my @files; ### have to extract every memeber individually ### for my $member ($zip->members) { push @files, $member->{fileName}; unless( $zip->extractMember($member) == &Archive::Zip::AZ_OK ) { return $self->_error(loc("Extraction of '%1' from '%2' failed", $member->{fileName}, $self->archive )); } } my $dir = $self->__get_extract_dir( \@files ); ### set what files where extract, and where they went ### $self->files( \@files ); $self->extract_path( File::Spec->rel2abs($dir) ); return 1;}sub __get_extract_dir { my $self = shift; my $files = shift || []; return unless scalar @$files; my($dir1, $dir2); for my $aref ( [ \$dir1, 0 ], [ \$dir2, -1 ] ) { my($dir,$pos) = @$aref; ### add a catdir(), so that any trailing slashes get ### take care of (removed) ### also, a catdir() normalises './dir/foo' to 'dir/foo'; ### which was the problem in bug #23999 my $res = -d $files->[$pos] ? File::Spec->catdir( $files->[$pos], '' ) : File::Spec->catdir( dirname( $files->[$pos] ) ); $$dir = $res; } ### if the first and last dir don't match, make sure the ### dirname is not set wrongly my $dir; ### dirs are the same, so we know for sure what the extract dir is if( $dir1 eq $dir2 ) { $dir = $dir1; ### dirs are different.. do they share the base dir? ### if so, use that, if not, fall back to '.' } else { my $base1 = [ File::Spec->splitdir( $dir1 ) ]->[0]; my $base2 = [ File::Spec->splitdir( $dir2 ) ]->[0]; $dir = File::Spec->rel2abs( $base1 eq $base2 ? $base1 : '.' ); } return File::Spec->rel2abs( $dir );}################################### Bunzip2 code##################################### bunzip2 wrapper... sub _bunzip2 { my $self = shift; my @methods = qw[_bunzip2_cz2 _bunzip2_bin]; @methods = reverse @methods if $PREFER_BIN; for my $method (@methods) { $self->_extractor($method) && return 1 if $self->$method(); } return $self->_error(loc("Unable to bunzip2 file '%1'", $self->archive));}sub _bunzip2_bin { my $self = shift; ### check for /bin/gzip -- we need it ### return $self->_error(loc("No '%1' program found", '/bin/bunzip2')) unless $self->bin_bunzip2; my $fh = FileHandle->new('>'. $self->_gunzip_to) or return $self->_error(loc("Could not open '%1' for writing: %2", $self->_gunzip_to, $! )); ### guard against broken bunzip2. See ->have_old_bunzip2() ### for details if( $self->have_old_bunzip2 and $self->archive !~ /\.bz2$/i ) { return $self->_error(loc("Your bunzip2 version is too old and ". "can only extract files ending in '%1'", '.bz2')); } my $cmd = [ $self->bin_bunzip2, '-cd', $self->archive ]; my $buffer; unless( scalar run( command => $cmd, verbose => $DEBUG, buffer => \$buffer ) ) { return $self->_error(loc("Unable to bunzip2 '%1': %2", $self->archive, $buffer)); } ### no buffers available? if( !IPC::Cmd->can_capture_buffer and !$buffer ) { $self->_error( $self->_no_buffer_content( $self->archive ) ); } print $fh $buffer if defined $buffer; close $fh; ### set what files where extract, and where they went ### $self->files( [$self->_gunzip_to] ); $self->extract_path( File::Spec->rel2abs(cwd()) ); return 1;}### using cz2, the compact versions... this we use mainly in archive::tar### extractor..# sub _bunzip2_cz1 {# my $self = shift;# # my $use_list = { 'IO::Uncompress::Bunzip2' => '0.0' };# unless( can_load( modules => $use_list ) ) {# return $self->_error(loc("You do not have '%1' installed - Please " .# "install it as soon as possible.",# 'IO::Uncompress::Bunzip2'));# }# # my $bz = IO::Uncompress::Bunzip2->new( $self->archive ) or# return $self->_error(loc("Unable to open '%1': %2",# $self->archive,# $IO::Uncompress::Bunzip2::Bunzip2Error));# # my $fh = FileHandle->new('>'. $self->_gunzip_to) or# return $self->_error(loc("Could not open '%1' for writing: %2",# $self->_gunzip_to, $! ));# # my $buffer;# $fh->print($buffer) while $bz->read($buffer) > 0;# $fh->close;# # ### set what files where extract, and where they went #### $self->files( [$self->_gunzip_to] );# $self->extract_path( File::Spec->rel2abs(cwd()) );# # return 1;# }sub _bunzip2_cz2 { my $self = shift; my $use_list = { 'IO::Uncompress::Bunzip2' => '0.0' }; unless( can_load( modules => $use_list ) ) { return $self->_error(loc("You do not have '%1' installed - Please " . "install it as soon as possible.", 'IO::Uncompress::Bunzip2')); } IO::Uncompress::Bunzip2::bunzip2($self->archive => $self->_gunzip_to) or return $self->_error(loc("Unable to uncompress '%1': %2", $self->archive, $IO::Uncompress::Bunzip2::Bunzip2Error)); ### set what files where extract, and where they went ### $self->files( [$self->_gunzip_to] ); $self->extract_path( File::Spec->rel2abs(cwd()) ); return 1;}################################### Error code##################################sub _error { my $self = shift; my $error = shift; $self->_error_msg( $error ); $self->_error_msg_long( Carp::longmess($error) ); ### set $Archive::Extract::WARN to 0 to disable printing ### of errors if( $WARN ) { carp $DEBUG ? $self->_error_msg_long : $self->_error_msg; } return;}sub error { my $self = shift; return shift() ? $self->_error_msg_long : $self->_error_msg;}sub _no_buffer_files { my $self = shift; my $file = shift or return; return loc("No buffer captured, unable to tell ". "extracted files or extraction dir for '%1'", $file);}sub _no_buffer_content { my $self = shift; my $file = shift or return; return loc("No buffer captured, unable to get content for '%1'", $file);}1;=pod=head1 HOW IT WORKSC<Archive::Extract> tries first to determine what type of archive youare passing it, by inspecting its suffix. It does not do this by usingMime magic, or something related. See C<CAVEATS> below.Once it has determined the file type, it knows which extraction methodsit can use on the archive. It will try a perl solution first, then fallback to a commandline tool if that fails. If that also fails, it willreturn false, indicating it was unable to extract the archive.See the section on C<GLOBAL VARIABLES> to see how to alter this order.=head1 CAVEATS=head2 File ExtensionsC<Archive::Extract> trusts on the extension of the archive to determinewhat type it is, and what extractor methods therefore can be used. Ifyour archives do not have any of the extensions as described in theC<new()> method, you will have to specify the type explicitly, orC<Archive::Extract> will not be able to extract the archive for you.=head2 Supporting Very Large FilesC<Archive::Extract> can use either pure perl modules or command lineprograms under the hood. Some of the pure perl modules (like C<Archive::Tar> take the entire contents of the archive into memory,which may not be feasible on your system. Consider setting the globalvariable C<$Archive::Extract::PREFER_BIN> to C<1>, which will preferthe use of command line programs and won't consume so much memory.See the C<GLOBAL VARIABLES> section below for details.=head2 Bunzip2 support of arbitrary extensions.Older versions of C</bin/bunzip2> do not support arbitrary file extensions and insist on a C<.bz2> suffix. Although we do our bestto guard against this, if you experience a bunzip2 error, it maybe related to this. For details, please see the C<have_old_bunzip2>method.=head1 GLOBAL VARIABLES=head2 $Archive::Extract::DEBUGSet this variable to C<true> to have all calls to command line toolsbe printed out, including all their output.This also enables C<Carp::longmess> errors, instead of the regularC<carp> errors.Good for tracking down why things don't work with your particularsetup.Defaults to C<false>.=head2 $Archive::Extract::WARNThis variable controls whether errors encountered internally byC<Archive::Extract> should be C<carp>'d or not.Set to false to silence warnings. Inspect the output of the C<error()>method manually to see what went wrong.Defaults to C<true>.=head2 $Archive::Extract::PREFER_BINThis variables controls whether C<Archive::Extract> should prefer theuse of perl modules, or commandline tools to extract archives.Set to C<true> to have C<Archive::Extract> prefer commandline tools.Defaults to C<false>.=head1 TODO=over 4=item Mime magic supportMaybe this module should use something like C<File::Type> to determinethe type, rather than blindly trust the suffix.=back=head1 BUG REPORTSPlease report bugs or other issues to E<lt>bug-archive-extract@rt.cpan.org<gt>.=head1 AUTHORThis module by Jos Boumans E<lt>kane@cpan.orgE<gt>.=head1 COPYRIGHTThis library is free software; you may redistribute and/or modify it under the same terms as Perl itself.=cut# Local variables:# c-indentation-style: bsd# c-basic-offset: 4# indent-tabs-mode: nil# End:# vim: expandtab shiftwidth=4:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -