Skip to content

Commit 04cbb23

Browse files
committed
Add OS-aware install wizard for g++/OpenGL deps, with confirm-before-install and proper cancel handling
1 parent 20c985e commit 04cbb23

3 files changed

Lines changed: 38 additions & 15 deletions

File tree

src/java/CppBuild.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,10 @@ private void checkGppAvailable(RunnerListener listener) throws Exception {
238238
try { if (Runtime.getRuntime().exec(new String[]{"g++","--version"}).waitFor()==0) return; }
239239
catch (Exception ignored) {}
240240

241-
// Try the guided installer first. If it succeeds, we're done; if the
242-
// user cancels or it fails, fall through to the existing dialog below.
241+
// Try the guided installer first. If it succeeds, we're done. If the
242+
// user cancels, InstallWizard throws CancelledByUser, which stops
243+
// the build entirely instead of falling through. Only a genuine
244+
// wizard failure (not a cancel) falls through to the dialog below.
243245
if (InstallWizard.run(listener)) return;
244246

245247
Object[] opts = { "Install Automatically", "Download MSYS2", "Cancel" };
@@ -272,8 +274,8 @@ else if (ch == 1) {
272274
catch (Exception ignored) {}
273275
if (isMac) {
274276
// Try the guided installer first (Xcode Command Line Tools, then
275-
// GLFW/GLEW via Homebrew if present). Falls through to the
276-
// existing dialog below if cancelled or unsuccessful.
277+
// GLFW/GLEW via Homebrew if present). A cancel throws and stops
278+
// the build; only a genuine failure falls through to the dialog.
277279
if (InstallWizard.run(listener)) return;
278280

279281
showGppDialog(
@@ -283,8 +285,8 @@ else if (ch == 1) {
283285
+ "Click Download Homebrew if not installed.</html>",
284286
"Download Homebrew", "https://brew.sh", listener);
285287
} else {
286-
// Try the guided installer first. Falls through to the existing
287-
// package-manager dialog below if cancelled or unsuccessful.
288+
// Try the guided installer first. A cancel throws and stops the
289+
// build; only a genuine failure falls through to the dialog below.
288290
if (InstallWizard.run(listener)) return;
289291

290292
// Detect package manager and offer auto-install
@@ -441,7 +443,7 @@ private boolean commandExists(String cmd) {
441443
} catch (Exception e) { return false; }
442444
}
443445

444-
private void checkNativeLibs(RunnerListener listener, File binary) {
446+
private void checkNativeLibs(RunnerListener listener, File binary) throws Exception {
445447
String os = System.getProperty("os.name").toLowerCase();
446448
boolean win = os.contains("win");
447449
boolean mac = os.contains("mac");
@@ -466,7 +468,7 @@ private boolean windowsLibsNowPresent(java.util.List<String> searchDirs, String[
466468
return true;
467469
}
468470

469-
private void checkWindowsDLLs(RunnerListener listener, File binary) {
471+
private void checkWindowsDLLs(RunnerListener listener, File binary) throws Exception {
470472
String[] required = { "glfw3.dll", "glew32.dll" };
471473
java.util.List<String> searchDirs = new java.util.ArrayList<>();
472474
searchDirs.add(binary.getParent());
@@ -557,7 +559,7 @@ private void checkWindowsDLLs(RunnerListener listener, File binary) {
557559
}
558560

559561
// ── macOS ──────────────────────────────────────────────────────────────────
560-
private void checkMacLibs(RunnerListener listener) {
562+
private void checkMacLibs(RunnerListener listener) throws Exception {
561563
// Check for glfw and glew via pkg-config or known Homebrew paths
562564
boolean glfwOk = new File("/opt/homebrew/lib/libglfw.dylib").exists()
563565
|| new File("/usr/local/lib/libglfw.dylib").exists()
@@ -626,7 +628,7 @@ private void checkMacLibs(RunnerListener listener) {
626628
}
627629

628630
// ── Linux ──────────────────────────────────────────────────────────────────
629-
private void checkLinuxLibs(RunnerListener listener) {
631+
private void checkLinuxLibs(RunnerListener listener) throws Exception {
630632
boolean glfwOk = new File("/usr/lib/libglfw.so").exists()
631633
|| new File("/usr/lib/x86_64-linux-gnu/libglfw.so").exists()
632634
|| new File("/usr/lib/x86_64-linux-gnu/libglfw.so.3").exists()

src/java/CppEditor.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,9 @@ public void handleRun(boolean present, Runnable stopCb, Runnable startCb) {
395395
statusError("Build failed — see console for errors.");
396396
deactivateRun();
397397
}
398+
} catch (InstallWizard.CancelledByUser e) {
399+
statusNotice("Cancelled.");
400+
deactivateRun();
398401
} catch (Exception e) {
399402
statusError(e.getMessage());
400403
deactivateRun();

src/java/InstallWizard.java

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@
2424
*/
2525
public class InstallWizard {
2626

27+
/**
28+
* Thrown when the user explicitly cancels the wizard (at the initial
29+
* missing-dependencies prompt, or mid-install). Callers should treat
30+
* this as "stop entirely" rather than falling back to other dialogs —
31+
* the user made a deliberate choice not to proceed.
32+
*/
33+
public static class CancelledByUser extends Exception {
34+
public CancelledByUser() { super("Installation cancelled by user."); }
35+
}
36+
2737
/**
2838
* Checks what's missing and, if anything is, shows a plain error dialog
2939
* first ("Missing: g++, glfw" + Install/Cancel). Only if the user clicks
@@ -34,7 +44,7 @@ public class InstallWizard {
3444
* this returns; false if the user cancelled or installation
3545
* could not be completed.
3646
*/
37-
public static boolean run(RunnerListener listener) {
47+
public static boolean run(RunnerListener listener) throws CancelledByUser {
3848
String os = System.getProperty("os.name").toLowerCase();
3949
InstallWizard w = new InstallWizard();
4050

@@ -52,6 +62,8 @@ public static boolean run(RunnerListener listener) {
5262
} else {
5363
// Unrecognized OS — we don't know how to install anything here, so
5464
// just tell the user exactly what's needed and let them sort it out.
65+
// This isn't a cancellation, so it returns false rather than
66+
// throwing — CppBuild's caller can still decide what to do next.
5567
java.util.List<String> generic = new java.util.ArrayList<>();
5668
generic.add("g++ (a C++17-capable compiler)");
5769
generic.add("glfw");
@@ -91,16 +103,22 @@ public static boolean run(RunnerListener listener) {
91103
}
92104
}
93105

94-
if (!proceed[0]) return false;
106+
if (!proceed[0]) throw new CancelledByUser();
95107

96108
// User confirmed — now open the real progress wizard and install.
109+
// A cancel from inside the wizard itself also surfaces as
110+
// CancelledByUser (checked via w.cancelled right after each call),
111+
// distinguishing "user backed out" from "install genuinely failed".
112+
boolean result;
97113
if (isWin) {
98-
return w.runWindows(missing);
114+
result = w.runWindows(missing);
99115
} else if (isMac) {
100-
return w.runMac(missing);
116+
result = w.runMac(missing);
101117
} else {
102-
return w.runLinux(missing);
118+
result = w.runLinux(missing);
103119
}
120+
if (!result && w.cancelled.get()) throw new CancelledByUser();
121+
return result;
104122
}
105123

106124
// ── Shared dialog plumbing ────────────────────────────────────────────

0 commit comments

Comments
 (0)