123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425 |
- package Automake::FileUtils;
- use 5.006;
- use strict;
- use Exporter;
- use File::stat;
- use IO::File;
- use Automake::Channels;
- use Automake::ChannelDefs;
- use vars qw (@ISA @EXPORT);
- @ISA = qw (Exporter);
- @EXPORT = qw (&contents
- &find_file &mtime
- &update_file &up_to_date_p
- &xsystem &xsystem_hint &xqx
- &dir_has_case_matching_file &reset_dir_cache
- &set_dir_cache_file);
- sub find_file ($@)
- {
- use File::Spec;
- my ($file_name, @include) = @_;
- my $optional = 0;
- $optional = 1
- if $file_name =~ s/\?$//;
- return File::Spec->canonpath ($file_name)
- if -e $file_name;
- if (!File::Spec->file_name_is_absolute ($file_name))
- {
- foreach my $path (@include)
- {
- return File::Spec->canonpath (File::Spec->catfile ($path, $file_name))
- if -e File::Spec->catfile ($path, $file_name)
- }
- }
- fatal "$file_name: no such file or directory"
- unless $optional;
- return undef;
- }
- sub mtime ($)
- {
- my ($file) = @_;
- return 0
- if $file eq '-' || ! -f $file;
- my $stat = stat ($file)
- or fatal "cannot stat $file: $!";
- return $stat->mtime;
- }
- sub update_file ($$;$)
- {
- my ($from, $to, $force) = @_;
- $force = 0
- unless defined $force;
- my $SIMPLE_BACKUP_SUFFIX = $ENV{'SIMPLE_BACKUP_SUFFIX'} || '~';
- use File::Compare;
- use File::Copy;
- if ($to eq '-')
- {
- my $in = new IO::File $from, "<";
- my $out = new IO::File (">-");
- while ($_ = $in->getline)
- {
- print $out $_;
- }
- $in->close;
- unlink ($from) || fatal "cannot remove $from: $!";
- return;
- }
- if (!$force && -f "$to" && compare ("$from", "$to") == 0)
- {
-
- msg 'note', "'$to' is unchanged";
- unlink ($from)
- or fatal "cannot remove $from: $!";
- return
- }
- if (-f "$to")
- {
-
- move ("$to", "$to$SIMPLE_BACKUP_SUFFIX")
- or fatal "cannot backup $to: $!";
- move ("$from", "$to")
- or fatal "cannot rename $from as $to: $!";
- msg 'note', "'$to' is updated";
- }
- else
- {
- move ("$from", "$to")
- or fatal "cannot rename $from as $to: $!";
- msg 'note', "'$to' is created";
- }
- }
- sub up_to_date_p ($@)
- {
- my ($file, @dep) = @_;
- my $mtime = mtime ($file);
- foreach my $dep (@dep)
- {
- if ($mtime < mtime ($dep))
- {
- verb "up_to_date ($file): outdated: $dep";
- return 0;
- }
- }
- verb "up_to_date ($file): up to date";
- return 1;
- }
- sub handle_exec_errors ($;$$)
- {
- my ($command, $expected, $hint) = @_;
- $expected = 0 unless defined $expected;
- if (defined $hint)
- {
- $hint = "\n" . $hint;
- }
- else
- {
- $hint = '';
- }
- $command = (split (' ', $command))[0];
- if ($!)
- {
- fatal "failed to run $command: $!" . $hint;
- }
- else
- {
- use POSIX qw (WIFEXITED WEXITSTATUS WIFSIGNALED WTERMSIG);
- if (WIFEXITED ($?))
- {
- my $status = WEXITSTATUS ($?);
-
- fatal ('',
- "$command failed with exit status: $status",
- exit_code => $status)
- unless $status == $expected;
- }
- elsif (WIFSIGNALED ($?))
- {
- my $signal = WTERMSIG ($?);
- fatal "$command terminated by signal: $signal";
- }
- else
- {
- fatal "$command exited abnormally";
- }
- }
- }
- sub xqx ($)
- {
- my ($command) = @_;
- verb "running: $command";
- $! = 0;
- my $res = `$command`;
- handle_exec_errors $command
- if $?;
- return $res;
- }
- sub xsystem (@)
- {
- my (@command) = @_;
- verb "running: @command";
- $! = 0;
- handle_exec_errors "@command"
- if system @command;
- }
- sub xsystem_hint (@)
- {
- my ($hint, @command) = @_;
- verb "running: @command";
- $! = 0;
- handle_exec_errors "@command", 0, $hint
- if system @command;
- }
- sub contents ($)
- {
- my ($file) = @_;
- verb "reading $file";
- local $/;
- my $f = new Automake::XFile $file, "<";
- my $contents = $f->getline;
- $f->close;
- return $contents;
- }
- use vars '%_directory_cache';
- sub dir_has_case_matching_file ($$)
- {
-
-
-
- my ($dirname, $file_name) = @_;
- return 0 unless -f "$dirname/$file_name";
-
-
-
-
-
- if (!exists $_directory_cache{$dirname})
- {
- error "failed to open directory '$dirname'"
- unless opendir (DIR, $dirname);
- $_directory_cache{$dirname} = { map { $_ => 1 } readdir (DIR) };
- closedir (DIR);
- }
- return exists $_directory_cache{$dirname}{$file_name};
- }
- sub reset_dir_cache ($)
- {
- delete $_directory_cache{$_[0]};
- }
- sub set_dir_cache_file ($$)
- {
- my ($dirname, $file_name) = @_;
- $_directory_cache{$dirname}{$file_name} = 1
- if exists $_directory_cache{$dirname};
- }
- 1;
|