diff options
Diffstat (limited to 'config')
-rwxr-xr-x | config/cvsu | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/config/cvsu b/config/cvsu new file mode 100755 index 000000000..4c7071fcb --- /dev/null +++ b/config/cvsu @@ -0,0 +1,249 @@ +#!/usr/bin/perl -w +# An efficient substitute for `cvs -n update'. + +use strict; +use Getopt::Long; + +# Do a quick check to see what files are out of date. +# tromey Thu Mar 16 1995 +# +# derived from http://www.cygnus.com/~tromey/ - jmm + +# To Do: +# Add option to include leading (non-`.') directory names of mentioned files + +(my $VERSION = '$Revision: 1.1 $ ') =~ tr/[0-9].//cd; +(my $program_name = $0) =~ s|.*/||; + +my @months = qw (Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec); +my @days = qw (Sun Mon Tue Wed Thu Fri Sat); + +my $debug = 0; + +# If this is set, do only local files. +my $local = 0; + +# If this is set, show conflicts with C +my $conflicts = 0; + +# If this is set, then don't check any dates and just print the names +# of all version-controlled files (but no directories). +my $list_all_files = 0; + +# Regex that matches file (as opposed to dir) entries in CVS/Entries. +# Note that we allow an empty value ('*' vs '+') for timestamp, to +# work around an odd bug in CVS. +my $file_entry_re = qr{^/([^/]+)/([^/]+)/([^/]*)}; + +sub usage ($) +{ + my ($exit_code) = @_; + no strict 'refs'; + no strict 'subs'; + my $STREAM = ($exit_code == 0 ? STDOUT : STDERR); + if ($exit_code != 0) + { + print $STREAM "Try `$program_name --help' for more information.\n"; + } + else + { + print $STREAM <<EOF; +Usage: $program_name [OPTIONS] [DIRECTORY]... + +An efficient substitute for `cvs -n update'. + +In a cvs-checked-out working directory, list all cvs-controlled files +that have been modified (or even touched but not changed), cvs added, or +cvs removed. This script is a lot faster than `cvs -n update' because +it doesn't use the repository. So for people at remote sites, it's MUCH +faster. Also, when you have changes to files in subdirectories, the +listing it produces is more useful since it includes the relative path +name on each line indicating an Added, Removed, or Modified file. + +NOTE: since $program_name works only on the local files it may indicate +files are modified that cvs can determine where merely touched. Similarly +files with a C may have had conflicts that have since been removed. + +Here are the options: + + --list-all-files don't check any dates; just print the names of all + version-controlled files (but no directories) + --local (-l) don't process subdirectories (like cvs' -l option) + --help display this help and exit + --version output version information and exit + --conflicts show conflicts with C instead of the default M + +EOF + } + exit $exit_code; +} + +sub do_directory ($$); + +{ + GetOptions + ( + debug => \$debug, + 'list-all-files' => \$list_all_files, + conflicts => \$conflicts, + local => \$local, + l => \$local, + help => sub { usage 0 }, + version => sub { print "$program_name version $VERSION\n"; exit }, + ) or usage 1; + + unshift (@ARGV, ".") if !@ARGV; + # print "$#ARGV ; $ARGV[0], $ARGV[1]\n"; + foreach (@ARGV) + { + do_directory ($_, 1); + } + + exit 0; +} + +sub do_directory ($$) { + my ($thisdir, $is_command_line_arg) = @_; + + $thisdir =~ s,^\./,,; + my $prefix = ($thisdir eq '.' ? '' : "$thisdir/"); + + print "\tCALL; thisdir = $thisdir\n" + if $debug; + + # Scan CVS/Entries. + my %version; + my %entries; + my %is_dir; + + my $entries_file = "${prefix}CVS/Entries"; + if ( ! open (ENTRIES, '<', $entries_file)) + { + my $warn = $is_command_line_arg ? '' : "Warning: "; + warn "$program_name: ${warn}couldn't open $entries_file: $!\n"; + $is_command_line_arg + and exit 1; + return; + } + + while (<ENTRIES>) { + # Ignore entries for directories. + if (m,^D,) + { + next if /^D$/; + if (m,^D/([^/]+)/,) + { + $is_dir{$1} = 1; + next; + } + # else fall through so we get the `invalid line' error + } + + /$file_entry_re/ + || die "$program_name: $entries_file: $.: invalid line\n"; + $entries{$1} = $3 || 'Empty-Timestamp'; + $version{$1} = $2; + } + close (ENTRIES); + + # process Entries.Log file if it exists + # lines are prefixed by A (add) or R (remove) + # we add or delete accordingly. + my $entries_log_file = "${prefix}CVS/Entries.Log"; + my $type; + if (open (ENTRIES, "< $entries_log_file")) { + while (<ENTRIES>) { + if (!/^([AR]) (.*)$/) { + warn "$program_name: $entries_log_file: $.: unrecognized line format\n"; + next; + } + ($type, $_) = ($1,$2); + # Ignore entries for directories. + if (m,^D,) + { + next if /^D$/; + if (m,^D/([^/]+)/,) + { + if ($type eq 'A') { + $is_dir{$1} = 1; + } else { + delete $is_dir{$1}; + } + next; + } + # else fall through so we get the `invalid line' error + } + + /$file_entry_re/ + || die "$program_name: $entries_log_file: $.: invalid line\n"; + if ($type eq 'A') { + $entries{$1} = $3; + $version{$1} = $2; + } else { + delete $entries{$1}; + delete $version{$1}; + } + } + close (ENTRIES); + } + + foreach (sort keys %entries) { + # Handle directories later. + die "$program_name: bogus entry: $prefix$_\n" + if ($_ eq 'CVS' || $_ eq '.' || $_ eq '..'); + (print "$prefix$_\n"), next if $list_all_files; + next if -l "$prefix$_"; + next unless $entries{$_}; + if ($version{$_} =~ /^-/) + { + # A negative revision number (e.g., `-1.9') means the file is + # slated for removal. + print "R $prefix$_\n"; + next; + } + elsif ($version{$_} eq '0') + { + # A revision number of `0' means the file is slated for addition. + print "A $prefix$_\n"; + next; + } + + # These strings appear in the date field only for additions + # and removals. + die "$program_name: unexpected entry for $_: $entries{$_}\n" + if $entries{$_} eq 'dummy timestamp' + || $entries{$_} =~ /^Initial /; + + next unless -f _; + + my $mtime = (stat _) [9]; + print "\t$mtime $_\n" + if $debug; + my ($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime ($mtime); + my $s = ($days[$wday] . ' ' . $months[$mon] . ' ' + . sprintf ("%2d %02d:%02d:%02d %02d", $mday, $hour, $min, + $sec, 1900 + $year)); + if ($entries{$_} ne $s) { + my $t = 'M'; + $t = 'C' + if ($conflicts && $entries{$_} =~ /^Result of merge\+/); + print "$t $prefix$_\n"; + if ($debug) { + print "\t$entries{$_}\n"; + print "\t$s\n"; + print "================\n"; + } + } + } + + # Now do directories. + if (!$local) + { + foreach (sort keys %is_dir) + { + print "\tdir = $thisdir, _ = $_\n" + if $debug; + do_directory ("$prefix$_", 0); + } + } +} |