hi,
attached are 2 files: a script that checks all files for the Last
Changed Date according to SVN, and updates the file if its year >
copyright notice in the file. I'm not very good with Perl, so it might
be badly programmed... However, it only needs running once.
The 2nd file is a test, and again, this only needs to run once a year.
Issues with the test file:
* I redirect stderr to stdout, maybe it needs to be restored later, but
I can imagine each test is a new invocation of perl, so in that case
it's not necessary.
* if it finds a file that is literally out of date (it needs copyright
notice update), it will only give an error message, not the file name
(which should really be the case, otherwise, you don't know what file to
fix)
* on ctrl-c it won't stop (well, for 1 second after which it
continues...) I guess it has to do with me using File::Find...
The test file can just be put in the parrot/t/configure directory, that
one will be run first when doing make test (so you don't have to wait
for it to run)
hope this helps,
klaas-jan
#! perl
# Copyright (C) 2007, The Perl Foundation.
=head1 NAME
adjustcopyright.t - check copyright for all files in the parrot distr.
=head1 SYNOPSIS
=head1 DESCRIPTION
This test checks the "Last Changed Date" according to SVN for the year
it was changed. Then it looks in the file being processed for a copyright
notice, and extracts the year. Then, if $SVNYear > $fileYear, fail test
(and the copyright should be updated).
=head1 ISSUES
=over 4
=item *
C^C won't stop the testing...
=item *
How to restore stderr after having it redirected to stdout?
=cut
use strict;
use warnings;
use lib qw( . lib ../lib ../../lib );
use File::Find;
use Parrot::Test;
use Parrot::Config;
use Test::More;
# don't know how many files will be tested:
plan tests => 1;
sub vdiag(@) { &diag if $ENV{TEST_VERBOSE} }
sub checkCopyright {
my $file = $_;
# only handle files, not directories
return unless -f $file;
# only handle text files
return unless -T $file;
# if there's '.svn' in the filename, it's the directory
(probably?)
return if $File::Find::name =~ m/.*\.svn.*/;
my $cmd = "svn info $File::Find::name";
#
# FIXME: restore stderr->stdout after we're done.
#
my $output = `$cmd 2>&1`;
my $SVNYear = undef; # to
store the year according to SVN
if ($output =~ m/.*Last Changed Date:\s+(\d\d\d\d).*/) {
$SVNYear = $1;
}
else {
return;
}
open(FILE, "< $File::Find::name") or die "cannot open file
$File::Find::name";
while(<FILE>) {
# on failure, it should emit the failing file's name so
we can fix it!
# check for copyright lines containing only 1 year; note the matching
space here.
if ($_ =~ m/.*[cC]opyright[^[\d\d\d\d\-]]*(\d\d\d\d).*/ ) { # check for
match
# ok found it, now compare with $SVNYear
# only change when SVN Year > current
is($1, $SVNYear);
}
# check for copyright lines like X-Y
elsif ($_ =~ m/.*[cC]opyright[^\d]*\d\d\d\d\-(\d\d\d\d).*/ ) {
is($1, $SVNYear);
}
}
close(FILE);
}
{
# set $parrotRootDir to parrot build directory:
my $parrotRootDir = $PConfig{'build_dir'};
# find takes an array containing directories to
# be processed, we only have 1 directory: parrot
my @dirlist = ();
push @dirlist, $parrotRootDir;
# check copyright for each file.
find(\&checkCopyright, @dirlist);
}
#
# Start of a script to recursively process all files in a directory to change
the copyright notice.
#
use File::Find;
use strict;
use warnings;
my @unhandled_files = ();
my @handled_files = ();
sub process_file {
my $oldValue = 2006; # the minimal value for a year
to be replaced
my $shouldChange = 0; # flag only set when file was changed in a year
later than it's copyright notice year.
my $file = $_;
# only handle files, not directories
return unless -f $file;
# only handle text files
return unless -T $file;
# only handle file if it is writable
return unless -w $file;
# open file for reading and writing
open(FILE, "+< $file") or die "can't open file $File::Find::name: $!";
my $filename = $File::Find::name;
unless (-e $filename) {
die "File $filename does not exist!\n";
} else {
print "Handling file $filename\n";
}
print "Getting SVN info from $File::Find::name...\n";
my $str = "svn info $filename > svninfo.txt";
print "\nExecuting:\n$str";
# <allison> kjs: may make sense to just use 'capture_output' from
lib/Parrot/Configure/Step.pm
# (instead of system)
system($str);
open(TEMPFILE, "< svninfo.txt") or die "cannot open file svninfo.txt";
my $SVNYear = undef; # to store the
year according to SVN
while(<TEMPFILE>) {
# get the year from that line:
if ($_ =~ m/Last Changed Date:\s+(\d\d\d\d).*/) {
print "\nMatched: $_'\nYear: $1\n";
$SVNYear = $1;
}
}
close(TEMPFILE);
unless (defined $SVNYear) {
print "Mmmm: no 'Last Changed Date' according to SVN\nSkipping file
$File::Find::name\n";
push @unhandled_files, $filename;
return;
}
# buffer to store file contents
my $filebuffer = '';
# read file line by line
while(<FILE>) {
# flag indicating whether the file has been changed yet
my $changed = 0;
# check for copyright lines containing only 1 year; note the matching
space here.
if ($_ =~ m/.*[cC]opyright[^[\d\d\d\d\-]]*(\d\d\d\d).*/ ) { # check for
match
print "Found copyright notice with year $1\n";
# ok found it, now compare with $SVNYear
# only change when SVN Year > current
if ($SVNYear > $1) {
print "CASE 1\n";
print "Ok, the 'Last Changed Date' according to SVN is:
$SVNYear.\n";
print "This is a later date than the current copyright
notice date, which is $1.\n";
print "I'll change\n\t'$_'\n\tinto: ";
# change a notice like '2006' into '2006-2007'
$_ =~ s/$1/$1\-$SVNYear/;
print $_;
print "\n";
# add line to file buffer
$filebuffer .= $_;
# set changed flag
$changed = 1;
}
}
# check for copyright lines like X-Y
elsif ($_ =~ m/.*[cC]opyright[^\d]*\d\d\d\d\-(\d\d\d\d).*/ ) {
if ($SVNYear > $1) {
print "CASE 2\n";
print "Ok, the 'Last Changed Date' according to SVN is:
$SVNYear.\n";
print "This is a later date than the current copyright
notice date, which is $1.\n";
print "I'll change\n\t'$_'\n\tinto: ";
# make sure only the 'Y', not 'X', in 'X-Y' is changed
$_ =~ s/\-$1/\-$SVNYear/;
print $_;
print "\n";
$filebuffer .= $_;
$changed = 1;
}
}
# if the line was not changed, it was not a copyright notice,
# therefore not added yet. So add it to the buffer now.
if($changed == 0) {
$filebuffer .= $_;
}
}
# end of file reached, now write the buffer back to file again.
# this code is taken from the Perl Cookbook.
seek(FILE, 0, 0) or die "can't seek to start of $file:
$!";
print FILE $filebuffer or die "can't print to $file:
$!";
truncate(FILE, tell(FILE)) or die "can't truncate $file:
$!";
close(FILE) or die "can't close $file: $!";
print "Handled file $file\n";
push @handled_files, $filename;
}
if (@ARGV < 1) {
print <<'USAGE'
Usage: perl changeCopyright <directory>
Updates the copyright notice to the year from SVN according to the
'Last Changed Date' for all files in <directory>.
Please give the FULL path to the directory (on windows this could be
'c:\parrot')
USAGE
}
else {
my @DIRLIST = ();
push @DIRLIST, $ARGV[0];
find(\&process_file, @DIRLIST);
if(@unhandled_files) {
open UNHANDLED, "> unhandledfiles.txt";
print "Unhandled files:\n";
while(@unhandled_files) {
my $file = shift @unhandled_files;
print UNHANDLED "$file\n";
}
close UNHANDLED;
}
if(@handled_files) {
open HANDLED, "> handledfiles.txt";
print "handled files:\n";
while(@handled_files) {
my $file = shift @handled_files;
print HANDLED "$file\n";
}
close HANDLED;
}
}
# TODO: compile a list of files that has been changed by this script.