perl: command_bidi_pipe() method should set-up git environmens
authorMasatake Osanai <unpush@gmail.com>
Mon, 14 Feb 2011 22:13:04 +0000 (07:13 +0900)
committerJunio C Hamano <gitster@pobox.com>
Mon, 14 Feb 2011 23:28:13 +0000 (15:28 -0800)
When command_input_pipe and command_output_pipe are used as a
method of a Git::repository instance, they eventually call into
_cmd_exec method that sets up the execution environment such as
GIT_DIR, GIT_WORK_TREE environment variables and the current
working directory in the child process that interacts with the
repository.

command_bidi_pipe however didn't expect to be called as such, and
lacked all these set-up.  Because of this, a program that did this
did not work as expected:

    my $repo = Git->repository(Directory => '/some/where/else');
    my ($pid, $in, $out, $ctx) =
    $repo->command_bidi_pipe(qw(hash-object -w --stdin-paths));

This patch refactors the _cmd_exec into _setup_git_cmd_env that
sets up the execution environment, and makes _cmd_exec and
command_bidi_pipe to use it.

Note that unlike _cmd_exec that execv's a git command as an
external process, command_bidi_pipe is called from the main line
of control, and the execution environment needs to be restored
after open2() does its magic.

Signed-off-by: Masatake Osanai <unpush@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
perl/Git.pm
t/t9700/test.pl

index 205e48aa3a7b912005565ac9c296205a897a1476..a86ab709c25b5e110aa2708941cea560f82c1fa8 100644 (file)
@@ -99,7 +99,7 @@ increase notwithstanding).
 
 use Carp qw(carp croak); # but croak is bad - throw instead
 use Error qw(:try);
-use Cwd qw(abs_path);
+use Cwd qw(abs_path cwd);
 use IPC::Open2 qw(open2);
 use Fcntl qw(SEEK_SET SEEK_CUR);
 }
@@ -396,7 +396,16 @@ See C<command_close_bidi_pipe()> for details.
 
 sub command_bidi_pipe {
        my ($pid, $in, $out);
+       my ($self) = _maybe_self(@_);
+       local %ENV = %ENV;
+       my $cwd_save = undef;
+       if ($self) {
+               shift;
+               $cwd_save = cwd();
+               _setup_git_cmd_env($self);
+       }
        $pid = open2($in, $out, 'git', @_);
+       chdir($cwd_save) if $cwd_save;
        return ($pid, $in, $out, join(' ', @_));
 }
 
@@ -843,7 +852,7 @@ sub _open_hash_and_insert_object_if_needed {
 
        ($self->{hash_object_pid}, $self->{hash_object_in},
         $self->{hash_object_out}, $self->{hash_object_ctx}) =
-               command_bidi_pipe(qw(hash-object -w --stdin-paths --no-filters));
+               $self->command_bidi_pipe(qw(hash-object -w --stdin-paths --no-filters));
 }
 
 sub _close_hash_and_insert_object {
@@ -932,7 +941,7 @@ sub _open_cat_blob_if_needed {
 
        ($self->{cat_blob_pid}, $self->{cat_blob_in},
         $self->{cat_blob_out}, $self->{cat_blob_ctx}) =
-               command_bidi_pipe(qw(cat-file --batch));
+               $self->command_bidi_pipe(qw(cat-file --batch));
 }
 
 sub _close_cat_blob {
@@ -1279,6 +1288,14 @@ sub _command_common_pipe {
 # for the given repository and execute the git command.
 sub _cmd_exec {
        my ($self, @args) = @_;
+       _setup_git_cmd_env($self);
+       _execv_git_cmd(@args);
+       die qq[exec "@args" failed: $!];
+}
+
+# set up the appropriate state for git command
+sub _setup_git_cmd_env {
+       my $self = shift;
        if ($self) {
                $self->repo_path() and $ENV{'GIT_DIR'} = $self->repo_path();
                $self->repo_path() and $self->wc_path()
@@ -1286,8 +1303,6 @@ sub _cmd_exec {
                $self->wc_path() and chdir($self->wc_path());
                $self->wc_subdir() and chdir($self->wc_subdir());
        }
-       _execv_git_cmd(@args);
-       die qq[exec "@args" failed: $!];
 }
 
 # Execute the given Git command ($_[0]) with arguments ($_[1..])
index c15ca2d6479a814d7649a38a671a554b6ed8b68f..13ba96e21a9295805aed40c89ecd5178db6bfae4 100755 (executable)
@@ -113,6 +113,16 @@ like($last_commit, qr/^[0-9a-fA-F]{40}$/, 'rev-parse returned hash');
 my $dir_commit = $r2->command_oneline('log', '-n1', '--pretty=format:%H', '.');
 isnt($last_commit, $dir_commit, 'log . does not show last commit');
 
+# commands outside working tree
+chdir($abs_repo_dir . '/..');
+my $r3 = Git->repository(Directory => $abs_repo_dir);
+my $tmpfile3 = "$abs_repo_dir/file3.tmp";
+open TEMPFILE3, "+>$tmpfile3" or die "Can't open $tmpfile3: $!";
+is($r3->cat_blob($file1hash, \*TEMPFILE3), 15, "cat_blob(outside): size");
+close TEMPFILE3;
+unlink $tmpfile3;
+chdir($abs_repo_dir);
+
 printf "1..%d\n", Test::More->builder->current_test;
 
 my $is_passing = eval { Test::More->is_passing };