git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 5/7] cvsserver: Implement update -p (print to stdout)

From
Damien Diederen <dash@foobox.net>
Date
Mar 27, 2008, 22:18 UTC
Message-ID
<e95fde851fdc6ef39f32054cba6cde0ae975b8fd.1206654905.git.dash@foobox.net>
In-Reply-To
<cover.1206393086.git.dash@foobox.net>

Cvs update -p -r <rev> <path> is the documented way to retrieve a specific revision of a file (similar to git show <rev>:<path>). Without this patch, the -p flag is ignored and status output is produced, causing clients to interpret it as the contents of the file.

TkCVS uses update -p as a basis for implementing its various "View" and "Diff" commands.

Signed-off-by: Damien Diederen <dash@foobox.net>
---
 git-cvsserver.perl |   47 +++++++++++++++++++++++++++++++++++------------
 1 files changed, 35 insertions(+), 12 deletions(-)
diff --git a/git-cvsserver.perl b/git-cvsserver.perl
index 89a4dac..49c0ba2 100755
--- a/git-cvsserver.perl
+++ b/git-cvsserver.perl
@@ -963,6 +963,17 @@ sub req_update
             $meta = $updater->getmeta($filename);
         }
 
+        # If -p was given, "print" the contents of the requested revision.
+        if ( exists ( $state->{opt}{p} ) ) {
+            if ( defined ( $meta->{revision} ) ) {
+                $log->info("Printing '$filename' revision " . $meta->{revision});
+
+                transmitfile($meta->{filehash}, { print => 1 });
+            }
+
+            next;
+        }
+
 	if ( ! defined $meta )
 	{
 	    $meta = {
@@ -1096,9 +1107,9 @@ sub req_update
             my $file_local = $filepart . ".mine";
             system("ln","-s",$state->{entries}{$filename}{modified_filename}, $file_local);
             my $file_old = $filepart . "." . $oldmeta->{revision};
-            transmitfile($oldmeta->{filehash}, $file_old);
+            transmitfile($oldmeta->{filehash}, { targetfile => $file_old });
             my $file_new = $filepart . "." . $meta->{revision};
-            transmitfile($meta->{filehash}, $file_new);
+            transmitfile($meta->{filehash}, { targetfile => $file_new });
 
             # we need to merge with the local changes ( M=successful merge, C=conflict merge )
             $log->info("Merging $file_local, $file_old, $file_new");
@@ -1550,14 +1561,14 @@ sub req_diff
                 print "E File $filename at revision 1.$revision1 doesn't exist\n";
                 next;
             }
-            transmitfile($meta1->{filehash}, $file1);
+            transmitfile($meta1->{filehash}, { targetfile => $file1 });
         }
         # otherwise we just use the working copy revision
         else
         {
             ( undef, $file1 ) = tempfile( DIR => $TEMP_DIR, OPEN => 0 );
             $meta1 = $updater->getmeta($filename, $wrev);
-            transmitfile($meta1->{filehash}, $file1);
+            transmitfile($meta1->{filehash}, { targetfile => $file1 });
         }
 
         # if we have a second -r switch, use it too
@@ -1572,7 +1583,7 @@ sub req_diff
                 next;
             }
 
-            transmitfile($meta2->{filehash}, $file2);
+            transmitfile($meta2->{filehash}, { targetfile => $file2 });
         }
         # otherwise we just use the working copy
         else
@@ -1585,7 +1596,7 @@ sub req_diff
         {
             ( undef, $file2 ) = tempfile( DIR => $TEMP_DIR, OPEN => 0 );
             $meta2 = $updater->getmeta($filename, $wrev);
-            transmitfile($meta2->{filehash}, $file2);
+            transmitfile($meta2->{filehash}, { targetfile => $file2 });
         }
 
         # We need to have retrieved something useful
@@ -2014,14 +2025,17 @@ sub revparse
     return undef;
 }
 
