Skip to content

Commit

Permalink
[Fixed JENKINS-21806] Improve ssh.exe finding on Windows with msysgit
Browse files Browse the repository at this point in the history
Adapt to msysgit installed in non-default locations, and to msysgit
alternative configurations as allowed by the msysgit installer.  The
mssygit installer allows the user to choose to make no changes to the
PATH, or to add the "cmd" directory to the PATH, or add the "bin"
directory to the PATH.

If the user chooses to make no changes to the PATH, then they
configure their Jenkins git with the absolute path of the git
executable.

If the user chooses to add the "cmd" directory to the PATH, then they
configure their Jenkins git with the executable as "git", "git.exe",
or (with some msysgit versions) "git.cmd".

If the user chooses to add the "bin" directory to the PATH, then they
configure similarly to the "cmd" directory case.

The plugin attempts to handle all those cases correctly.

Special thanks to Thiago Zanetti for providing the original code for
this fix.
  • Loading branch information
MarkEWaite committed Jul 15, 2014
1 parent 824d028 commit 9430af7
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 15 deletions.
103 changes: 88 additions & 15 deletions src/main/java/org/jenkinsci/plugins/gitclient/CliGitAPIImpl.java
Expand Up @@ -1258,26 +1258,99 @@ private File createUnixSshAskpass(SSHUserPrivateKey sshUser) throws IOException
return ssh;
}

private String getPathToExe(String userGitExe) {
userGitExe = userGitExe.toLowerCase();

String cmd;
String exe;
if (userGitExe.endsWith(".exe")) {
cmd = userGitExe.replace(".exe", ".cmd");
exe = userGitExe;
} else if (userGitExe.endsWith(".cmd")) {
cmd = userGitExe;
exe = userGitExe.replace(".cmd", ".exe");
} else {
cmd = userGitExe + ".cmd";
exe = userGitExe + ".exe";
}

private File createWindowsGitSSH(File key) throws IOException {
File ssh = File.createTempFile("ssh", ".bat");
// windows git installer place C:\Program Files\Git\cmd\git.exe in PATH

String progFiles = System.getenv("ProgramFiles");
String sshPath = "/Git/bin/ssh.exe";
File sshexe = new File(progFiles + sshPath);
if (!sshexe.exists()) {
// try the (x86) version for 64-bit Windows builds
sshexe = new File(progFiles + " (x86)" + sshPath);
String[] pathDirs = System.getenv("PATH").split(File.pathSeparator);

for (String pathDir : pathDirs) {
File exeFile = new File(pathDir, exe);
if (exeFile.exists()) {
return exeFile.getAbsolutePath();
}
File cmdFile = new File(pathDir, cmd);
if (cmdFile.exists()) {
return cmdFile.getAbsolutePath();
}
}

return null;
}

private File getFileFromEnv(String envVar, String suffix) {
String envValue = System.getenv(envVar);
if (envValue == null) {
return null;
}
if (!sshexe.exists()) {
// try the ssh.exe next to known git.exe
sshexe = new File(new File(gitExe).getParentFile(), "ssh.exe");
return new File(envValue + suffix);
}

private File getSSHExeFromGitExeParentDir(String userGitExe) {
String parentPath = new File(userGitExe).getParent();
if (parentPath == null) {
return null;
}
return new File(parentPath + "\\ssh.exe");
}

if (!sshexe.exists()) {
throw new RuntimeException("git plugin only support official git client http://git-scm.com/download/win");
/* package */ File getSSHExecutable() {
// First check the GIT_SSH environment variable
File sshexe = getFileFromEnv("GIT_SSH", "");
if (sshexe != null && sshexe.exists()) {
return sshexe;
}

// Check Program Files
sshexe = getFileFromEnv("ProgramFiles", "\\Git\\bin\\ssh.exe");
if (sshexe != null && sshexe.exists()) {
return sshexe;
}

// Check Program Files(x86) for 64 bit computer
sshexe = getFileFromEnv("ProgramFiles(x86)", "\\Git\\bin\\ssh.exe");
if (sshexe != null && sshexe.exists()) {
return sshexe;
}

// Search for an ssh.exe near the git executable.
sshexe = getSSHExeFromGitExeParentDir(gitExe);
if (sshexe != null && sshexe.exists()) {
return sshexe;
}

// Search for git on the PATH, then look near it
String gitPath = getPathToExe(gitExe);
if (gitPath != null) {
// In case we are using msysgit from the cmd directory
// instead of the bin directory, replace cmd with bin in
// the path while trying to find ssh.exe.
sshexe = getSSHExeFromGitExeParentDir(gitPath.replace("/cmd/", "/bin/").replace("\\cmd\\", "\\bin\\"));
if (sshexe != null && sshexe.exists()) {
return sshexe;
}
}

throw new RuntimeException("ssh executable not found. The git plugin only supports official git client http://git-scm.com/download/win");
}

private File createWindowsGitSSH(File key) throws IOException {
File ssh = File.createTempFile("ssh", ".bat");

File sshexe = getSSHExecutable();

PrintWriter w = new PrintWriter(ssh);
w .println("@echo off");
w .println("\"" + sshexe.getAbsolutePath() + "\" -i \"" + key.getAbsolutePath() +"\" -o StrictHostKeyChecking=no %* ");
Expand Down
10 changes: 10 additions & 0 deletions src/test/java/org/jenkinsci/plugins/gitclient/GitAPITestCase.java
Expand Up @@ -2619,4 +2619,14 @@ public void test_longpaths_disabled() throws Exception {
w.cmd("git config --add core.longpaths false");
check_longpaths(false);
}

@NotImplementedInJGit
/* Not implemented in JGit because it is not needed there */
public void test_git_ssh_executable_found_on_windows() throws Exception {
if (!SystemUtils.IS_OS_WINDOWS) {
return;
}

assertTrue("ssh.exe not found", w.cgit().getSSHExecutable().exists());
}
}

1 comment on commit 9430af7

@thiagozanetti
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you can see, Java is not my real deal. :) I'll checkout this version and try it here. Thanks!

Please sign in to comment.