From 38ecf3a35d4255368a24ca255daf0b1ea433f1e3 Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Tue, 18 Dec 2012 01:28:45 +0100 Subject: [PATCH 1/3] 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 Signed-off-by: Junio C Hamano --- perl/Git.pm | 45 +++++++++++++++++++++++++++++++++++++++++- perl/Git/SVN/Prompt.pm | 20 +------------------ 2 files changed, 45 insertions(+), 20 deletions(-) diff --git a/perl/Git.pm b/perl/Git.pm index 497f420178..72e93c7e1b 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -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). Useful mostly only internally. sub html_path { command_oneline('--html-path') } +=item prompt ( PROMPT ) + +Query user C 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 () diff --git a/perl/Git/SVN/Prompt.pm b/perl/Git/SVN/Prompt.pm index 3a6f8af0d9..a2cbcc8a58 100644 --- a/perl/Git/SVN/Prompt.pm +++ b/perl/Git/SVN/Prompt.pm @@ -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 = ; - $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; } From 8f3cab2b4d7b6da8b69eea730e5774dcb208c50f Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Tue, 18 Dec 2012 01:28:47 +0100 Subject: [PATCH 2/3] perl/Git.pm: Honor SSH_ASKPASS as fallback if GIT_ASKPASS is not set If GIT_ASKPASS environment variable is not set, git-svn does not try to use SSH_ASKPASS as git-core does. This change adds a fallback to SSH_ASKPASS. Signed-off-by: Sven Strickroth Signed-off-by: Junio C Hamano --- perl/Git.pm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/perl/Git.pm b/perl/Git.pm index 72e93c7e1b..8dfca65454 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -515,8 +515,8 @@ sub html_path { command_oneline('--html-path') } Query user C 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, +Honours GIT_ASKPASS and SSH_ASKPASS environment variables for querying +the user. If no *_ASKPASS variable is set or an error occoured, the terminal is tried as a fallback. =cut @@ -527,6 +527,9 @@ sub prompt { if (exists $ENV{'GIT_ASKPASS'}) { $ret = _prompt($ENV{'GIT_ASKPASS'}, $prompt); } + if (!defined $ret && exists $ENV{'SSH_ASKPASS'}) { + $ret = _prompt($ENV{'SSH_ASKPASS'}, $prompt); + } if (!defined $ret) { print STDERR $prompt; STDERR->flush; From e9263e458055ab361a7292adc800d3e62b47b39f Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Tue, 18 Dec 2012 01:28:48 +0100 Subject: [PATCH 3/3] git-svn, perl/Git.pm: extend and use Git->prompt method for querying users git-svn reads usernames and other user queries from an interactive terminal. 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). This change extends the Git::prompt helper, so that it can also be used for non password queries, and makes use of it instead of using hand-rolled prompt-response code that only works with the interactive terminal. Signed-off-by: Sven Strickroth Signed-off-by: Junio C Hamano --- perl/Git.pm | 28 +++++++++++++++++----------- perl/Git/SVN/Prompt.pm | 16 +++++++--------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/perl/Git.pm b/perl/Git.pm index 8dfca65454..931047c51d 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -511,18 +511,19 @@ C). Useful mostly only internally. sub html_path { command_oneline('--html-path') } -=item prompt ( PROMPT ) +=item prompt ( PROMPT , ISPASSWORD ) Query user C and return answer from user. Honours GIT_ASKPASS and SSH_ASKPASS environment variables for querying the user. If no *_ASKPASS variable is set or an error occoured, the terminal is tried as a fallback. +If C is set and true, the terminal disables echo. =cut sub prompt { - my ($prompt) = @_; + my ($prompt, $isPassword) = @_; my $ret; if (exists $ENV{'GIT_ASKPASS'}) { $ret = _prompt($ENV{'GIT_ASKPASS'}, $prompt); @@ -533,16 +534,20 @@ sub 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; + if (defined $isPassword && $isPassword) { + 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; + } else { + chomp($ret = ); } - Term::ReadKey::ReadMode('restore'); - print STDERR "\n"; - STDERR->flush; } return $ret; } @@ -550,6 +555,7 @@ sub prompt { sub _prompt { my ($askpass, $prompt) = @_; return unless length $askpass; + $prompt =~ s/\n/ /g; my $ret; open my $fh, "-|", $askpass, $prompt or return; $ret = <$fh>; diff --git a/perl/Git/SVN/Prompt.pm b/perl/Git/SVN/Prompt.pm index a2cbcc8a58..74daa7a597 100644 --- a/perl/Git/SVN/Prompt.pm +++ b/perl/Git/SVN/Prompt.pm @@ -62,16 +62,16 @@ sub ssl_server_trust { issuer_dname fingerprint); my $choice; prompt: - print STDERR $may_save ? + my $options = $may_save ? "(R)eject, accept (t)emporarily or accept (p)ermanently? " : "(R)eject or accept (t)emporarily? "; STDERR->flush; - $choice = lc(substr( || 'R', 0, 1)); - if ($choice =~ /^t$/i) { + $choice = lc(substr(Git::prompt("Certificate problem.\n" . $options) || 'R', 0, 1)); + if ($choice eq 't') { $cred->may_save(undef); - } elsif ($choice =~ /^r$/i) { + } elsif ($choice eq 'r') { return -1; - } elsif ($may_save && $choice =~ /^p$/i) { + } elsif ($may_save && $choice eq 'p') { $cred->may_save($may_save); } else { goto prompt; @@ -109,9 +109,7 @@ sub username { if (defined $_username) { $username = $_username; } else { - print STDERR "Username: "; - STDERR->flush; - chomp($username = ); + $username = Git::prompt("Username: "); } $cred->username($username); $cred->may_save($may_save); @@ -120,7 +118,7 @@ sub username { sub _read_password { my ($prompt, $realm) = @_; - my $password = Git::prompt($prompt); + my $password = Git::prompt($prompt, 1); $password; }