Merge branch 'ar/batch-cat'
authorJunio C Hamano <gitster@pobox.com>
Sun, 25 May 2008 20:38:06 +0000 (13:38 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sun, 25 May 2008 20:38:06 +0000 (13:38 -0700)
* ar/batch-cat:
change quoting in test t1006-cat-file.sh
builtin-cat-file.c: use parse_options()
git-svn: Speed up fetch
Git.pm: Add hash_and_insert_object and cat_blob
Git.pm: Add command_bidi_pipe and command_close_bidi_pipe
git-hash-object: Add --stdin-paths option
Add more tests for git hash-object
Move git-hash-object tests from t5303 to t1007
git-cat-file: Add --batch option
git-cat-file: Add --batch-check option
git-cat-file: Make option parsing a little more flexible
git-cat-file: Small refactor of cmd_cat_file
Add tests for git cat-file

1  2 
git-svn.perl
diff --combined git-svn.perl
index 0e61897b9ecc255d3d22d016b46c90d3a30e9f38,33e9266fe689609034bb69da694f877ad6191672..37976f25057ac5d3c91a13ab8564a4cb40f59f79
@@@ -4,7 -4,7 +4,7 @@@
  use warnings;
  use strict;
  use vars qw/  $AUTHOR $VERSION
-               $sha1 $sha1_short $_revision
+               $sha1 $sha1_short $_revision $_repository
                $_q $_authors %users/;
  $AUTHOR = 'Eric Wong <normalperson@yhbt.net>';
  $VERSION = '@@GIT_VERSION@@';
@@@ -65,8 -65,7 +65,8 @@@ my ($_stdin, $_help, $_edit
        $_template, $_shared,
        $_version, $_fetch_all, $_no_rebase,
        $_merge, $_strategy, $_dry_run, $_local,
 -      $_prefix, $_no_checkout, $_url, $_verbose);
 +      $_prefix, $_no_checkout, $_url, $_verbose,
 +      $_git_format);
  $Git::SVN::_follow_parent = 1;
  my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username,
                      'config-dir=s' => \$Git::SVN::Ra::config_dir,
@@@ -83,7 -82,6 +83,7 @@@ my %fc_opts = ( 'follow-parent|follow!
                'repack-flags|repack-args|repack-opts=s' =>
                   \$Git::SVN::_repack_flags,
                'use-log-author' => \$Git::SVN::_use_log_author,
 +              'add-author-from' => \$Git::SVN::_add_author_from,
                %remote_opts );
  
  my ($_trunk, $_tags, $_branches, $_stdlayout);
@@@ -190,7 -188,7 +190,7 @@@ my %cmd = 
                    { 'url' => \$_url, } ],
        'blame' => [ \&Git::SVN::Log::cmd_blame,
                    "Show what revision and author last modified each line of a file",
 -                  {} ],
 +                  { 'git-format' => \$_git_format } ],
  );
  
  my $cmd;
@@@ -222,12 -220,13 +222,13 @@@ unless ($cmd && $cmd =~ /(?:clone|init|
                }
                $ENV{GIT_DIR} = $git_dir;
        }
+       $_repository = Git->repository(Repository => $ENV{GIT_DIR});
  }
  
  my %opts = %{$cmd{$cmd}->[2]} if (defined $cmd);
  
  read_repo_config(\%opts);
 -Getopt::Long::Configure('pass_through') if ($cmd && $cmd eq 'log');
 +Getopt::Long::Configure('pass_through') if ($cmd && ($cmd eq 'log' || $cmd eq 'blame'));
  my $rv = GetOptions(%opts, 'help|H|h' => \$_help, 'version|V' => \$_version,
                      'minimize-connections' => \$Git::SVN::Migration::_minimize,
                      'id|i=s' => \$Git::SVN::default_ref_id,
@@@ -303,6 -302,7 +304,7 @@@ sub do_git_init_db 
                        }
                }
                command_noisy(@init_db);
+               $_repository = Git->repository(Repository => ".git");
        }
        my $set;
        my $pfx = "svn-remote.$Git::SVN::default_repo_id";
