Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Release with new features and bugfixes:
* https://github.com/devonfw/IDEasy/issues/2292[#2292]: Questions appear twice
* https://github.com/devonfw/IDEasy/issues/825[#825]: Add commandlet for GC Log Analyzer
* https://github.com/devonfw/IDEasy/issues/1938[#1938]: GUI not launchable outside of project context
* https://github.com/devonfw/IDEasy/issues/2206[#2206]: IDEasy title not properly shown on macOS

The full list of changes for this release can be found in https://github.com/devonfw/IDEasy/milestone/48?closed=1[milestone 2026.08.001].

Expand Down
22 changes: 21 additions & 1 deletion cli/src/main/java/com/devonfw/tools/ide/tool/gui/Gui.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ protected void doRun() {
"-f", //use specified POM file
pomPath.toString(),
"org.codehaus.mojo:exec-maven-plugin:3.1.0:exec",
"-Dexec.executable=java",
"-Dexec.executable=" + getGuiExecutable(javaInstallation),
"-Dexec.classpathScope=compile",
"-Dexec.args=-classpath %classpath com.devonfw.ide.gui.AppLauncher",
"-Dexec.async=true"
Expand All @@ -111,4 +111,24 @@ protected void doRun() {
"Failed to launch the GUI. If maven reports issues with dependency resolution, check whether the maven M2 repo is enabled in your project.", e);
}
}

/**
* The GUI is launched as a plain {@code java} process without a native app bundle. On macOS this makes the Dock and menu bar show the executable's
* filename "java" instead of "IDEasy" (see issue #2206). As a workaround we exec a symlink named "IDEasy" that points to the real java executable instead
* of exec-ing "java" directly.
*
* @param javaInstallation the {@link ToolInstallation} of the java tool used to launch the GUI.
* @return the executable to pass to Maven's {@code exec:exec} goal in order to launch the GUI.
*/
String getGuiExecutable(ToolInstallation javaInstallation) {

if (!this.context.getSystemInfo().isMac()) {
return "java";
}
Path javaExecutable = javaInstallation.binDir().resolve("java");
Path link = this.context.getTempPath().resolve("IDEasy");
this.context.getFileAccess().mkdirs(link.getParent());
this.context.getFileAccess().symlink(javaExecutable, link, false);
return link.toString();
}
}
86 changes: 86 additions & 0 deletions cli/src/test/java/com/devonfw/tools/ide/tool/gui/GuiTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package com.devonfw.tools.ide.tool.gui;

import java.nio.file.Files;
import java.nio.file.Path;

import org.junit.jupiter.api.Test;

import com.devonfw.tools.ide.context.AbstractIdeContextTest;
import com.devonfw.tools.ide.context.AbstractIdeTestContext;
import com.devonfw.tools.ide.context.IdeTestContext;
import com.devonfw.tools.ide.io.WindowsSymlinkTestHelper;
import com.devonfw.tools.ide.os.SystemInfoMock;
import com.devonfw.tools.ide.tool.ToolInstallation;
import com.devonfw.tools.ide.version.VersionIdentifier;

/**
* Test of {@link Gui}.
*/
class GuiTest extends AbstractIdeContextTest {

private ToolInstallation newJavaInstallation(IdeTestContext context) {

Path binDir = context.getSoftwarePath().resolve("java/bin");
context.getFileAccess().mkdirs(binDir);
Path javaExecutable = binDir.resolve("java");
try {
Files.createFile(javaExecutable);
} catch (Exception e) {
throw new IllegalStateException(e);
}
return new ToolInstallation(binDir.getParent(), binDir.getParent(), binDir, VersionIdentifier.of("25.0.0"), false);
}

@Test
void testGetGuiExecutableOnMacCreatesSymlinkNamedIDEasy() throws Exception {

// arrange
WindowsSymlinkTestHelper.assumeSymlinksSupported();
IdeTestContext context = newContext(PROJECT_BASIC, null, true);
((AbstractIdeTestContext) context).setSystemInfo(SystemInfoMock.MAC_ARM64);
ToolInstallation javaInstallation = newJavaInstallation(context);
Gui gui = new Gui(context);

// act
String executable = gui.getGuiExecutable(javaInstallation);

// assert
Path link = context.getTempPath().resolve("IDEasy");
assertThat(executable).isEqualTo(link.toString());
assertThat(Files.isSymbolicLink(link)).isTrue();
assertThat(link.toRealPath()).isEqualTo(javaInstallation.binDir().resolve("java").toRealPath());
}

@Test
void testGetGuiExecutableOnWindowsReturnsPlainJava() {

// arrange
IdeTestContext context = newContext(PROJECT_BASIC, null, true);
((AbstractIdeTestContext) context).setSystemInfo(SystemInfoMock.WINDOWS_X64);
ToolInstallation javaInstallation = newJavaInstallation(context);
Gui gui = new Gui(context);

// act
String executable = gui.getGuiExecutable(javaInstallation);

// assert
assertThat(executable).isEqualTo("java");
}

@Test
void testGetGuiExecutableOnLinuxReturnsPlainJava() {

// arrange
IdeTestContext context = newContext(PROJECT_BASIC, null, true);
((AbstractIdeTestContext) context).setSystemInfo(SystemInfoMock.LINUX_X64);
ToolInstallation javaInstallation = newJavaInstallation(context);
Gui gui = new Gui(context);

// act
String executable = gui.getGuiExecutable(javaInstallation);

// assert
assertThat(executable).isEqualTo("java");
}

}