Merge branch 'sf/putty-w-args'

The command line options for ssh invocation needs to be tweaked for
some implementations of SSH (e.g. PuTTY plink wants "-P <port>"
while OpenSSH wants "-p <port>" to specify port to connect to), and
the variant was guessed when GIT_SSH environment variable is used
to specify it.  The logic to guess now applies to the command
specified by the newer GIT_SSH_COMMAND and also core.sshcommand
configuration variable, and comes with an escape hatch for users to
deal with misdetected cases.

* sf/putty-w-args:
  connect.c: stop conflating ssh command names and overrides
  connect: Add the envvar GIT_SSH_VARIANT and ssh.variant config
  git_connect(): factor out SSH variant handling
  connect: rename tortoiseplink and putty variables
  connect: handle putty/plink also in GIT_SSH_COMMAND
This commit is contained in:
Junio C Hamano 2017-02-27 13:57:14 -08:00
Родитель 098ed50e8a 486c8e8c6a
Коммит be6ab596a8
4 изменённых файлов: 133 добавлений и 19 удалений

Просмотреть файл

@ -1957,6 +1957,17 @@ Environment variable settings always override any matches. The URLs that are
matched against are those given directly to Git commands. This means any URLs
visited as a result of a redirection do not participate in matching.
ssh.variant::
Depending on the value of the environment variables `GIT_SSH` or
`GIT_SSH_COMMAND`, or the config setting `core.sshCommand`, Git
auto-detects whether to adjust its command-line parameters for use
with plink or tortoiseplink, as opposed to the default (OpenSSH).
+
The config variable `ssh.variant` can be set to override this auto-detection;
valid values are `ssh`, `plink`, `putty` or `tortoiseplink`. Any other value
will be treated as normal ssh. This setting can be overridden via the
environment variable `GIT_SSH_VARIANT`.
i18n.commitEncoding::
Character encoding the commit messages are stored in; Git itself
does not care per se, but this information is necessary e.g. when

Просмотреть файл

@ -1025,6 +1025,12 @@ Usually it is easier to configure any desired options through your
personal `.ssh/config` file. Please consult your ssh documentation
for further details.
`GIT_SSH_VARIANT`::
If this environment variable is set, it overrides Git's autodetection
whether `GIT_SSH`/`GIT_SSH_COMMAND`/`core.sshCommand` refer to OpenSSH,
plink or tortoiseplink. This variable overrides the config setting
`ssh.variant` that serves the same purpose.
`GIT_ASKPASS`::
If this environment variable is set, then Git commands which need to
acquire passwords or passphrases (e.g. for HTTP or IMAP authentication)

Просмотреть файл