@@@ -319,6 -319,7 +321,7 @@@ sub init_subdir 
        mkpath([$repo_path]) unless -d $repo_path;
        chdir $repo_path or die "Couldn't chdir to $repo_path: $!\n";
        $ENV{GIT_DIR} = '.git';
+       $_repository = Git->repository(Repository => $ENV{GIT_DIR});
  }
  
  sub cmd_clone {
@@@ -616,7 -617,7 +619,7 @@@ sub cmd_create_ignore 
                print GITIGNORE "$s\n";
                close(GITIGNORE)
                  or fatal("Failed to close `$ignore': $!");
 -              command_noisy('add', $ignore);
 +              command_noisy('add', '-f', $ignore);
        });
  }
  
@@@ -1013,28 -1014,17 +1016,28 @@@ sub get_commit_entry 
                my ($msg_fh, $ctx) = command_output_pipe('cat-file',
                                                         $type, $treeish);
                my $in_msg = 0;
 +              my $author;
 +              my $saw_from = 0;
                while (<$msg_fh>) {
                        if (!$in_msg) {
                                $in_msg = 1 if (/^\s*$/);
 +                              $author = $1 if (/^author (.*>)/);
                        } elsif (/^git-svn-id: /) {
                                # skip this for now, we regenerate the
                                # correct one on re-fetch anyways
                                # TODO: set *:merge properties or like...
                        } else {
 +                              if (/^From:/ || /^Signed-off-by:/) {
 +                                      $saw_from = 1;
 +                              }
                                print $log_fh $_ or croak $!;
                        }
                }
 +              if ($Git::SVN::_add_author_from && defined($author)
 +                  && !$saw_from) {
 +                      print $log_fh "\nFrom: $author\n"
 +                            or croak $!;
 +              }
                command_close_pipe($msg_fh, $ctx);
        }
        close $log_fh or croak $!;
@@@ -1261,7 -1251,7 +1264,7 @@@ use constant rev_map_fmt => 'NH40'
  use vars qw/$default_repo_id $default_ref_id $_no_metadata $_follow_parent
              $_repack $_repack_flags $_use_svm_props $_head
              $_use_svnsync_props $no_reuse_existing $_minimize_url
 -          $_use_log_author/;
 +          $_use_log_author $_add_author_from/;
  use Carp qw/croak/;
  use File::Path qw/mkpath/;
  use File::Copy qw/copy/;
@@@ -3030,6 -3020,7 +3033,7 @@@ use vars qw/@ISA/
  use strict;
  use warnings;
  use Carp qw/croak/;
+ use File::Temp qw/tempfile/;
  use IO::File qw//;
  
  # file baton members: path, mode_a, mode_b, pool, fh, blob, base
@@@ -3185,14 -3176,9 +3189,9 @@@ sub apply_textdelta 
        my $base = IO::File->new_tmpfile;
        $base->autoflush(1);
        if ($fb->{blob}) {
-               defined (my $pid = fork) or croak $!;
-               if (!$pid) {
-                       open STDOUT, '>&', $base or croak $!;
-                       print STDOUT 'link ' if ($fb->{mode_a} == 120000);
-                       exec qw/git-cat-file blob/, $fb->{blob} or croak $!;
-               }
-               waitpid $pid, 0;
-               croak $? if $?;
+               print $base 'link ' if ($fb->{mode_a} == 120000);
+               my $size = $::_repository->cat_blob($fb->{blob}, $base);
+               die "Failed to read object $fb->{blob}" unless $size;
  
                if (defined $exp) {
                        seek $base, 0, 0 or croak $!;
@@@ -3233,14 -3219,18 +3232,18 @@@ sub close_file 
                                sysseek($fh, 0, 0) or croak $!;
                        }
                }
