diff --git a/cli/pom.xml b/cli/pom.xml index 113a30ccb..654ca1e75 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -16,7 +16,6 @@ com.devonfw.tools.ide.cli.Ideasy ideasy ${project.artifactId}-${os.detected.classifier}-${os.detected.arch} - 17 0.9.28 3.24.1 2.4.0 diff --git a/cli/src/main/java/com/devonfw/tools/ide/completion/CompletionCandidateCollector.java b/cli/src/main/java/com/devonfw/tools/ide/completion/CompletionCandidateCollector.java index 9d1c64f1f..27fd2e709 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/completion/CompletionCandidateCollector.java +++ b/cli/src/main/java/com/devonfw/tools/ide/completion/CompletionCandidateCollector.java @@ -57,7 +57,7 @@ default int addAllMatches(String text, String[] sortedCandidates, Property pr index++; count++; } else { - index = -index; + index = -index - 1; } while ((index >= 0) && (index < sortedCandidates.length)) { if (sortedCandidates[index].startsWith(text)) { diff --git a/cli/src/main/java/com/devonfw/tools/ide/context/AbstractIdeContext.java b/cli/src/main/java/com/devonfw/tools/ide/context/AbstractIdeContext.java index e7e4c1bc9..9ce391150 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/context/AbstractIdeContext.java +++ b/cli/src/main/java/com/devonfw/tools/ide/context/AbstractIdeContext.java @@ -40,7 +40,8 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; -import java.net.InetAddress; +import java.net.URL; +import java.net.URLConnection; import java.nio.file.Files; import java.nio.file.Path; import java.util.HashMap; @@ -598,7 +599,13 @@ public boolean isOnline() { boolean online = false; try { int timeout = 1000; - online = InetAddress.getByName("github.com").isReachable(timeout); + //open a connection to github.com and try to retrieve data + //getContent fails if there is no connection + URLConnection connection = new URL("https://www.github.com").openConnection(); + connection.setConnectTimeout(timeout); + connection.getContent(); + online = true; + } catch (Exception ignored) { } diff --git a/cli/src/main/java/com/devonfw/tools/ide/context/IdeContext.java b/cli/src/main/java/com/devonfw/tools/ide/context/IdeContext.java index 0a87eb864..361e3a0b2 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/context/IdeContext.java +++ b/cli/src/main/java/com/devonfw/tools/ide/context/IdeContext.java @@ -445,6 +445,19 @@ default String getMavenArgs() { } + /** + * @return the String value for the variable M2_REPO, or null if called outside an IDEasy installation. + */ + default String getMavenRepoEnvVariable() { + + if (getIdeHome() != null) { + Path m2Repo = getConfPath().resolve(Mvn.M2_CONFIG_FOLDER).resolve("repository"); + return m2Repo.toString(); + } + return null; + + } + /** * Updates the current working directory (CWD) and configures the environment paths according to the specified parameters. This method is central to changing * the IDE's notion of where it operates, affecting where configurations, workspaces, settings, and other resources are located or loaded from. diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/mvn/Mvn.java b/cli/src/main/java/com/devonfw/tools/ide/tool/mvn/Mvn.java index 66132d649..607b513fb 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/mvn/Mvn.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/mvn/Mvn.java @@ -33,7 +33,8 @@ public class Mvn extends PluginBasedCommandlet { /** The name of the settings.xml */ public static final String SETTINGS_FILE = "settings.xml"; - private static final String M2_CONFIG_FOLDER = ".m2"; + /** The name of the m2 repository */ + public static final String M2_CONFIG_FOLDER = ".m2"; private static final String SETTINGS_SECURITY_FILE = "settings-security.xml"; diff --git a/cli/src/main/java/com/devonfw/tools/ide/variable/IdeVariables.java b/cli/src/main/java/com/devonfw/tools/ide/variable/IdeVariables.java index 396939a53..059f8b9fd 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/variable/IdeVariables.java +++ b/cli/src/main/java/com/devonfw/tools/ide/variable/IdeVariables.java @@ -41,9 +41,12 @@ public interface IdeVariables { /** {@link VariableDefinition} for version of maven (mvn). */ VariableDefinitionVersion MVN_VERSION = new VariableDefinitionVersion("MVN_VERSION", "MAVEN_VERSION"); - /** {@link VariableDefinition} arguments for maven to set the m2 repo location. */ + /** {@link VariableDefinition} arguments for maven to locate the settings file. */ VariableDefinitionString MAVEN_ARGS = new VariableDefinitionString("MAVEN_ARGS", null, c -> c.getMavenArgs(), false, true); + /** {@link VariableDefinition} arguments for maven to set the m2 repo location. */ + VariableDefinitionString M2_REPO = new VariableDefinitionString("M2_REPO", null, c -> c.getMavenRepoEnvVariable(), false, true); + /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getWorkspaceName() WORKSPACE}. */ VariableDefinitionString DOCKER_EDITION = new VariableDefinitionString("DOCKER_EDITION", null, c -> "rancher"); @@ -58,7 +61,7 @@ public interface IdeVariables { /** A {@link Collection} with all pre-defined {@link VariableDefinition}s. */ Collection> VARIABLES = List.of(PATH, HOME, WORKSPACE_PATH, IDE_HOME, IDE_ROOT, WORKSPACE, IDE_TOOLS, CREATE_START_SCRIPTS, - IDE_MIN_VERSION, MVN_VERSION, DOCKER_EDITION, JASYPT_OPTS, MAVEN_ARGS, PROJECT_NAME); + IDE_MIN_VERSION, MVN_VERSION, M2_REPO, DOCKER_EDITION, JASYPT_OPTS, MAVEN_ARGS, PROJECT_NAME); /** * @param name the name of the requested {@link VariableDefinition}. diff --git a/cli/src/main/java/com/devonfw/tools/ide/version/VersionSegment.java b/cli/src/main/java/com/devonfw/tools/ide/version/VersionSegment.java index fb47384f5..8f067891b 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/version/VersionSegment.java +++ b/cli/src/main/java/com/devonfw/tools/ide/version/VersionSegment.java @@ -222,6 +222,12 @@ public VersionComparisonResult compareVersion(VersionSegment other) { if (!lettersResult.isEqual()) { return lettersResult; } + if (!"_".equals(this.separator) && "_".equals(other.separator)) { + return VersionComparisonResult.GREATER; + } else if ("_".equals(this.separator) && !"_".equals(other.separator)) { + return VersionComparisonResult.LESS; + } + if (this.number < other.number) { return VersionComparisonResult.LESS; } else if (this.number > other.number) { diff --git a/cli/src/test/java/com/devonfw/tools/ide/completion/CompletionCandidateCollectorDefaultTest.java b/cli/src/test/java/com/devonfw/tools/ide/completion/CompletionCandidateCollectorDefaultTest.java new file mode 100644 index 000000000..d0ed48464 --- /dev/null +++ b/cli/src/test/java/com/devonfw/tools/ide/completion/CompletionCandidateCollectorDefaultTest.java @@ -0,0 +1,34 @@ +package com.devonfw.tools.ide.completion; + +import com.devonfw.tools.ide.commandlet.Commandlet; +import com.devonfw.tools.ide.commandlet.VersionCommandlet; +import com.devonfw.tools.ide.context.AbstractIdeContextTest; +import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.context.IdeTestContextMock; +import com.devonfw.tools.ide.property.Property; +import com.devonfw.tools.ide.property.VersionProperty; +import org.junit.jupiter.api.Test; + +class CompletionCandidateCollectorDefaultTest extends AbstractIdeContextTest { + + /** + * Test of {@link CompletionCandidateCollectorDefault#addAllMatches(String, String[], Property, Commandlet)} + */ + @Test + public void testAddAllMatches() { + + String[] sortedCandidates = { "1", "2.0", "2.1", "3" }; + String input = "2"; + String[] expectedCandidates = { "2.0", "2.1" }; + + VersionProperty versionProperty = new VersionProperty("", false, "version"); + IdeContext context = IdeTestContextMock.get(); + CompletionCandidateCollector collector = new CompletionCandidateCollectorDefault(context); + + int matches = collector.addAllMatches(input, sortedCandidates, versionProperty, new VersionCommandlet(context)); + + assertThat(matches).isEqualTo(2); + assertThat(collector.getCandidates().stream().map(CompletionCandidate::text)).containsExactly(expectedCandidates); + + } +} \ No newline at end of file diff --git a/cli/src/test/java/com/devonfw/tools/ide/version/VersionIdentifierTest.java b/cli/src/test/java/com/devonfw/tools/ide/version/VersionIdentifierTest.java index 20fa0ed8d..d25df1c58 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/version/VersionIdentifierTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/version/VersionIdentifierTest.java @@ -249,4 +249,15 @@ public void testMatchAny() { assertThat(pattern.matches(VersionIdentifier.of("17.0-SNAPSHOT"))).isTrue(); } + @Test + public void testCompareJavaVersions() { + + VersionIdentifier v21_35 = VersionIdentifier.of("21_35"); + VersionIdentifier v21_0_2_13 = VersionIdentifier.of("21.0.2_13"); + VersionIdentifier v21_0_3_9 = VersionIdentifier.of("21.0.3_9"); + assertThat(v21_35).isLessThan(v21_0_2_13); + assertThat(v21_0_2_13).isLessThan(v21_0_3_9); + assertThat(v21_0_3_9).isGreaterThan(v21_35); + } + } diff --git a/gui/pom.xml b/gui/pom.xml new file mode 100644 index 000000000..6cd3b2e15 --- /dev/null +++ b/gui/pom.xml @@ -0,0 +1,82 @@ + + + 4.0.0 + + com.devonfw.tools.IDEasy.dev + ide + dev-SNAPSHOT + ../pom.xml + + com.devonfw.tools.IDEasy + gui + ${revision} + gui + + + com.devonfw.ide.gui.AppLauncher + 21 + 4.0.18 + 0.0.8 + + + + + ${project.groupId} + ide-cli + ${project.version} + + + org.openjfx + javafx-controls + ${javafx.version} + + + org.openjfx + javafx-fxml + ${javafx.version} + + + org.testfx + testfx-core + ${testfx.version} + test + + + org.testfx + testfx-junit5 + ${testfx.version} + test + + + org.testfx + openjfx-monocle + 17.0.10 + test + + + + + + + org.openjfx + javafx-maven-plugin + ${javafx.maven.plugin.version} + + + + ${mainClass} + app + app + app + true + true + true + + + + + + + \ No newline at end of file diff --git a/gui/src/main/java/com/devonfw/ide/gui/App.java b/gui/src/main/java/com/devonfw/ide/gui/App.java new file mode 100644 index 000000000..7e875256e --- /dev/null +++ b/gui/src/main/java/com/devonfw/ide/gui/App.java @@ -0,0 +1,38 @@ +package com.devonfw.ide.gui; + +import com.devonfw.tools.ide.version.IdeVersion; +import javafx.application.Application; +import javafx.fxml.FXMLLoader; +import javafx.geometry.Rectangle2D; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.stage.Screen; +import javafx.stage.Stage; + +import java.io.IOException; + +/** + * GUI Application for IDEasy + */ +public class App extends Application { + + Parent root; + + @Override + public void start(Stage primaryStage) throws IOException { + + root = FXMLLoader.load(App.class.getResource("main-view.fxml")); + + Rectangle2D bounds = Screen.getPrimary().getVisualBounds(); + Scene scene = new Scene(root, bounds.getWidth() / 2, bounds.getHeight() / 2); + + primaryStage.setTitle("IDEasy - version " + IdeVersion.get()); + primaryStage.setScene(scene); + primaryStage.show(); + } + + public static void main(String[] args) { + + launch(args); + } +} diff --git a/gui/src/main/java/com/devonfw/ide/gui/AppLauncher.java b/gui/src/main/java/com/devonfw/ide/gui/AppLauncher.java new file mode 100644 index 000000000..3a3a78d6c --- /dev/null +++ b/gui/src/main/java/com/devonfw/ide/gui/AppLauncher.java @@ -0,0 +1,15 @@ +package com.devonfw.ide.gui; + +/** + * Launcher class for the App. + * Workaround for "Error: JavaFX runtime components are missing, and are required to run this application." + * Inspired by + * StackOverflow + */ +public class AppLauncher { + public static void main(final String[] args) { + + App.main(args); + } + +} diff --git a/gui/src/main/resources/com/devonfw/ide/gui/main-view.fxml b/gui/src/main/resources/com/devonfw/ide/gui/main-view.fxml new file mode 100644 index 000000000..ab0800c57 --- /dev/null +++ b/gui/src/main/resources/com/devonfw/ide/gui/main-view.fxml @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/gui/src/test/java/com/devonfw/ide/gui/AppBaseTest.java b/gui/src/test/java/com/devonfw/ide/gui/AppBaseTest.java new file mode 100644 index 000000000..1de30246f --- /dev/null +++ b/gui/src/test/java/com/devonfw/ide/gui/AppBaseTest.java @@ -0,0 +1,54 @@ +package com.devonfw.ide.gui; + +import javafx.stage.Stage; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.testfx.framework.junit5.ApplicationTest; +import org.testfx.matcher.base.NodeMatchers; + +import java.io.IOException; + +import static org.testfx.api.FxAssert.verifyThat; + +/** + * Base Test + */ +public class AppBaseTest extends ApplicationTest { + + @Override + public void start(Stage stage) throws IOException { + + new App().start(stage); + } + + /** + * Set up headless testing + * + * @throws IOException + */ + @BeforeAll + public static void setupHeadlessMode() { + + //Enable headless testing. Should be moved as a system property "-Dheadless=true" into workflows to only affect CI + System.setProperty("headless", "true"); + + if (Boolean.getBoolean("headless")) { + System.setProperty("testfx.robot", "glass"); + System.setProperty("glass.platform", "Monocle"); + System.setProperty("testfx.headless", "true"); + System.setProperty("prism.order", "sw"); + System.setProperty("java.awt.headless", "true"); + } + + } + + /** + * Test if welcome message is shown when GUI is started + */ + @Test + public void ensureHelloMessageIsShownOnStartUp() { + + verifyThat("#hellomessage", NodeMatchers.isNotNull()); + } + +} diff --git a/pom.xml b/pom.xml index cf21be915..217d4a590 100644 --- a/pom.xml +++ b/pom.xml @@ -19,6 +19,7 @@ IDEasy ${revision} + 17 @@ -51,6 +52,7 @@ documentation cli + gui