#************************************************************** | |
# | |
# Licensed to the Apache Software Foundation (ASF) under one | |
# or more contributor license agreements. See the NOTICE file | |
# distributed with this work for additional information | |
# regarding copyright ownership. The ASF licenses this file | |
# to you under the Apache License, Version 2.0 (the | |
# "License"); you may not use this file except in compliance | |
# with the License. You may obtain a copy of the License at | |
# | |
# http://www.apache.org/licenses/LICENSE-2.0 | |
# | |
# Unless required by applicable law or agreed to in writing, | |
# software distributed under the License is distributed on an | |
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
# KIND, either express or implied. See the License for the | |
# specific language governing permissions and limitations | |
# under the License. | |
# | |
#************************************************************** | |
package installer::patch::FileOperations; | |
use File::Basename; | |
use File::Copy; | |
use IO::Compress::Bzip2; | |
use IO::Uncompress::Bunzip2; | |
my $CompressionMethod = "bzip2"; | |
=head1 NAME | |
package installer::patch::FileOperations - Class for collecting, checking and executing file operations. | |
=cut | |
sub new ($) | |
{ | |
my ($class) = (@_); | |
my $self = { | |
'operations' => [] | |
}; | |
bless($self, $class); | |
return $self; | |
} | |
sub AddCopyOperation ($$$) | |
{ | |
my ($self, $source_name, $target_name) = @_; | |
push | |
@{$self->{'operations'}}, | |
[ | |
'copy', | |
$source_name, | |
$target_name | |
]; | |
} | |
sub AddMakeDirectoryOperation ($$) | |
{ | |
my ($self, $path) = @_; | |
push | |
@{$self->{'operations'}}, | |
[ | |
'mkdir', | |
$path | |
]; | |
} | |
sub AddCompressOperation ($$) | |
{ | |
my ($self, $filename) = @_; | |
push | |
@{$self->{'operations'}}, | |
[ | |
'compress', | |
$filename | |
]; | |
} | |
sub AddUncompressOperation ($$$) | |
{ | |
my ($self, $source_name, $target_name) = @_; | |
push | |
@{$self->{'operations'}}, | |
[ | |
'uncompress', | |
$source_name, | |
$target_name | |
]; | |
} | |
sub Check ($) | |
{ | |
my ($self) = @_; | |
# Keep track of which directories or files would be created to check if | |
# operations that depend on these files will succeed. | |
my %files = (); | |
my %directories = (); | |
my @error_messages = (); | |
foreach my $operation (@{$self->{'operations'}}) | |
{ | |
my $command = $operation->[0]; | |
if ($command eq "copy") | |
{ | |
my ($source_name, $destination_name) = ($operation->[1], $operation->[2]); | |
if ( ! -f $source_name) | |
{ | |
push @error_messages, sprintf("%s is not a regular file and can not be copied", $source_name); | |
} | |
my $destination_path = dirname($destination_name); | |
if ( ! -d $destination_path && ! defined $directories{$destination_path}) | |
{ | |
push @error_messages, sprintf("destination path %s does not exist", $destination_path); | |
} | |
if ( -f $destination_name) | |
{ | |
# The destination file already exists. We have to overwrite it. | |
if ( ! -w $destination_name) | |
{ | |
push @error_messges, sprintf("destination file %s exists but can not be overwritten", $destination_name); | |
} | |
} | |
$files{$destination_name} = 1; | |
} | |
elsif ($command eq "mkdir") | |
{ | |
my $path = $operation->[1]; | |
if ( -d $path) | |
{ | |
# Directory already exists. That is OK, the mkdir command will be silently ignored. | |
} | |
else | |
{ | |
$directories{$path} = 1; | |
} | |
} | |
elsif ($command eq "compress") | |
{ | |
my $filename = $operation->[1]; | |
if ( ! -f $filename && ! defined $files{$filename}) | |
{ | |
# File does not exist and will not be created by an earlier operation. | |
push @error_messages, sprintf("file %s does not exist and can not be compressed", $filename); | |
} | |
} | |
elsif ($command eq "uncompress") | |
{ | |
my ($source_filename, $destination_filename) = ($operation->[1], $operation->[2]); | |
if ($CompressionMethod eq "bzip2") | |
{ | |
$source_filename .= ".bz2"; | |
} | |
if ( ! -f $source_filename && ! defined $files{$source_filename}) | |
{ | |
# File does not exist and will not be created by an earlier operation. | |
push @error_messages, sprintf("file %s does not exist and can not be decompressed", $source_filename); | |
} | |
if ( -f $destination_filename && ! -w $destination_filename) | |
{ | |
# Destination file aleady exists but can not be replaced. | |
push @error_messages, sprintf("compress destination file %s exists but can not be replaced", $destination_filename); | |
} | |
} | |
else | |
{ | |
push @error_messages, sprintf("unknown operation %s", $command); | |
} | |
} | |
return @error_messages; | |
} | |
sub CheckAndExecute ($) | |
{ | |
my ($self) = @_; | |
my @error_messages = $self->Check(); | |
if (scalar @error_messages > 0) | |
{ | |
$installer::logger::Lang->printf("can not execute all operations:\n"); | |
for my $message (@error_messages) | |
{ | |
$installer::logger::Lang->printf("ERROR: %s\n", $message); | |
} | |
return 0; | |
} | |
else | |
{ | |
return $self->Execute(); | |
} | |
} | |
sub Execute ($) | |
{ | |
my ($self) = @_; | |
foreach my $operation (@{$self->{'operations'}}) | |
{ | |
my $command = $operation->[0]; | |
if ($command eq "copy") | |
{ | |
my ($source_name, $destination_name) = ($operation->[1], $operation->[2]); | |
$installer::logger::Lang->printf("copy from %s\n to %s\n", $source_name, $destination_name); | |
if ( ! $DryRun) | |
{ | |
my $result = copy($source_name, $destination_name); | |
if ( ! $result) | |
{ | |
$installer::logger::Lang->printf("ERROR: copying from %s to %s failed", | |
$source_name, $destination_name); | |
} | |
} | |
} | |
elsif ($command eq "mkdir") | |
{ | |
my $path = $operation->[1]; | |
if ( -d $path) | |
{ | |
# Path exists already. Do nothing. | |
} | |
else | |
{ | |
$installer::logger::Lang->printf("creating directory %s\n", $path); | |
if ( ! $DryRun) | |
{ | |
if (File::Path::make_path($path, {'mode' => 0775}) == 0) | |
{ | |
$installer::logger::Lang->printf("could not create directory %s\n", $path); | |
} | |
} | |
} | |
} | |
elsif ($command eq "compress") | |
{ | |
my $filename = $operation->[1]; | |
$installer::logger::Lang->printf("compressing %s\n", $filename); | |
if ( ! $DryRun) | |
{ | |
my $result = 0; | |
if ($CompressionMethod eq "bzip2") | |
{ | |
$result = IO::Compress::Bzip2::bzip2($filename => $filename.".bz2"); | |
} | |
if ($result == 0) | |
{ | |
$installer::logger::Lang->printf("ERROR: could not compress %s\n", $filename); | |
} | |
else | |
{ | |
unlink($filename); | |
} | |
} | |
} | |
elsif ($command eq "uncompress") | |
{ | |
my ($source_name, $destination_name) = ($operation->[1], $operation->[2]); | |
if ($CompressionMethod eq "bzip2") | |
{ | |
$source_name .= ".bz2"; | |
} | |
$installer::logger::Lang->printf("uncompressing %s to %s\n", $source_name, $destination_name); | |
my $destination_base_name = basename($destination_name); | |
if ( ! $DryRun) | |
{ | |
my $result = 0; | |
if ($CompressionMethod eq "bzip2") | |
{ | |
$result = IO::Uncompress::Bunzip2::bunzip2($source_name => $destination_name); | |
} | |
if ($result == 0) | |
{ | |
$installer::logger::Lang->printf("ERROR: failed to extract content of '%s' from '%s'\n", | |
$destination_name, $source_name); | |
return 0; | |
} | |
} | |
} | |
else | |
{ | |
die "unknown operation $command\n"; | |
} | |
} | |
return 1; | |
} | |
sub GetOperationCount ($) | |
{ | |
my ($self) = @_; | |
return scalar @{$self->{'operations'}}; | |
} | |
1; |