@ -691,6 +691,68 @@ static const char *get_ssh_command(void)
return NULL;
}
static int override_ssh_variant(int *port_option, int *needs_batch)
{
char *variant;
variant = xstrdup_or_null(getenv("GIT_SSH_VARIANT"));
if (!variant &&
git_config_get_string("ssh.variant", &variant))
return 0;
if (!strcmp(variant, "plink") || !strcmp(variant, "putty")) {
*port_option = 'P';
*needs_batch = 0;
} else if (!strcmp(variant, "tortoiseplink")) {
*port_option = 'P';
*needs_batch = 1;
} else {
*port_option = 'p';
*needs_batch = 0;
}
free(variant);
return 1;
}
static void handle_ssh_variant(const char *ssh_command, int is_cmdline,
int *port_option, int *needs_batch)
{
const char *variant;
char *p = NULL;
if (override_ssh_variant(port_option, needs_batch))
return;
if (!is_cmdline) {
p = xstrdup(ssh_command);
variant = basename(p);
} else {
const char **ssh_argv;
p = xstrdup(ssh_command);
if (split_cmdline(p, &ssh_argv)) {
variant = basename((char *)ssh_argv[0]);
/*
* At this point, variant points into the buffer
* referenced by p, hence we do not need ssh_argv
* any longer.
*/
free(ssh_argv);
} else
return;
}
if (!strcasecmp(variant, "plink") ||
!strcasecmp(variant, "plink.exe"))
*port_option = 'P';
else if (!strcasecmp(variant, "tortoiseplink") ||
!strcasecmp(variant, "tortoiseplink.exe")) {
*port_option = 'P';
*needs_batch = 1;
}
free(p);
}
/*
* This returns a dummy child_process if the transport protocol does not
* need fork(2), or a struct child_process object if it does. Once done,
@ -769,7 +831,8 @@ struct child_process *git_connect(int fd[2], const char *url,
conn->in = conn->out = -1;
if (protocol == PROTO_SSH) {
const char *ssh;
int putty = 0, tortoiseplink = 0;
int needs_batch = 0;
int port_option = 'p';
char *ssh_host = hostandport;
const char *port = NULL;
transport_check_allowed("ssh");
@ -792,10 +855,10 @@ struct child_process *git_connect(int fd[2], const char *url,
}
ssh = get_ssh_command();
if (!ssh) {
const char *base;
char *ssh_dup;
if (ssh)
handle_ssh_variant(ssh, 1, &port_option,
&needs_batch);
else {
/*
* GIT_SSH is the no-shell version of
* GIT_SSH_COMMAND (and must remain so for
@ -806,17 +869,10 @@ struct child_process *git_connect(int fd[2], const char *url,
ssh = getenv("GIT_SSH");
if (!ssh)
ssh = "ssh";
ssh_dup = xstrdup(ssh);
base = basename(ssh_dup);
tortoiseplink = !strcasecmp(base, "tortoiseplink") ||
!strcasecmp(base, "tortoiseplink.exe");
putty = tortoiseplink ||
!strcasecmp(base, "plink") ||
!strcasecmp(base, "plink.exe");
free(ssh_dup);
else
handle_ssh_variant(ssh, 0,
&port_option,
&needs_batch);
}
argv_array_push(&conn->args, ssh);
@ -824,11 +880,11 @@ struct child_process *git_connect(int fd[2], const char *url,
argv_array_push(&conn->args, "-4");
else if (flags & CONNECT_IPV6)
argv_array_push(&conn->args, "-6");
if (tortoiseplink)
if (needs_batch)
argv_array_push(&conn->args, "-batch");
if (port) {
/* P is for PuTTY, p is for OpenSSH */
argv_array_push(&conn->args, putty ? "-P" : "-p");
argv_array_pushf(&conn->args,
"-%c", port_option);
argv_array_push(&conn->args, port);
}
argv_array_push(&conn->args, ssh_host);

Просмотреть файл

@ -386,6 +386,47 @@ test_expect_success 'tortoiseplink is like putty, with extra arguments' '
expect_ssh "-batch -P 123" myhost src
'
test_expect_success 'double quoted plink.exe in GIT_SSH_COMMAND' '
copy_ssh_wrapper_as "$TRASH_DIRECTORY/plink.exe" &&
GIT_SSH_COMMAND="\"$TRASH_DIRECTORY/plink.exe\" -v" \
git clone "[myhost:123]:src" ssh-bracket-clone-plink-3 &&
expect_ssh "-v -P 123" myhost src
'
SQ="'"
test_expect_success 'single quoted plink.exe in GIT_SSH_COMMAND' '
copy_ssh_wrapper_as "$TRASH_DIRECTORY/plink.exe" &&
GIT_SSH_COMMAND="$SQ$TRASH_DIRECTORY/plink.exe$SQ -v" \
git clone "[myhost:123]:src" ssh-bracket-clone-plink-4 &&
expect_ssh "-v -P 123" myhost src
'
test_expect_success 'GIT_SSH_VARIANT overrides plink detection' '
copy_ssh_wrapper_as "$TRASH_DIRECTORY/plink" &&
GIT_SSH_VARIANT=ssh \
git clone "[myhost:123]:src" ssh-bracket-clone-variant-1 &&
expect_ssh "-p 123" myhost src
'
test_expect_success 'ssh.variant overrides plink detection' '
copy_ssh_wrapper_as "$TRASH_DIRECTORY/plink" &&
git -c ssh.variant=ssh \
clone "[myhost:123]:src" ssh-bracket-clone-variant-2 &&
expect_ssh "-p 123" myhost src
'
test_expect_success 'GIT_SSH_VARIANT overrides plink detection to plink' '
GIT_SSH_VARIANT=plink \
git clone "[myhost:123]:src" ssh-bracket-clone-variant-3 &&
expect_ssh "-P 123" myhost src
'
test_expect_success 'GIT_SSH_VARIANT overrides plink to tortoiseplink' '
GIT_SSH_VARIANT=tortoiseplink \
git clone "[myhost:123]:src" ssh-bracket-clone-variant-4 &&
expect_ssh "-batch -P 123" myhost src
'
# Reset the GIT_SSH environment variable for clone tests.
setup_ssh_wrapper