git-svn, perl/Git.pm: add central method for prompting passwords

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>

Sven Strickroth committed Dec 18, 2012 at 01:28 UTC 38ecf3a35d4255368a24ca255daf0b1ea433f1e3
2 files changed +45 -20
perl/Git.pm
+44 -1
@@ -58,7 +58,7 @@ require Exporter;
58 command_output_pipe command_input_pipe command_close_pipe
59 command_bidi_pipe command_close_bidi_pipe
60 version exec_path html_path hash_object git_cmd_try
61 - remote_refs
61 + remote_refs prompt
62 temp_acquire temp_release temp_reset temp_path);
63
64
@@ -511,6 +511,49 @@ C<git --html-path>). Useful mostly only internally.
511
512 sub html_path { command_oneline('--html-path') }
513
514 +=item prompt ( PROMPT )
515 +
516 +Query user C<PROMPT> and return answer from user.
517 +
518 +Honours GIT_ASKPASS environment variable for querying
519 +the user. If no GIT_ASKPASS variable is set or an error occoured,
520 +the terminal is tried as a fallback.
521 +
522 +=cut
523 +
524 +sub prompt {
525 + my ($prompt) = @_;
526 + my $ret;
527 + if (exists $ENV{'GIT_ASKPASS'}) {
528 + $ret = _prompt($ENV{'GIT_ASKPASS'}, $prompt);
529 + }
530 + if (!defined $ret) {
531 + print STDERR $prompt;
532 + STDERR->flush;
533 + require Term::ReadKey;
534 + Term::ReadKey::ReadMode('noecho');
535 + $ret = '';
536 + while (defined(my $key = Term::ReadKey::ReadKey(0))) {
537 + last if $key =~ /[\012\015]/; # \n\r
538 + $ret .= $key;
539 + }
540 + Term::ReadKey::ReadMode('restore');
541 + print STDERR "\n";
542 + STDERR->flush;
543 + }
544 + return $ret;
545 +}
546 +
547 +sub _prompt {
548 + my ($askpass, $prompt) = @_;
549 + return unless length $askpass;
550 + my $ret;
551 + open my $fh, "-|", $askpass, $prompt or return;
552 + $ret = <$fh>;
553 + $ret =~ s/[\015\012]//g; # strip \r\n, chomp does not work on all systems (i.e. windows) as expected
554 + close ($fh);
555 + return $ret;
556 +}
557
558 =item repo_path ()
559
perl/Git/SVN/Prompt.pm
+1 -19
@@ -120,25 +120,7 @@ sub username {
120
121 sub _read_password {
122 my ($prompt, $realm) = @_;
123 - my $password = '';
124 - if (exists $ENV{GIT_ASKPASS}) {
125 - open(PH, "-|", $ENV{GIT_ASKPASS}, $prompt);
126 - $password = <PH>;
127 - $password =~ s/[\012\015]//; # \n\r
128 - close(PH);
129 - } else {
130 - print STDERR $prompt;
131 - STDERR->flush;
132 - require Term::ReadKey;
133 - Term::ReadKey::ReadMode('noecho');
134 - while (defined(my $key = Term::ReadKey::ReadKey(0))) {
135 - last if $key =~ /[\012\015]/; # \n\r
136 - $password .= $key;
137 - }
138 - Term::ReadKey::ReadMode('restore');
139 - print STDERR "\n";
140 - STDERR->flush;
141 - }
123 + my $password = Git::prompt($prompt);
124 $password;
125 }
126