mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-98232 Git executable auto-detector should prefer values from the PATH
Test: - add tests on PATH; - let specify different drive letters, use drive letters in expected and actual paths to make them more natural looking.
This commit is contained in:
@@ -22,6 +22,7 @@ import com.intellij.execution.process.ProcessOutput;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.CharsetToolkit;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -53,6 +54,7 @@ public class GitExecutableDetector {
|
||||
private static final String GIT_EXE = "git.exe";
|
||||
|
||||
public static final String DEFAULT_WIN_GIT = GIT_EXE;
|
||||
public static final String PATH_ENV = "PATH";
|
||||
|
||||
@NotNull
|
||||
public String detect() {
|
||||
@@ -75,7 +77,12 @@ public class GitExecutableDetector {
|
||||
|
||||
@NotNull
|
||||
private String detectForWindows() {
|
||||
String exec = checkMsys();
|
||||
String exec = checkInPath();
|
||||
if (exec != null) {
|
||||
return exec;
|
||||
}
|
||||
|
||||
exec = checkProgramFiles();
|
||||
if (exec != null) {
|
||||
return exec;
|
||||
}
|
||||
@@ -88,8 +95,37 @@ public class GitExecutableDetector {
|
||||
return checkSoleExecutable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks into the %PATH% and checks Git directories mentioned there.
|
||||
* @return Git executable to be used or null if nothing interesting was found in the PATH.
|
||||
*/
|
||||
@Nullable
|
||||
private static String checkMsys() {
|
||||
private String checkInPath() {
|
||||
String PATH = getPath();
|
||||
if (PATH == null) {
|
||||
return null;
|
||||
}
|
||||
List<String> pathEntries = StringUtil.split(PATH, ";");
|
||||
for (String pathEntry : pathEntries) {
|
||||
if (looksLikeGit(pathEntry)) {
|
||||
return checkBinDir(new File(pathEntry));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean looksLikeGit(@NotNull String path) {
|
||||
List<String> dirs = FileUtil.splitPath(path);
|
||||
for (String dir : dirs) {
|
||||
if (dir.toLowerCase().startsWith("git")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String checkProgramFiles() {
|
||||
final String[] PROGRAM_FILES = { "Program Files", "Program Files (x86)" };
|
||||
|
||||
// collecting all potential msys distributives
|
||||
@@ -190,6 +226,11 @@ public class GitExecutableDetector {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected String getPath() {
|
||||
return System.getenv(PATH_ENV);
|
||||
}
|
||||
|
||||
// Compare strategy: greater is better (if v1 > v2, then v1 is a better candidate for the Git executable)
|
||||
private static class VersionDirsComparator implements Comparator<File> {
|
||||
|
||||
|
||||
@@ -32,106 +32,166 @@ import static junit.framework.Assert.assertEquals
|
||||
class GitExecutableDetectorWindowsTest {
|
||||
|
||||
private File testRoot
|
||||
private def canRun = []
|
||||
private def CAN_RUN = []
|
||||
private String PATH
|
||||
|
||||
@Before
|
||||
void setUp() {
|
||||
GitTestUtil.setWindows(true);
|
||||
testRoot = FileUtil.createTempDirectory("", "")
|
||||
setWindowsRoot(testRoot);
|
||||
setWindowsRoot(new File(testRoot, "C_"));
|
||||
PATH = System.getenv("PATH")
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Simple case"() {
|
||||
fs "/Program Files/Git/bin/git.exe"
|
||||
fs "C:/Program Files/Git/bin/git.exe"
|
||||
assertExecutable "C:/Program Files/Git/bin/git.exe"
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Prefer default Git without version to versioned ones"() {
|
||||
fs "/Program Files/Git/bin/git.exe", "/Program Files/Git 1.8/bin/git.exe", "/Program Files/Git_1.7.1/bin/git.exe"
|
||||
fs "C:/Program Files/Git/bin/git.exe",
|
||||
"C:/Program Files/Git 1.8/bin/git.exe",
|
||||
"C:/Program Files/Git_1.7.1/bin/git.exe"
|
||||
assertExecutable "C:/Program Files/Git/bin/git.exe"
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Prefer the latest version"() {
|
||||
fs "/Program Files (x86)/Git 1.8/cmd/git.exe",
|
||||
"/Program Files/Git_1.7.1/bin/git.exe",
|
||||
"/Program Files/Git_1.7.5/cmd/git.cmd",
|
||||
"/Program Files (x86)/Git_1.7.0.2/bin/git.exe"
|
||||
fs "C:/Program Files (x86)/Git 1.8/cmd/git.exe",
|
||||
"C:/Program Files/Git_1.7.1/bin/git.exe",
|
||||
"C:/Program Files/Git_1.7.5/cmd/git.cmd",
|
||||
"C:/Program Files (x86)/Git_1.7.0.2/bin/git.exe"
|
||||
assertExecutable "C:/Program Files (x86)/Git 1.8/cmd/git.exe"
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Prefer Program Files over x86"() {
|
||||
fs "/Program Files (x86)/Git 1.8/bin/git.exe", "/Program Files/Git 1.8/bin/git.exe"
|
||||
fs "C:/Program Files (x86)/Git 1.8/bin/git.exe",
|
||||
"C:/Program Files/Git 1.8/bin/git.exe"
|
||||
assertExecutable "C:/Program Files/Git 1.8/bin/git.exe"
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Prefer git.cmd over git.exe"() {
|
||||
fs "/Program Files (x86)/Git 1.7.4/bin/git.exe", "/Program Files/Git 1.7.4/cmd/git.cmd"
|
||||
fs "C:/Program Files (x86)/Git 1.7.4/bin/git.exe",
|
||||
"C:/Program Files/Git 1.7.4/cmd/git.cmd"
|
||||
assertExecutable "C:/Program Files/Git 1.7.4/cmd/git.cmd"
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Prefer cmd over bin in newer versions of Git"() {
|
||||
fs "/Program Files (x86)/Git 1.8/bin/git.exe", "/Program Files/Git 1.8/cmd/git.exe"
|
||||
fs "C:/Program Files (x86)/Git 1.8/bin/git.exe",
|
||||
"C:/Program Files/Git 1.8/cmd/git.exe"
|
||||
assertExecutable "C:/Program Files/Git 1.8/cmd/git.exe"
|
||||
}
|
||||
|
||||
@Test
|
||||
void "1.8.0 Prefer cmd/git.cmd over cmd/git.exe and bin/git.exe"() {
|
||||
fs "/Program Files (x86)/Git_1.8/bin/git.exe",
|
||||
"/Program Files (x86)/Git_1.8/cmd/git.cmd",
|
||||
"/Program Files (x86)/Git_1.8/cmd/git.exe"
|
||||
fs "C:/Program Files (x86)/Git_1.8/bin/git.exe",
|
||||
"C:/Program Files (x86)/Git_1.8/cmd/git.cmd",
|
||||
"C:/Program Files (x86)/Git_1.8/cmd/git.exe"
|
||||
assertExecutable "C:/Program Files (x86)/Git_1.8/cmd/git.cmd"
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Prefer msys over cygwin"() {
|
||||
fs "/Program Files (x86)/Git_1.8.0.2/cmd/git.exe",
|
||||
"/Program Files (x86)/Git_1.8.0.2/bin/git.exe",
|
||||
"/cygwin/bin/git.exe"
|
||||
fs "C:/Program Files (x86)/Git_1.8.0.2/cmd/git.exe",
|
||||
"C:/Program Files (x86)/Git_1.8.0.2/bin/git.exe",
|
||||
"C:/cygwin/bin/git.exe"
|
||||
assertExecutable "C:/Program Files (x86)/Git_1.8.0.2/cmd/git.exe"
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Only cygwin"() {
|
||||
fs "/cygwin/bin/git.exe"
|
||||
fs "C:/cygwin/bin/git.exe"
|
||||
assertExecutable "C:/cygwin/bin/git.exe"
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Many different versions, real case"() {
|
||||
fs "/Program Files (x86)/Git_1.7.0.2/bin/git.exe",
|
||||
"/Program Files (x86)/Git_1.7.0.2/cmd/git.cmd",
|
||||
"/Program Files (x86)/Git_1.7.8/bin/git.exe",
|
||||
"/Program Files (x86)/Git_1.7.8/cmd/git.cmd",
|
||||
"/Program Files (x86)/Git_1.8/bin/git.exe",
|
||||
"/Program Files (x86)/Git_1.8/cmd/git.cmd",
|
||||
"/Program Files (x86)/Git_1.8/cmd/git.exe",
|
||||
"/Program Files (x86)/Git_1.8.0.2/cmd/git.exe",
|
||||
"/Program Files (x86)/Git_1.8.0.2/bin/git.exe",
|
||||
"/cygwin/bin/git.exe"
|
||||
fs "C:/Program Files (x86)/Git_1.7.0.2/bin/git.exe",
|
||||
"C:/Program Files (x86)/Git_1.7.0.2/cmd/git.cmd",
|
||||
"C:/Program Files (x86)/Git_1.7.8/bin/git.exe",
|
||||
"C:/Program Files (x86)/Git_1.7.8/cmd/git.cmd",
|
||||
"C:/Program Files (x86)/Git_1.8/bin/git.exe",
|
||||
"C:/Program Files (x86)/Git_1.8/cmd/git.cmd",
|
||||
"C:/Program Files (x86)/Git_1.8/cmd/git.exe",
|
||||
"C:/Program Files (x86)/Git_1.8.0.2/cmd/git.exe",
|
||||
"C:/Program Files (x86)/Git_1.8.0.2/bin/git.exe",
|
||||
"C:/cygwin/bin/git.exe"
|
||||
assertExecutable "C:/Program Files (x86)/Git_1.8.0.2/cmd/git.exe"
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Program not found, try git.exe"() {
|
||||
canRun = [ "git.exe" ]
|
||||
CAN_RUN = [ "git.exe" ]
|
||||
assertExecutable "git.exe"
|
||||
}
|
||||
|
||||
@Test
|
||||
void "For both git.exe and git.cmd prefer git.cmd"() {
|
||||
canRun = [ "git.exe", "git.cmd" ]
|
||||
CAN_RUN = [ "git.exe", "git.cmd" ]
|
||||
assertExecutable "git.cmd"
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Find Git in PATH"() {
|
||||
PATH = "D:/Program Files (x86)/Git_distr/cmd";
|
||||
fs "D:/Program Files (x86)/Git_distr/cmd/git.cmd"
|
||||
assertExecutable "D:/Program Files (x86)/Git_distr/cmd/git.cmd"
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Find Git in PATH not on the first place"() {
|
||||
PATH = "C:/Ruby193/bin;C:/Users/John.Doe/Documents/Git_1.8.0.2/bin";
|
||||
fs "C:/Users/John.Doe/Documents/Git_1.8.0.2/bin/git.exe"
|
||||
assertExecutable "C:/Users/John.Doe/Documents/Git_1.8.0.2/bin/git.exe"
|
||||
}
|
||||
|
||||
@Test
|
||||
void "No Git in PATH, then look in Program Files"() {
|
||||
PATH = "%SystemRoot%/system32;%SystemRoot%;%SystemRoot%/System32/Wbem;%SYSTEMROOT%/System32/WindowsPowerShell/v1.0/;" +
|
||||
"C:/Program Files/Intel/DMIX;C:/Program Files/Mercurial/;C:/Program Files/TortoiseHg/;"
|
||||
fs "C:/Program Files/Git/bin/git.exe"
|
||||
assertExecutable "C:/Program Files/Git/bin/git.exe"
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Prefer PATH to Program Files"() {
|
||||
PATH = "C:/Ruby193/bin;C:/Users/John.Doe/Documents/Git_1.8.0.2/bin";
|
||||
fs "C:/Program Files/Git/bin/git.exe",
|
||||
"C:/Users/John.Doe/Documents/Git_1.8.0.2/bin/git.exe"
|
||||
assertExecutable "C:/Users/John.Doe/Documents/Git_1.8.0.2/bin/git.exe"
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Prefer the first entry from the PATH"() {
|
||||
PATH = "C:/Ruby193/bin;D:/Git/cmd;C:/Users/John.Doe/Documents/Git_1.8.0.2/bin;";
|
||||
fs "D:/Git/cmd/git.cmd",
|
||||
"C:/Users/John.Doe/Documents/Git_1.8.0.2/bin/git.exe"
|
||||
assertExecutable "D:/Git/cmd/git.cmd"
|
||||
}
|
||||
|
||||
@Test
|
||||
void "Don't use Git from PATH if it doesn't exist on disk"() {
|
||||
PATH = "C:/Ruby193/bin;D:/Git/cmd;";
|
||||
fs "C:/Program Files/Git/bin/git.exe"
|
||||
assertExecutable "C:/Program Files/Git/bin/git.exe"
|
||||
}
|
||||
|
||||
def assertExecutable(String expected) {
|
||||
expected = FileUtil.toSystemDependentName(expected).replace("C:", testRoot.path)
|
||||
assertEquals "Incorrect executable detected", expected, detect()
|
||||
// we want to specify unix-like paths in "expected", because they are easier to write :)
|
||||
def detected = detect()
|
||||
detected = convertBack(detected)
|
||||
assertEquals "Incorrect executable detected", expected, detected
|
||||
}
|
||||
|
||||
String convertBack(String detected) {
|
||||
detected = detected.replace(testRoot.path + "/", "").replace('\\', '/')
|
||||
detected = returnDiskColor(detected)
|
||||
return detected
|
||||
}
|
||||
|
||||
def fs(String... paths) {
|
||||
@@ -141,16 +201,36 @@ class GitExecutableDetectorWindowsTest {
|
||||
}
|
||||
|
||||
def mkPath(String path) {
|
||||
def file = new File(testRoot.getPath() + FileUtil.toSystemDependentName(path))
|
||||
path = FileUtil.toSystemDependentName(replaceDiskColon(path))
|
||||
def file = new File(testRoot.getPath() + File.separator + path)
|
||||
file.getParentFile().mkdirs()
|
||||
file.createNewFile()
|
||||
}
|
||||
|
||||
static String replaceDiskColon(String path) {
|
||||
if (path[1] == ':') {
|
||||
return path[0] + "_" + path.substring(2)
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
private static String returnDiskColor(String path) {
|
||||
if (path[1] == '_') {
|
||||
return path[0] + ":" + path.substring(2)
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
private String detect() {
|
||||
new GitExecutableDetector() {
|
||||
@Override
|
||||
protected boolean runs(@NotNull String exec) {
|
||||
return canRun.contains(exec);
|
||||
return CAN_RUN.contains(exec);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPath() {
|
||||
return PATH.replaceAll('(\\w):', testRoot.path + File.separator + "\$1_");
|
||||
}
|
||||
}.detect();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user