-               defined(my $pid = open my $out,'-|') or die "Can't fork: $!\n";
-               if (!$pid) {
-                       open STDIN, '<&', $fh or croak $!;
-                       exec qw/git-hash-object -w --stdin/ or croak $!;
+               my ($tmp_fh, $tmp_filename) = File::Temp::tempfile(UNLINK => 1);
+               my $result;
+               while ($result = sysread($fh, my $string, 1024)) {
+                       syswrite($tmp_fh, $string, $result);
                }
-               chomp($hash = do { local $/; <$out> });
-               close $out or croak $!;
+               defined $result or croak $!;
+               close $tmp_fh or croak $!;
                close $fh or croak $!;
+               $hash = $::_repository->hash_and_insert_object($tmp_filename);
                $hash =~ /^[a-f\d]{40}$/ or die "not a sha1: $hash\n";
                close $fb->{base} or croak $!;
        } else {
@@@ -3566,13 -3556,8 +3569,8 @@@ sub chg_file 
        } elsif ($m->{mode_a} =~ /^120/ && $m->{mode_b} !~ /^120/) {
                $self->change_file_prop($fbat,'svn:special',undef);
        }
-       defined(my $pid = fork) or croak $!;
-       if (!$pid) {
-               open STDOUT, '>&', $fh or croak $!;
-               exec qw/git-cat-file blob/, $m->{sha1_b} or croak $!;
-       }
-       waitpid $pid, 0;
-       croak $? if $?;
+       my $size = $::_repository->cat_blob($m->{sha1_b}, $fh);
+       croak "Failed to read object $m->{sha1_b}" unless $size;
        $fh->flush == 0 or croak $!;
        seek $fh, 0, 0 or croak $!;
  
@@@ -3686,7 -3671,7 +3684,7 @@@ sub escape_uri_only 
        my ($uri) = @_;
        my @tmp;
        foreach (split m{/}, $uri) {
 -              s/([^\w.%-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg;
 +              s/([^\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg;
                push @tmp, $_;
        }
        join('/', @tmp);
  }
  
  sub cmd_blame {
 -      my $path = shift;
 +      my $path = pop;
  
        config_pager();
        run_pager();
  
 -      my ($fh, $ctx) = command_output_pipe('blame', @_, $path);
 -      while (my $line = <$fh>) {
 -              if ($line =~ /^\^?([[:xdigit:]]+)\s/) {
 -                      my (undef, $rev, undef) = ::cmt_metadata($1);
 -                      $rev = sprintf('%-10s', $rev);
 -                      $line =~ s/^\^?[[:xdigit:]]+(\s)/$rev$1/;
 +      my ($fh, $ctx, $rev);
 +
 +      if ($_git_format) {
 +              ($fh, $ctx) = command_output_pipe('blame', @_, $path);
 +              while (my $line = <$fh>) {
 +                      if ($line =~ /^\^?([[:xdigit:]]+)\s/) {
 +                              # Uncommitted edits show up as a rev ID of
 +                              # all zeros, which we can't look up with
 +                              # cmt_metadata
 +                              if ($1 !~ /^0+$/) {
 +                                      (undef, $rev, undef) =
 +                                              ::cmt_metadata($1);
 +                                      $rev = '0' if (!$rev);
 +                              } else {
 +                                      $rev = '0';
 +                              }
 +                              $rev = sprintf('%-10s', $rev);
 +                              $line =~ s/^\^?[[:xdigit:]]+(\s)/$rev$1/;
 +                      }
 +                      print $line;
 +              }
 +      } else {
 +              ($fh, $ctx) = command_output_pipe('blame', '-p', @_, 'HEAD',
 +                                                '--', $path);
 +              my ($sha1);
 +              my %authors;
 +              while (my $line = <$fh>) {
 +                      if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) {
 +                              $sha1 = $1;
 +                              (undef, $rev, undef) = ::cmt_metadata($1);
 +                              $rev = '0' if (!$rev);
 +                      }
 +                      elsif ($line =~ /^author (.*)/) {
 +                              $authors{$rev} = $1;
 +                              $authors{$rev} =~ s/\s/_/g;
 +                      }
 +                      elsif ($line =~ /^\t(.*)$/) {
 +                              printf("%6s %10s %s\n", $rev, $authors{$rev}, $1);
 +                      }
                }
 -              print $line;
        }
        command_close_pipe($fh, $ctx);
  }