cvs-utils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

`cvsdo diff'


From: Tom Tromey
Subject: `cvsdo diff'
Date: 01 Jul 2001 13:12:24 -0600

Sorry for the cross post.  I think this is of interest to both
projects.  I'm trying to make it possible to use both utilities at
once.

The appended patch (made with Alexandre's "cvsdiff" :-) changes the
cvsutils `cvsdiff' to `cvsdo diff', which seems more natural to me.
It also adds a few TODO items for `cvsdo diff'.

Tom

Index: ChangeLog
from  Tom Tromey  <address@hidden>

        * README: Document `cvsdo diff'.
        * Makefile.am (plscripts): Removed cvsdiff.
        (plscripts_src): Removed cvsdiff.pl.
        * cvsdiff.pl: Removed.
        * cvsdo.pl (Main): Handle `diff'.  Anchor command-matching regular
        expression.
        (offline_diff): New function.  Taken from cvsdiff.pl `Main'
        (offline_diff): Modified to handle files on command line.
        (handle_added, handle_removed, handle_modified, diff_print,
        warning): From cvsdiff.pl.
        Use `Time::Local'.

Index: Makefile.am
===================================================================
RCS file: /usr/local/cvs/cvsutils/Makefile.am,v
retrieving revision 1.5
diff -u -r1.5 Makefile.am
--- Makefile.am 2001/05/16 19:08:49 1.5
+++ Makefile.am 2001/07/01 18:51:08
@@ -5,8 +5,8 @@
 shscripts = cvsco cvsdiscard cvspurge cvstrim cvsrmadm
 shscripts_src = cvsco.sh cvsdiscard.sh cvspurge.sh cvstrim.sh cvsrmadm.sh
 
-plscripts = cvsu cvsdo cvsdiff cvschroot
-plscripts_src = cvsu.pl cvsdo.pl cvsdiff.pl cvschroot.pl
+plscripts = cvsu cvsdo cvschroot
+plscripts_src = cvsu.pl cvsdo.pl cvschroot.pl
 
 bin_SCRIPTS = $(shscripts) $(plscripts)
 CLEANFILES = $(bin_SCRIPTS)
Index: README
===================================================================
RCS file: /usr/local/cvs/cvsutils/README,v
retrieving revision 1.14
diff -u -r1.14 README
--- README 2001/05/16 19:08:49 1.14
+++ README 2001/07/01 18:51:08
@@ -97,23 +97,6 @@
  Note that the backups for modified files are removed. cvstrim relies
 
 
-                               cvsdiff
-
-cvsdiff is an offline "cvs diff"
- "cvsdiff" tries to locate the backup copies of the modified files. If they
-can be found, cvsdiff compares them with the current version using "diff"
- Only those backup copies are used, that have the modification date equal
-the date listed in CVS/Entries for the modified file
- "cvsdiff" patches the diff output to make it more robust to apply.
-An exception is made for files named "ChangeLog" - in this case "diff" will
-be instructed to omit all context lines, so that the patch can be applied
-even if other changes have been written to the ChangeLog.
- Also the added files are handled properly. The header of the "diff" output
-is patched in such way, that at least GNU patch will create a new file when
-the resulting patch is applied and remove that file when the patch is
-reverted
-
-
                                cvschroot
 
 cvschroot makes it possible to change CVS/Root in all subdirectories to
@@ -134,8 +117,23 @@
 
                                cvsdo
 
-cvsdo simulates some of the CVS commands (currently add and remove) without
-any access to the CVS server.
+cvsdo simulates some of the CVS commands (currently add, remove, and
+diff) without any access to the CVS server.
 You can now create diffs with "cvs diff -N", and all removed and added
 files will be mentioned there as such, even if you only have read-only
 access to the repository
+
+"cvsdo diff" is an offline "cvs diff"
+ "cvsdo diff" tries to locate the backup copies of the modified
+files. If they can be found, cvsdiff compares them with the current
+version using "diff"
+ Only those backup copies are used, that have the modification date equal
+the date listed in CVS/Entries for the modified file
+ "cvsdo diff" patches the diff output to make it more robust to apply.
+An exception is made for files named "ChangeLog" - in this case "diff" will
+be instructed to omit all context lines, so that the patch can be applied
+even if other changes have been written to the ChangeLog.
+ Also the added files are handled properly. The header of the "diff" output
+is patched in such way, that at least GNU patch will create a new file when
+the resulting patch is applied and remove that file when the patch is
+reverted
Index: TODO
===================================================================
RCS file: /usr/local/cvs/cvsutils/TODO,v
retrieving revision 1.24
diff -u -r1.24 TODO
--- TODO 2000/06/24 00:03:49 1.24
+++ TODO 2001/07/01 18:51:08
@@ -11,3 +11,5 @@
 cvsdep - "cvsdo touch Makefile.in" and other dependent stuff
 "cvsdo prune" offline prune empty directories
 cvsdiff - handle "cvs remove"d files properly
+"cvsdo diff" - read .cvsrc for diff options; handle diff options
+    from command line; handle files for diffing on command line
Index: cvsdo.pl
===================================================================
RCS file: /usr/local/cvs/cvsutils/cvsdo.pl,v
retrieving revision 1.2
diff -u -r1.2 cvsdo.pl
--- cvsdo.pl 2000/06/23 22:50:07 1.2
+++ cvsdo.pl 2001/07/01 18:51:08
@@ -4,6 +4,7 @@
 # CVS repositories
 
 require 5.004;
+use Time::Local;
 use Getopt::Long;
 use strict;
 
@@ -30,10 +31,14 @@
 
        my $command = shift (@ARGV);
 
-       if ( $want_ver || !$command || ($command !~ /(add|remove)/) ) {
+       if ( $want_ver || !$command || ($command !~ /^(add|remove|diff)$/) ) {
                usage();
        }
 
+       if ($command eq 'diff') {
+               offline_diff (@ARGV);
+               return;
+       }
        if ( $#ARGV < 0 ) {
                error ("No files specified\n");
        }
@@ -123,6 +128,150 @@
                ( unlink $file || error ("Cannot delete file $file\n") );
 }
 
+sub offline_diff
+{
+        my (@files) = @_;
+
+       if (scalar @files > 0) {
+               error ("`cvsdo diff' takes no arguments");
+       }
+
+       open(CVSADM, "cvsu --ignore --types AMRO |") ||
+               error ("Cannot read output of cvsu: $!");
+
+       while (<CVSADM>) {
+               chomp;
+               if ($_ !~ m{^([AMRO]) (.*)$}) {
+                       error ("Unrecognized output from cvsu");
+               }
+               my $type = $1;
+               my $file = $2;
+               if ($type eq "A") {
+                       handle_added ($file);
+               }
+               elsif ($type eq "R") {
+                       handle_removed ($file);
+               }
+               else {
+                       handle_modified ($file);
+               }
+       }
+}
+
+# Handle added files
+sub handle_added
+{
+       my $file = shift(@_);
+       open(DIFFOUT, "diff -u -L /dev/null -L $file /dev/null $file |") ||
+               error ("Cannot read output of diff: $!");
+       diff_print ("Index: $file");
+       while (<DIFFOUT>) {
+               diff_print ($_);
+       }
+}
+
+# Handle removed files
+sub handle_removed
+{
+       my $file = shift(@_);
+       # FIXME: scan for backup copies, as in handle_modified()
+       # Any ideas about how to make `patch' erase that file?
+       diff_print ("File $file should be removed!\n");
+}
+
+# Handle modified files
+sub handle_modified
+{
+       my $file = shift(@_);
+       # split into directory and file name
+       $file =~ m{^((.*/)?)([^/]+)};
+       my $short_file = $3;
+       my $dir = $1;
+       my %months = (
+               "Jan" => 0,
+               "Feb" => 1,
+               "Mar" => 2,
+               "Apr" => 3,
+               "May" => 4,
+               "Jun" => 5,
+               "Jul" => 6,
+               "Aug" => 7,
+               "Sep" => 8,
+               "Oct" => 9,
+               "Nov" => 10,
+               "Dec" => 11
+       );
+
+       # Lookup the original timestamp in CVS/Entries
+       open (ENTRIES, "< ${dir}CVS/Entries")
+               || error ("couldn't open ${dir}CVS/Entries: $!");
+       my $date_str;
+       while (<ENTRIES>) {
+               if ( m{^/$short_file/[^/]*/([^/]+)/} ) {
+                       $date_str = $1;
+                       last;
+               }
+       }
+       unless (defined $date_str) {
+               error ("$file is not listed in ${dir}CVS/Entries");
+       }
+       close (ENTRIES);
+
+       unless ($date_str =~ m{^(...) (...) (..) (..):(..):(..) (....)$}) {
+               error ("Invalid timestamp for $file: $date_str");
+       }
+
+       my $basetime = timegm($6, $5, $4, $3, $months{$2}, $7 - 1900);
+
+       # Scan the directory for similar files
+       my $backup_file;
+       opendir (DIR, $dir eq "" ? "." : $dir) ||
+               error ("Cannot open directory $dir: $!");
+       foreach (readdir (DIR)) {
+               m{$short_file} || next;;
+               my $candidate = $dir . $_;
+               stat ($candidate) || next;
+               if ($basetime == (stat _) [9]) {
+                       $backup_file = $candidate;
+                       last;
+               }
+       }
+       closedir (DIR);
+
+       unless (defined $backup_file) {
+               warning ("Backup file for $file not found");
+               return;
+       }
+
+       my $diff_opts = "-u";
+       if ($short_file eq "ChangeLog") {
+               $diff_opts = "-u1";
+       }
+
+       open(DIFFOUT,
+            "diff $diff_opts -L $file -L $file $backup_file $file |") ||
+               error ("Cannot read output of diff: $!");
+       diff_print ("Index: $file");
+       while (<DIFFOUT>) {
+               diff_print ($_);
+       }
+}
+
+# print message and make sure that it ends with a UNIX-style newline
+sub diff_print
+{
+       my $msg = shift(@_);
+       chomp $msg;
+       print $msg . "\012";
+}
+
+# print a warning message
+# newline is added at the end
+sub warning
+{
+       print STDERR "cvsdiff: WARNING: " . shift(@_) . "\n";
+}
+
 # print message and exit (like "die", but without raising an exception)
 sub error
 {
@@ -140,7 +289,8 @@
        "       add             Add a new file\n" .
        "         -f | --force    Don't check whether the file exists\n" .
        "       remove          Remove a file\n" .
-       "         -f | --force    Delete existing files\n";
+       "         -f | --force    Delete existing files\n" .
+       "       diff            Print diffs for files\n";
        exit 1;
 }
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]