-# This method takes a file hash and does a CVS "file transfer" which transmits the
-# size of the file, and then the file contents.
-# If a second argument $targetfile is given, the file is instead written out to
-# a file by the name of $targetfile
+# This method takes a file hash and does a CVS "file transfer".  Its
+# exact behaviour depends on a second, optional hash table argument:
+# - If $options->{targetfile}, dump the contents to that file;
+# - If $options->{print}, use M/MT to transmit the contents one line
+#   at a time;
+# - Otherwise, transmit the size of the file, followed by the file
+#   contents.
 sub transmitfile
 {
     my $filehash = shift;
-    my $targetfile = shift;
+    my $options = shift;
 
     if ( defined ( $filehash ) and $filehash eq "deleted" )
     {
@@ -2043,11 +2057,20 @@ sub transmitfile
 
     if ( open my $fh, '-|', "git-cat-file", "blob", $filehash )
     {
-        if ( defined ( $targetfile ) )
+        if ( defined ( $options->{targetfile} ) )
         {
+            my $targetfile = $options->{targetfile};
             open NEWFILE, ">", $targetfile or die("Couldn't open '$targetfile' for writing : $!");
             print NEWFILE $_ while ( <$fh> );
             close NEWFILE or die("Failed to write '$targetfile': $!");
+        } elsif ( defined ( $options->{print} ) && $options->{print} ) {
+            while ( <$fh> ) {
+                if( /\n\z/ ) {
+                    print 'M ', $_;
+                } else {
+                    print 'MT text ', $_, "\n";
+                }
+            }
         } else {
             print "$size\n";
             print while ( <$fh> );
-- 
1.5.5.rc1.19.gfe7681
Previous: Damien DiederenNext: Damien Diederen
Message 20 of 22 in “Enhance TkCVS interoperability”
  1. 0/7 Enhance TkCVS interoperabilityDamien Diederen, Mar 24, 2008
  2. 1/7 cvsserver: Respond to the 'editors' commandDamien Diederen, Mar 24, 2008
  3. Frank LichtenheldMar 25, 2008
  4. 2/7 cvsserver: Only print the file part of the filename in status headerDamien Diederen, Mar 24, 2008
  5. 3/7 cvsserver: Do not include status output for subdirectories if -l is passedDamien Diederen, Mar 24, 2008
  6. 4/7 cvsserver: Add a few tests for 'status' commandDamien Diederen, Mar 24, 2008
  7. 5/7 cvsserver: Implemented update -p (print to stdout)Damien Diederen, Mar 24, 2008
  8. 6/7 cvsserver: Added test for update -pDamien Diederen, Mar 24, 2008
  9. 7/7 cvsserver: Use the user part of the email in log and annotate resultsDamien Diederen, Mar 24, 2008
  10. Frank LichtenheldMar 25, 2008
  11. Rafael Garcia-SuarezMar 25, 2008
  12. Damien DiederenMar 25, 2008
  13. Junio C HamanoMar 25, 2008
  14. 0/7 Enhance TkCVS interoperabilityDamien Diederen, Mar 27, 2008
  15. Junio C HamanoMar 28, 2008
  16. 1/7 cvsserver: Respond to the 'editors' and 'watchers' commandsDamien Diederen, Mar 27, 2008
  17. 2/7 cvsserver: Only print the file part of the filename in status headerDamien Diederen, Mar 27, 2008
  18. 3/7 cvsserver: Do not include status output for subdirectories if -l is passedDamien Diederen, Mar 27, 2008
  19. 4/7 cvsserver: Add a few tests for 'status' commandDamien Diederen, Mar 27, 2008
  20. 5/7 cvsserver: Implement update -p (print to stdout)Damien Diederen, Mar 27, 2008
  21. 6/7 cvsserver: Add test for update -pDamien Diederen, Mar 27, 2008
  22. 7/7 cvsserver: Use the user part of the email in log and annotate resultsDamien Diederen, Mar 27, 2008

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.