|
Packit |
0848f5 |
#! /usr/bin/env perl
|
|
Packit |
0848f5 |
# -*- Mode: perl; -*-
|
|
Packit |
0848f5 |
#
|
|
Packit |
0848f5 |
# This script is a replacement for several scripts that process source
|
|
Packit |
0848f5 |
# files, extracting information from them. This file provides a set
|
|
Packit |
0848f5 |
# of routines for processing files and maintaining a cache of the results.
|
|
Packit |
0848f5 |
# It uses a more sophisticated
|
|
Packit |
0848f5 |
# approach to avoid rescanning all files by keeping track of local changes
|
|
Packit |
0848f5 |
# It does this on a directory-by-directory basis as a comprimise between
|
|
Packit |
0848f5 |
# doing the minimal work but limiting the number and size of the "extra"
|
|
Packit |
0848f5 |
# files. In this case, for each directory, the following dot file is
|
|
Packit |
0848f5 |
# produced (with a <name> provided depending on use:
|
|
Packit |
0848f5 |
# .<name>-cache
|
|
Packit |
0848f5 |
# This file contains lines of the form
|
|
Packit |
0848f5 |
# <dir>
|
|
Packit |
0848f5 |
# <file name="filename" info="date or md5 hash"/>
|
|
Packit |
0848f5 |
# ...
|
|
Packit |
0848f5 |
# </dir>
|
|
Packit |
0848f5 |
# <data>
|
|
Packit |
0848f5 |
# <fileinfo name="filename">
|
|
Packit |
0848f5 |
# data for this file extracted from file
|
|
Packit |
0848f5 |
# </fileinfo>
|
|
Packit |
0848f5 |
# ...
|
|
Packit |
0848f5 |
# </data>
|
|
Packit |
0848f5 |
# The file has a separate directory to speed reading of the list of
|
|
Packit |
0848f5 |
# know files so that the comparisons for updates can be
|
|
Packit |
0848f5 |
# computed quickly.
|
|
Packit |
0848f5 |
#
|
|
Packit |
0848f5 |
# In addition, this allows us to create lists of information by
|
|
Packit |
0848f5 |
# combining the directories in which we're interested, rather than
|
|
Packit |
0848f5 |
# all of the directories. This will also make it possible to
|
|
Packit |
0848f5 |
# update these tables at configure time with modules provided by other
|
|
Packit |
0848f5 |
# developers.
|
|
Packit |
0848f5 |
#
|
|
Packit |
0848f5 |
# Algorithm:
|
|
Packit |
0848f5 |
# For each directory (use readdir)
|
|
Packit |
0848f5 |
# Get a list of matching files (filename pattern supplied, default is
|
|
Packit |
0848f5 |
# *.[chi])
|
|
Packit |
0848f5 |
# if a cache file is found
|
|
Packit |
0848f5 |
# read cache file directory
|
|
Packit |
0848f5 |
# compare with source files
|
|
Packit |
0848f5 |
# for each out-of-date or new file, extract information (see below)
|
|
Packit |
0848f5 |
# else mark file as unchanged
|
|
Packit |
0848f5 |
# check for deleted files
|
|
Packit |
0848f5 |
# if any changes
|
|
Packit |
0848f5 |
# read old cache file for info from unchanged files
|
|
Packit |
0848f5 |
# write new directory and data entries
|
|
Packit |
0848f5 |
# else
|
|
Packit |
0848f5 |
# for each file
|
|
Packit |
0848f5 |
# extract information
|
|
Packit |
0848f5 |
# write new directory and data entries
|
|
Packit |
0848f5 |
# (optional) if specified, call routine to process cache file contents
|
|
Packit |
0848f5 |
# (e.g., generate a derived file).
|
|
Packit |
0848f5 |
#
|
|
Packit |
0848f5 |
# Data structures
|
|
Packit |
0848f5 |
# Within a directory
|
|
Packit |
0848f5 |
# fileInfo{filename} = extracted info
|
|
Packit |
0848f5 |
# filesUpdated[] = array of file names that match critera
|
|
Packit |
0848f5 |
# fileInCache{filename} = comparison info
|
|
Packit |
0848f5 |
#
|
|
Packit |
0848f5 |
# -------------------------------------------------------------------------
|
|
Packit |
0848f5 |
use warnings;
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
$gDebug = 0;
|
|
Packit |
0848f5 |
# verbose of 1 gives the least amount of data, higher values give
|
|
Packit |
0848f5 |
# increasing amount of detail. (0, of course, gives no detail)
|
|
Packit |
0848f5 |
$gVerbose = 0;
|
|
Packit |
0848f5 |
$gUpdateAll = 0;
|
|
Packit |
0848f5 |
# -------------------------------------------------------------------------
|
|
Packit |
0848f5 |
# Return an array of regular files in the named directory
|
|
Packit |
0848f5 |
sub GetFileNamesInDirectory {
|
|
Packit |
0848f5 |
my ($dir,$pattern) = @_;
|
|
Packit |
0848f5 |
my @filesFound = ();
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
opendir DIR, $dir || die "Could not open $dir\n";
|
|
Packit |
0848f5 |
while (my $file = readdir DIR) {
|
|
Packit |
0848f5 |
if (! -f "$dir/$file") { next; }
|
|
Packit |
0848f5 |
if ($file =~ /^\.$/ || $file =~ /^\.\.$/) { next; }
|
|
Packit |
0848f5 |
if ($file =~ /$pattern/) {
|
|
Packit |
0848f5 |
$filesFound[$#filesFound+1] = $file;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
closedir DIR;
|
|
Packit |
0848f5 |
return @filesFound;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
# Return a hash of files and their comparison information
|
|
Packit |
0848f5 |
sub ReadCacheDirectory {
|
|
Packit |
0848f5 |
my ($dir, $cachefile) = @_;
|
|
Packit |
0848f5 |
my %fileInCache = ();
|
|
Packit |
0848f5 |
my $found = 0;
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
if (! -f "$dir/$cachefile") { return %fileInCache; }
|
|
Packit |
0848f5 |
open CFD, "<$dir/$cachefile" || return %fileInCache;
|
|
Packit |
0848f5 |
# Look for directory
|
|
Packit |
0848f5 |
while (<CFD>) {
|
|
Packit |
0848f5 |
if (/<dir>/) { $found = 1; last; }
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
if ($found) {
|
|
Packit |
0848f5 |
while (<CFD>) {
|
|
Packit |
0848f5 |
if (/<\/dir>/) { last; }
|
|
Packit |
0848f5 |
if (/<file\s+name=\"([^\"]+)\"\s+info=\"([^\"]+)\"\s*\/>/) {
|
|
Packit |
0848f5 |
$fileInCache{$1} = $2;
|
|
Packit |
0848f5 |
print "Found file $1 in cache\n" if $gDebug;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
close CFD;
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
return %fileInCache;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
# Return a hash of information from each, indexed by filename
|
|
Packit |
0848f5 |
sub ReadCacheContents {
|
|
Packit |
0848f5 |
my ($dir, $cachefile) = @_;
|
|
Packit |
0848f5 |
my %fileInfo = ();
|
|
Packit |
0848f5 |
my $found = 0;
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
if (! -f "$dir/$cachefile") { return %fileInfo; }
|
|
Packit |
0848f5 |
open CFD, "<$dir/$cachefile" || return %fileInfo;
|
|
Packit |
0848f5 |
# Look for data
|
|
Packit |
0848f5 |
while (<CFD>) {
|
|
Packit |
0848f5 |
if (/<data>/) { $found = 1; last; }
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
if ($found) {
|
|
Packit |
0848f5 |
while (<CFD>) {
|
|
Packit |
0848f5 |
if (/<\/data>/) { last; }
|
|
Packit |
0848f5 |
if (/<fileinfo\s+name=\"([^\"]+)\">/) {
|
|
Packit |
0848f5 |
my $filename = $1;
|
|
Packit |
0848f5 |
my $info = "";
|
|
Packit |
0848f5 |
while (<CFD>) {
|
|
Packit |
0848f5 |
if (/<\/fileinfo>/) { last; }
|
|
Packit |
0848f5 |
$info .= $_;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
$fileInfo{$filename} = $info;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
close CFD;
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
return %fileInfo;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
# Print the cache. Pass fileInfo by reference (\%fileInfo)
|
|
Packit |
0848f5 |
sub PrintCacheFile {
|
|
Packit |
0848f5 |
my ($dir,$cachefile,$fileInfo) = @_;
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
open CFD, ">$dir/$cachefile" || die "Could not open $dir/$cachefile\n";
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
print CFD "<dir>\n";
|
|
Packit |
0848f5 |
foreach my $file (keys(%$fileInfo)) {
|
|
Packit |
0848f5 |
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime) =
|
|
Packit |
0848f5 |
stat "$dir/$file";
|
|
Packit |
0848f5 |
print CFD "<file name=\"$file\" info=\"$mtime\"/>\n";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
print CFD "</dir>\n";
|
|
Packit |
0848f5 |
print CFD "<data>\n";
|
|
Packit |
0848f5 |
foreach my $file (keys(%$fileInfo)) {
|
|
Packit |
0848f5 |
print CFD "<fileinfo name=\"$file\">\n";
|
|
Packit |
0848f5 |
print CFD $$fileInfo{$file};
|
|
Packit |
0848f5 |
print CFD "</fileinfo>\n";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
print CFD "</data>\n";
|
|
Packit |
0848f5 |
close CFD;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
sub processFiles {
|
|
Packit |
0848f5 |
my ($dir,$cachefile,$pattern) = @_;
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
my @files = &GetFileNamesInDirectory( $dir, $pattern );
|
|
Packit |
0848f5 |
my %filesInCache = &ReadCacheDirectory( $dir, $cachefile );
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
my @filesToScan = ();
|
|
Packit |
0848f5 |
my @filesDeleted = ();
|
|
Packit |
0848f5 |
my @filesUnchanged = ();
|
|
Packit |
0848f5 |
my %filesInDir = ();
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
print "Number of files matching pattern in $dir is $#files\n" if $gDebug;
|
|
Packit |
0848f5 |
for (my $i=0; $i <= $#files; $i++) {
|
|
Packit |
0848f5 |
$filesInDir{$files[$i]} = 1;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
foreach my $file (keys(%filesInCache)) {
|
|
Packit |
0848f5 |
# Get info on file
|
|
Packit |
0848f5 |
if (-f "$dir/$file") {
|
|
Packit |
0848f5 |
print "Found $file\n" if $gDebug;
|
|
Packit |
0848f5 |
delete $filesInDir{$file};
|
|
Packit |
0848f5 |
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime) =
|
|
Packit |
0848f5 |
stat "$dir/$file";
|
|
Packit |
0848f5 |
if ($mtime > $filesInCache{$file} || $gUpdateAll) {
|
|
Packit |
0848f5 |
# File has been changed since last update
|
|
Packit |
0848f5 |
$filesToScan[$#filesToScan+1] = $file;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
else {
|
|
Packit |
0848f5 |
$filesUnchanged[$#filesUnchanged+1] = $file;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
else {
|
|
Packit |
0848f5 |
# This file has been deleted
|
|
Packit |
0848f5 |
print "File $dir/$file has been deleted since the cache was created\n" if $gDebug;
|
|
Packit |
0848f5 |
$filesDeleted[$#filesDeleted+1] = $file;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
my @filesCreated = keys(%filesInDir);
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# Check for unchanged
|
|
Packit |
0848f5 |
if ($#filesCreated == -1 &&
|
|
Packit |
0848f5 |
$#filesDeleted == -1 &&
|
|
Packit |
0848f5 |
$#filesToScan == -1) {
|
|
Packit |
0848f5 |
# Nothing to do, we can leave the cache file as is
|
|
Packit |
0848f5 |
print "Cache in $dir unchanged\n" if $gDebug || $gVerbose > 1;
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
else {
|
|
Packit |
0848f5 |
if ($gDebug || $gVerbose > 0) {
|
|
Packit |
0848f5 |
# Give a detailed description
|
|
Packit |
0848f5 |
my $sep = "";
|
|
Packit |
0848f5 |
print "Changes in dir $dir: ";
|
|
Packit |
0848f5 |
if ($#fileCreated >= 0) {
|
|
Packit |
0848f5 |
my $num = $#filesCreated + 1;
|
|
Packit |
0848f5 |
print "created = $num";
|
|
Packit |
0848f5 |
$sep = ", ";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
if ($#filesDeleted >= 0) {
|
|
Packit |
0848f5 |
my $num = $#filesDeleted + 1;
|
|
Packit |
0848f5 |
print "${sep}deleted = $num";
|
|
Packit |
0848f5 |
$sep = ", ";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
if ($#filesToScan >= 0) {
|
|
Packit |
0848f5 |
my $num = $#filesToScan + 1;
|
|
Packit |
0848f5 |
print "${sep}changed = $num";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
print "\n";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
# We need to scan some files, adding their info to fileInfo
|
|
Packit |
0848f5 |
my %fileInfo = &ReadCacheContents( $dir, $cachefile );
|
|
Packit |
0848f5 |
for (my $i=0; $i<=$#filesDeleted; $i++) {
|
|
Packit |
0848f5 |
delete $fileInfo{$filesDeleted[$i]};
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
foreach $file (@filesCreated,@filesToScan) {
|
|
Packit |
0848f5 |
print "Scanning file $dir/$file\n" if $gDebug;
|
|
Packit |
0848f5 |
$fileInfo{$file} = &$scanFile( "$dir/$file" );
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
&PrintCacheFile( $dir, $cachefile, \%fileInfo );
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
sub processDirs {
|
|
Packit |
0848f5 |
my ($dir, $cachefile, $pattern) = @_;
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
print "Processing $dir...\n" if $gDebug;
|
|
Packit |
0848f5 |
my @dirs = ();
|
|
Packit |
0848f5 |
# Find the directories
|
|
Packit |
0848f5 |
opendir DIR, "$dir" || die "Cannot open $dir\n";
|
|
Packit |
0848f5 |
while (my $file = readdir DIR) {
|
|
Packit |
0848f5 |
if (! -d "$dir/$file") { next; }
|
|
Packit |
0848f5 |
if ($file =~ /^\./) { next; }
|
|
Packit |
0848f5 |
if ($file =~ /^.svn/) { next; }
|
|
Packit |
0848f5 |
if ($file =~ /autom4te.cache/) { next; }
|
|
Packit |
0848f5 |
$dirs[$#dirs+1] = "$file";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
closedir DIR;
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# For each of these, process it
|
|
Packit |
0848f5 |
for (my $i=0; $i<=$#dirs; $i++) {
|
|
Packit |
0848f5 |
my $ndir = "$dir/$dirs[$i]";
|
|
Packit |
0848f5 |
&processDirs( $ndir, $cachefile, $pattern );
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# process the files in this directory
|
|
Packit |
0848f5 |
&processFiles( $dir, $cachefile, $pattern );
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# This is a general routine to process directories
|
|
Packit |
0848f5 |
sub processDirsAndAction {
|
|
Packit |
0848f5 |
my ($dir, $action, $actionData) = @_;
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
print "Processing $dir...\n" if $gDebug;
|
|
Packit |
0848f5 |
my @dirs = ();
|
|
Packit |
0848f5 |
# Find the directories
|
|
Packit |
0848f5 |
opendir DIR, "$dir" || die "Cannot open $dir\n";
|
|
Packit |
0848f5 |
while (my $file = readdir DIR) {
|
|
Packit |
0848f5 |
if (! -d "$dir/$file") { next; }
|
|
Packit |
0848f5 |
if ($file =~ /^\./) { next; }
|
|
Packit |
0848f5 |
if ($file =~ /^.svn/) { next; }
|
|
Packit |
0848f5 |
if ($file =~ /autom4te.cache/) { next; }
|
|
Packit |
0848f5 |
$dirs[$#dirs+1] = "$file";
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
closedir DIR;
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# For each of these, process it
|
|
Packit |
0848f5 |
for (my $i=0; $i<=$#dirs; $i++) {
|
|
Packit |
0848f5 |
my $ndir = "$dir/$dirs[$i]";
|
|
Packit |
0848f5 |
&processDirsAndAction( $ndir, $action, $actionData );
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
# process the files in this directory
|
|
Packit |
0848f5 |
&$action( $dir, $actionData );
|
|
Packit |
0848f5 |
}
|
|
Packit |
0848f5 |
|
|
Packit |
0848f5 |
1;
|