git-svn, perl/Git.pm: add central method for prompting passwords
authorSven Strickroth <sven.strickroth@tu-clausthal.de>
Tue, 18 Dec 2012 00:28:45 +0000 (01:28 +0100)
committerJunio C Hamano <gitster@pobox.com>
Tue, 18 Dec 2012 01:21:22 +0000 (17:21 -0800)
git-svn reads passwords from an interactive terminal or by using
GIT_ASKPASS helper tool. This cause GUIs (w/o STDIN connected) to hang
waiting forever for git-svn to complete
(http://code.google.com/p/tortoisegit/issues/detail?id=967).

Commit 56a853b62c0ae7ebaad0a7a0a704f5ef561eb795 also tried to solve
this issue, but was incomplete as described above.

Instead of using hand-rolled prompt-response code that only works with the
interactive terminal, a reusable prompt() method is introduced in this commit.

Signed-off-by: Sven Strickroth <email@cs-ware.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
perl/Git.pm
perl/Git/SVN/Prompt.pm

index 497f420178a73061901393f8c21a9feb17054b6d..72e93c7e1b938f1909056a51646781ace26e06f2 100644 (file)
@@ -58,7 +58,7 @@ require Exporter;
                 command_output_pipe command_input_pipe command_close_pipe
                 command_bidi_pipe command_close_bidi_pipe
                 version exec_path html_path hash_object git_cmd_try
-                remote_refs
+                remote_refs prompt
                 temp_acquire temp_release temp_reset temp_path);
 
 
@@ -511,6 +511,49 @@ C<git --html-path>). Useful mostly only internally.
 
 sub html_path { command_oneline('--html-path') }
 
+=item prompt ( PROMPT )
+
+Query user C<PROMPT> and return answer from user.
+
+Honours GIT_ASKPASS environment variable for querying
+the user. If no GIT_ASKPASS variable is set or an error occoured,
+the terminal is tried as a fallback.
+
+=cut
+
+sub prompt {
+       my ($prompt) = @_;
+       my $ret;
+       if (exists $ENV{'GIT_ASKPASS'}) {
+               $ret = _prompt($ENV{'GIT_ASKPASS'}, $prompt);
+       }
+       if (!defined $ret) {
+               print STDERR $prompt;
+               STDERR->flush;
+               require Term::ReadKey;
+               Term::ReadKey::ReadMode('noecho');
+               $ret = '';
+               while (defined(my $key = Term::ReadKey::ReadKey(0))) {
+                       last if $key =~ /[\012\015]/; # \n\r
+                       $ret .= $key;
+               }
+               Term::ReadKey::ReadMode('restore');
+               print STDERR "\n";
+               STDERR->flush;
+       }
+       return $ret;
+}
+
+sub _prompt {
+       my ($askpass, $prompt) = @_;
+       return unless length $askpass;
+       my $ret;
+       open my $fh, "-|", $askpass, $prompt or return;
+       $ret = <$fh>;
+       $ret =~ s/[\015\012]//g; # strip \r\n, chomp does not work on all systems (i.e. windows) as expected
+       close ($fh);
+       return $ret;
+}
 
 =item repo_path ()
 
index 3a6f8af0d9849c5f2fc886f8fc3ac9a8575e271e..a2cbcc8a5870e9bb5aba7020f69a2f1359e09bd0 100644 (file)
@@ -120,25 +120,7 @@ sub username {
 
 sub _read_password {
        my ($prompt, $realm) = @_;
-       my $password = '';
-       if (exists $ENV{GIT_ASKPASS}) {
-               open(PH, "-|", $ENV{GIT_ASKPASS}, $prompt);
-               $password = <PH>;
-               $password =~ s/[\012\015]//; # \n\r
-               close(PH);
-       } else {
-               print STDERR $prompt;
-               STDERR->flush;
-               require Term::ReadKey;
-               Term::ReadKey::ReadMode('noecho');
-               while (defined(my $key = Term::ReadKey::ReadKey(0))) {
-                       last if $key =~ /[\012\015]/; # \n\r
-                       $password .= $key;
-               }
-               Term::ReadKey::ReadMode('restore');
-               print STDERR "\n";
-               STDERR->flush;
-       }
+       my $password = Git::prompt($prompt);
        $password;
 }