### ### Copyright 2000-2007 University of Illinois Board of Trustees ### All rights reserved. ### ### PSGConf::Action::File - base class for psgconf file-generator action types ### ### Campus Information Technologies and Educational Services ### University of Illinois at Urbana-Champaign ### package PSGConf::Action::File; use strict; use File::Basename; use File::Compare; use File::Copy; use File::Path; use File::stat; use POSIX; use Text::Diff (); # Use () so we do not get diff() redefinition errors use PSGConf::Action::ChMod; use PSGConf::Action::ChOwn; use PSGConf::Action::ChGrp; use PSGConf::Util; our @ISA = qw(PSGConf::Action::ChMod PSGConf::Action::ChOwn PSGConf::Action::ChGrp); ############################################################################### ### constructor ############################################################################### sub new { my ($class, %opts) = @_; my ($self) = \%opts; $self->{backup} = 1 if (!exists($self->{backup})); ### Call the ChMod action as well. $self = PSGConf::Action::ChMod::new($class, %$self); ### Call the ChOwn action as well. $self = PSGConf::Action::ChOwn::new($class, %$self); ### Call the ChGrp action as well. return PSGConf::Action::ChGrp::new($class, %$self); } ############################################################################### ### utility function to check whether file changed ############################################################################### sub _file_changed { my ($self, $psgconf) = @_; ### check for changes $self->{changed} = 1 if (! -e $self->{name} || compare($self->{name}, $self->{tmpfile}) != 0); ### check for permission differences $self->PSGConf::Action::ChMod::check($psgconf); ### check for ownership differences $self->PSGConf::Action::ChOwn::check($psgconf); ### check for group differences $self->PSGConf::Action::ChGrp::check($psgconf); return $self->{changed}; } ############################################################################### ### check method ############################################################################### sub check { my ($self, $psgconf) = @_; ### Intentionally left blank. } ############################################################################### ### diff method ############################################################################### sub diff { my ($self, $psgconf) = @_; my ($mytgt); if (! -e $self->{name} || compare($self->{name}, $self->{tmpfile}) != 0) { print "###############################################################################\n"; print "### DIFF FOR $self->{name}\n"; if (! -e $self->{name}) { print "### (original file does not exist)\n"; $mytgt = '/dev/null'; } else { $mytgt = $self->{name}; } print "###############################################################################\n"; ### ### Make sure we only run Text::Diff::diff on known text files. ### if ( -e $self->{tmpfile} ) { if ( -T $mytgt && -T $self->{tmpfile} ) { print Text::Diff::diff $mytgt, $self->{tmpfile}; } else { printf "+ Binary file(s) %s, %s are different\n", $mytgt, $self->{tmpfile}; } } print "\n"; } ### check for permission differences $self->PSGConf::Action::ChMod::diff($psgconf); ### check for ownership differences $self->PSGConf::Action::ChOwn::diff($psgconf); ### check for group differences $self->PSGConf::Action::ChGrp::diff($psgconf); } ############################################################################### ### do() method ############################################################################### sub do { my ($self, $psgconf) = @_; ### install new file if contents changed if (-e $self->{tmpfile}) { ### save or remove original file if (-e $self->{name} || -l $self->{name}) { ### ### for regular files, don't delete the original, ### since it might have multiple hard links ### if (!$self->{backup}) { if (! -f $self->{name}) { rmtree($self->{name}); } } elsif (! $psgconf->save_file($self->{name}, $self->{backup})) { return -1; } } ### copy new file into place mkpath(dirname($self->{name})); if (!copy($self->{tmpfile}, $self->{name})) { warn "\t!!! copy('$self->{tmpfile}', " . "'$self->{name}'): $!\n"; return -1; } } ### check for permission differences $self->PSGConf::Action::ChMod::do($psgconf); ### check for ownership differences $self->PSGConf::Action::ChOwn::do($psgconf); ### check for group differences $self->PSGConf::Action::ChGrp::do($psgconf); ### remove tmpfile if applicable if (-e $self->{tmpfile} && $psgconf->{rm_tmpfiles} && !unlink($self->{tmpfile})) { warn "\t!!! unlink('$self->{tmpfile}'): $!\n"; } return 1; } ############################################################################### ### documentation ############################################################################### 1; __END__ =head1 NAME PSGConf::Action::File - base class for psgconf file-generator action types =head1 SYNOPSIS use PSGConf::Action::File; $psgconf->register_actions( PSGConf::Action::File->new( 'name' => '/path/to/file', ... ), ... ); =head1 DESCRIPTION The B module provides a base class for B action classes that manipulate a file. The B class is not intended to be used to directly instantiate action objects, but it does support a number of methods for use in subclasses. The B class is derived from the B, B and B classes, but it defines/overrides the following methods: =over 4 =item _file_changed($psgconf) Utility method for use in subclasses' check() method. Checks to see whether the existing file differs from the tmpfile then calls the C methods in C, C and C. Sets the object's Iattribute and returns the same values as the check() method. =item check() Returns 0. (This method should be replaced by the subclass.) =item diff() Display the differences between the tmpfile and the existing file. Also displays mode and ownership changes. =item do() Moves the tmpfile into place, optionally backing up the original file. Also sets mode and ownership. =back In addition to the attributes supported by the B class, the B class supports the following attributes: =over 4 =item I The octal mode of the file. Defaults to 0644. Set to -1 to disable check. =item I The numeric user id of the file. Defaults to 0. Set to -1 to disable check. =item I The numeric group id of the file. Defaults to 0. Set to -1 to disable check. =item I A boolean flag to indicate whether a backup copy of the existing file will be saved. If enabled, existing files will be saved under their original name but with the prefix ".". Default is to backup. =back =head1 BUGS The class should support multiple instantiations for the same file, where subsequent instantiations would use the tmpfile from the previous instantiation instead of the actual original file on the system. =head1 SEE ALSO L L L L L L =cut