Skip to content

Commit 24dc148

Browse files
committed
Find path to bash automatically for Windows #17 and add check if the path to bash is really point to bash #7
1 parent 8c884c3 commit 24dc148

File tree

9 files changed

+220
-138
lines changed

9 files changed

+220
-138
lines changed

src/main/java/com/github/introfog/gitwave/GitWaveLauncher.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package com.github.introfog.gitwave;
1818

1919
import com.github.introfog.gitwave.model.AppConfig;
20-
import com.github.introfog.gitwave.model.OsRecogniser;
2120
import com.github.introfog.gitwave.model.StageFactory;
2221

2322
import javafx.application.Application;
@@ -28,11 +27,8 @@ public class GitWaveLauncher extends Application {
2827
public void start(Stage stage) {
2928
StageFactory.createPrimaryExecuteWindow(stage).getStage().show();
3029
AppConfig.getInstance().setHostServices(getHostServices());
31-
if (!OsRecogniser.isCurrentOsUnixLike()) {
32-
final String pathToGitBashExe = AppConfig.getInstance().getPathToGitBashExe();
33-
if (pathToGitBashExe == null || pathToGitBashExe.isEmpty()) {
34-
StageFactory.createModalSetupWindow().getStage().showAndWait();
35-
}
30+
if (AppConfig.getInstance().getPathToBash() == null) {
31+
StageFactory.createModalSetupWindow().getStage().showAndWait();
3632
}
3733
}
3834

src/main/java/com/github/introfog/gitwave/controller/SettingsController.java

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
import com.github.introfog.gitwave.model.AppConfig;
2020
import com.github.introfog.gitwave.model.DialogFactory;
21-
import com.github.introfog.gitwave.model.OsRecogniser;
2221
import com.github.introfog.gitwave.model.StageFactory.FxmlStageHolder;
2322

2423
import java.io.File;
@@ -33,6 +32,7 @@
3332
import javafx.scene.control.Label;
3433
import javafx.scene.control.TextField;
3534
import javafx.stage.FileChooser;
35+
import javafx.stage.FileChooser.ExtensionFilter;
3636
import javafx.util.Duration;
3737
import org.slf4j.Logger;
3838
import org.slf4j.LoggerFactory;
@@ -59,15 +59,9 @@ public class SettingsController extends BaseController {
5959
public void initialize(FxmlStageHolder fxmlStageHolder) {
6060
super.initialize(fxmlStageHolder);
6161
super.setClosingOnEscapePressing(fxmlStageHolder);
62-
if (OsRecogniser.isCurrentOsUnixLike()) {
63-
pathToBashExe.disableProperty().set(true);
64-
browse.setDisable(true);
65-
pathToBashText.setDisable(true);
66-
} else {
67-
final String pathToGitBashExeStr = AppConfig.getInstance().getPathToGitBashExe();
68-
if (pathToGitBashExeStr != null && !pathToGitBashExeStr.isEmpty()) {
69-
pathToBashExe.setText(pathToGitBashExeStr);
70-
}
62+
final String pathToGitBashExeStr = AppConfig.getInstance().getPathToBash();
63+
if (pathToGitBashExeStr != null) {
64+
pathToBashExe.setText(pathToGitBashExeStr);
7165
}
7266
save.requestFocus();
7367
if (done != null) {
@@ -77,17 +71,13 @@ public void initialize(FxmlStageHolder fxmlStageHolder) {
7771

7872
@FXML
7973
protected void save() {
80-
File bashExeFile = new File(pathToBashExe.getText());
81-
if (bashExeFile.exists() && bashExeFile.getAbsolutePath().endsWith(".exe")) {
82-
final String absolutePath = bashExeFile.getAbsolutePath();
83-
AppConfig.getInstance().setPathToGitBashExe(absolutePath);
84-
// TODO #7 add check that path is specified to GitBash.exe not for any other .exe
85-
LOGGER.info("Path to GitBash.exe registered to '{}'", absolutePath);
74+
File bashFile = new File(pathToBashExe.getText());
75+
if (bashFile.exists() && AppConfig.getInstance().setPathToBash(bashFile.getAbsolutePath())) {
8676
closeStage();
8777
} else {
88-
LOGGER.error("Wrong path to GitBash.exe '{}'", bashExeFile.getAbsolutePath());
89-
DialogFactory.createErrorAlert("Git Bash executable hasn't been specified",
90-
"Git Bash executable hasn't been specified correctly. Either specify path manually or find via file browser.", 210);
78+
LOGGER.error("Wrong path to bash '{}'", bashFile.getAbsolutePath());
79+
DialogFactory.createErrorAlert("Bash hasn't been specified",
80+
"Bash hasn't been specified correctly. Either specify path manually or find via file browser.", 210);
9181
}
9282
}
9383

@@ -119,14 +109,14 @@ protected void cleanLogs() {
119109
@FXML
120110
protected void browseGitBashExe() {
121111
FileChooser fileChooser = new FileChooser();
122-
FileChooser.ExtensionFilter exeFilter = new FileChooser.ExtensionFilter("Bash executable (*.exe)", "*.exe");
123-
fileChooser.getExtensionFilters().add(exeFilter);
124-
125-
final String pathToGitBashExeStr = AppConfig.getInstance().getPathToGitBashExe();
126-
if (pathToGitBashExeStr != null && !pathToGitBashExeStr.isEmpty()) {
127-
File gitBashDir = new File(pathToGitBashExeStr.substring(0, pathToGitBashExeStr.lastIndexOf("\\")));
128-
if (gitBashDir.exists() && gitBashDir.isDirectory()) {
129-
fileChooser.setInitialDirectory(gitBashDir);
112+
FileChooser.ExtensionFilter bashFilter = new ExtensionFilter("Path to bash", "*.*") ;
113+
fileChooser.getExtensionFilters().add(bashFilter);
114+
115+
final String pathToGitBashStr = AppConfig.getInstance().getPathToBash();
116+
if (pathToGitBashStr != null) {
117+
File bashDir = new File(pathToGitBashStr.substring(0, pathToGitBashStr.lastIndexOf('/')));
118+
if (bashDir.exists() && bashDir.isDirectory()) {
119+
fileChooser.setInitialDirectory(bashDir);
130120
}
131121
}
132122

@@ -135,7 +125,7 @@ protected void browseGitBashExe() {
135125
if (selectedFile.exists()) {
136126
pathToBashExe.setText(selectedFile.getAbsolutePath());
137127
} else {
138-
LOGGER.error("Wrong browsed path to GitBash.exe '{}'", selectedFile);
128+
LOGGER.error("Wrong browsed path to bash '{}'", selectedFile);
139129
DialogFactory.createErrorAlert("Provided file wasn't found", "Provided file wasn't found, try again");
140130
}
141131
} else {

src/main/java/com/github/introfog/gitwave/controller/main/MenuController.java

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@
33
import com.github.introfog.gitwave.controller.SupportController;
44
import com.github.introfog.gitwave.model.AppConfig;
55
import com.github.introfog.gitwave.model.DialogFactory;
6-
import com.github.introfog.gitwave.model.OsRecogniser;
6+
import com.github.introfog.gitwave.model.OsHelper;
77
import com.github.introfog.gitwave.model.StageFactory;
88
import com.github.introfog.gitwave.model.StageFactory.FxmlStageHolder;
99
import com.github.introfog.gitwave.model.UpdateChecker;
1010

11-
import java.io.File;
1211
import javafx.concurrent.Task;
1312
import javafx.scene.control.Menu;
1413
import javafx.scene.control.MenuItem;
@@ -32,17 +31,14 @@ public MenuController(FxmlStageHolder fxmlStageHolder, Menu menu, MenuItem updat
3231

3332
@Override
3433
public boolean isValid() {
35-
if (OsRecogniser.isCurrentOsUnixLike()) {
36-
return true;
37-
}
38-
final String pathToGitBashExe = AppConfig.getInstance().getPathToGitBashExe();
39-
if (pathToGitBashExe == null || pathToGitBashExe.isEmpty()) {
40-
DialogFactory.createErrorAlert("GitBash path hasn't been specified", "Specify path to GitBash in Menu->Settings.");
34+
if (AppConfig.getInstance().getPathToBash() == null) {
35+
DialogFactory.createErrorAlert("Bash hasn't been specified", "Specify bash in Menu->Settings.");
4136
return false;
42-
} if (!(new File(pathToGitBashExe)).exists()) {
43-
LOGGER.error("Specified GitBash.exe path '{}' points to not-existent file, running git command was skipped.", pathToGitBashExe);
44-
DialogFactory.createErrorAlert("Invalid path to GitBash.exe", "Specified path \"" + pathToGitBashExe +
45-
"\" points to not-existent file. Specify correct path in settings.", 210);
37+
} if (!OsHelper.isValidPathToBash(AppConfig.getInstance().getPathToBash())) {
38+
LOGGER.error("Specified path to bash '{}' doesn't point to bash, running git command was skipped.",
39+
AppConfig.getInstance().getPathToBash());
40+
DialogFactory.createErrorAlert("Invalid path to bash", "Specified path \"" + AppConfig.getInstance().getPathToBash() +
41+
"\" doesn't point to bash. Specify correct path in settings.", 210);
4642
return false;
4743
}
4844
return true;

src/main/java/com/github/introfog/gitwave/model/AppConfig.java

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.github.introfog.gitwave.model;
1818

19+
import com.github.introfog.gitwave.model.OsHelper.CurrentOs;
1920
import com.github.introfog.gitwave.model.dto.CommandDto;
2021
import com.github.introfog.gitwave.model.dto.ConfigDto;
2122

@@ -41,33 +42,57 @@ public final class AppConfig {
4142

4243
private final ConfigDto config;
4344
private HostServices hostServices;
45+
private final CurrentOs currentOs;
46+
private String pathToBash;
4447

4548
private final AtomicBoolean appWasClosed = new AtomicBoolean(false);
4649

4750

4851
private AppConfig() {
4952
this.config = AppConfig.initConfig();
53+
this.currentOs = OsHelper.getCurrentOs();
54+
final String pathToBashFromConfig = config.getPathToGitBash();
55+
if (pathToBashFromConfig != null) {
56+
LOGGER.info("Check path to bash from config.");
57+
if (OsHelper.isValidPathToBash(pathToBashFromConfig)) {
58+
this.pathToBash = pathToBashFromConfig;
59+
} else {
60+
config.setPathToGitBash(null);
61+
saveConfig();
62+
DialogFactory.createInfoAlert("Invalid config path to bash", "Path to bash \"" + pathToBashFromConfig + "\" "
63+
+ "specified in config invalid, path will be found automatically.");
64+
}
65+
}
66+
if (pathToBash == null) {
67+
this.pathToBash = OsHelper.getPathToBash(currentOs);
68+
}
5069
}
5170

5271
public static AppConfig getInstance() {
5372
return INSTANCE;
5473
}
5574

56-
public HostServices getHostServices() {
57-
return hostServices;
75+
public String getPathToBash() {
76+
return pathToBash;
5877
}
5978

60-
public void setHostServices(HostServices hostServices) {
61-
this.hostServices = hostServices;
79+
public boolean setPathToBash(String pathToBashParam) {
80+
if (OsHelper.isValidPathToBash(pathToBashParam)) {
81+
LOGGER.info("Path to bash registered to '{}'", pathToBashParam);
82+
this.pathToBash = pathToBashParam;
83+
config.setPathToGitBash(pathToBashParam);
84+
saveConfig();
85+
return true;
86+
}
87+
return false;
6288
}
6389

64-
public void setPathToGitBashExe(String pathToGitBashExe) {
65-
config.setPathToGitBash(pathToGitBashExe);
66-
saveConfig();
90+
public HostServices getHostServices() {
91+
return hostServices;
6792
}
6893

69-
public String getPathToGitBashExe() {
70-
return config.getPathToGitBash();
94+
public void setHostServices(HostServices hostServices) {
95+
this.hostServices = hostServices;
7196
}
7297

7398
public void setLastRunFolder(String lastRunFolder) {

src/main/java/com/github/introfog/gitwave/model/CommandExecutor.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,7 @@ private static List<RunnableCommand> createRunnableCommands(List<File> repositor
8686

8787
private static String[] constructCmdCommand(String gitRepoPath, String command) {
8888
List<String> cmdCommand = new ArrayList<>();
89-
if (OsRecogniser.isCurrentOsUnixLike()) {
90-
cmdCommand.add("bash");
91-
} else {
92-
cmdCommand.add(AppConfig.getInstance().getPathToGitBashExe().replace("\\", "/"));
93-
}
89+
cmdCommand.add(AppConfig.getInstance().getPathToBash());
9490
cmdCommand.add("-c");
9591
cmdCommand.add("cd '" + gitRepoPath + "' && " + command);
9692
return cmdCommand.toArray(new String[]{});
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/*
2+
* Copyright 2023-2024 Dmitry Chubrick
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.github.introfog.gitwave.model;
18+
19+
import java.io.BufferedReader;
20+
import java.io.IOException;
21+
import java.io.InputStreamReader;
22+
import org.slf4j.Logger;
23+
import org.slf4j.LoggerFactory;
24+
25+
public final class OsHelper {
26+
private static final Logger LOGGER = LoggerFactory.getLogger(OsHelper.class);
27+
28+
private OsHelper() {
29+
// Do nothing
30+
}
31+
32+
public static String getPathToBash(CurrentOs currentOs) {
33+
switch (currentOs) {
34+
case WINDOWS:
35+
LOGGER.info("Find path to git bash for Windows OS.");
36+
String pathToBash = extractPathToGitForWindows();
37+
LOGGER.info("Extracted path from Windows Registry: {}", pathToBash);
38+
if (pathToBash != null) {
39+
pathToBash = pathToBash.replace("\\", "/");
40+
}
41+
return isValidPathToBash(pathToBash) ? pathToBash : null;
42+
case LINUX:
43+
case MACOS:
44+
return "bash";
45+
default:
46+
return null;
47+
}
48+
}
49+
50+
public static boolean isValidPathToBash(String pathToBash) {
51+
try {
52+
LOGGER.info("Check if the following path to bash is valid: '{}'", pathToBash);
53+
if (pathToBash == null || pathToBash.isEmpty()) {
54+
LOGGER.info("'{}' isn't valid path to bash.", pathToBash);
55+
return false;
56+
}
57+
Process process = Runtime.getRuntime().exec(new String[]{pathToBash, "--version"});
58+
59+
String line;
60+
StringBuilder result = new StringBuilder();
61+
BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream()));
62+
63+
while ((line = stdout.readLine()) != null) {
64+
result.append(line);
65+
}
66+
stdout.close();
67+
68+
String output = result.toString();
69+
final boolean isValid = output.contains("bash");
70+
LOGGER.info("Output of the command '{} --version', and the result of check for validity is: {}", pathToBash, isValid);
71+
return isValid;
72+
} catch (IOException e) {
73+
LOGGER.warn("Command '{} --version' fail with the following exception.", pathToBash, e);
74+
return false;
75+
}
76+
}
77+
78+
public static CurrentOs getCurrentOs() {
79+
CurrentOs currentOs;
80+
String os = System.getProperty("os.name").toLowerCase();
81+
if (os.contains("win")) {
82+
currentOs = CurrentOs.WINDOWS;
83+
} else if (os.contains("mac")) {
84+
currentOs = CurrentOs.MACOS;
85+
} else if (os.contains("nix") || os.contains("nux") || os.contains("aix")) {
86+
currentOs = CurrentOs.LINUX;
87+
} else {
88+
currentOs = CurrentOs.UNRECOGNISED;
89+
}
90+
LOGGER.info("System.getProperty(\"os.name\")={}. Recognised OS: {}", os, currentOs);
91+
return currentOs;
92+
}
93+
94+
private static String extractPathToGitForWindows() {
95+
String installPath = null;
96+
97+
try {
98+
String value = readRegistry("HKLM\\SOFTWARE\\GitForWindows", "InstallPath");
99+
if (value != null && !value.isEmpty()) {
100+
installPath = value;
101+
}
102+
103+
if (installPath == null) {
104+
value = readRegistry("HKCU\\Software\\GitForWindows", "InstallPath");
105+
if (value != null && !value.isEmpty()) {
106+
installPath = value;
107+
}
108+
}
109+
} catch (Exception e) {
110+
LOGGER.warn("Extracting path from Windows Registry throw an exception.", e);
111+
}
112+
113+
return installPath == null ? null : installPath + "\\bin\\bash.exe";
114+
}
115+
116+
private static String readRegistry(String location, String key){
117+
try {
118+
Process process = Runtime.getRuntime().exec("REG QUERY " + location + " /v " + key);
119+
120+
String line;
121+
StringBuilder result = new StringBuilder();
122+
BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream()));
123+
124+
while ((line = stdout.readLine()) != null) {
125+
result.append(line);
126+
}
127+
stdout.close();
128+
129+
// Example of result: HKEY_LOCAL_MACHINE\SOFTWARE\GitForWindows InstallPath REG_SZ E:\Programs\Git
130+
if( !result.toString().contains(key)){
131+
return null;
132+
}
133+
134+
String[] parsed = result.toString().split("\\s+");
135+
return parsed[parsed.length-1];
136+
}
137+
catch (Exception e) {
138+
return null;
139+
}
140+
}
141+
142+
public enum CurrentOs {
143+
WINDOWS,
144+
MACOS,
145+
LINUX,
146+
UNRECOGNISED
147+
}
148+
}

0 commit comments

Comments
 (0)