diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 8866a010de..e57bae3c37 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -6,6 +6,8 @@ This file documents all notable changes to https://github.com/devonfw/IDEasy[IDE Release with new features and bugfixes: +* https://github.com/devonfw/IDEasy/issues/2286[#2286]: Fix SystemPath.findBinary to search extraPathEntries + The full list of changes for this release can be found in https://github.com/devonfw/IDEasy/milestone/49?closed=1[milestone 2026.08.002]. diff --git a/cli/src/main/java/com/devonfw/tools/ide/common/SystemPath.java b/cli/src/main/java/com/devonfw/tools/ide/common/SystemPath.java index 310acc00ba..d3215a5c09 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/common/SystemPath.java +++ b/cli/src/main/java/com/devonfw/tools/ide/common/SystemPath.java @@ -284,6 +284,12 @@ public Path findBinary(Path toolPath, Predicate filter) { String fileName = toolPath.getFileName().toString(); if (parent == null) { + for (Path path : this.extraPathEntries) { + Path binaryPath = findBinaryInOrder(path, fileName); + if (binaryPath != null && filter.test(binaryPath)) { + return binaryPath; + } + } for (Path path : this.tool2pathMap.values()) { Path binaryPath = findBinaryInOrder(path, fileName); if (binaryPath != null && filter.test(binaryPath)) { diff --git a/cli/src/test/java/com/devonfw/tools/ide/common/SystemPathTest.java b/cli/src/test/java/com/devonfw/tools/ide/common/SystemPathTest.java index a2e9c3853c..2fff021f0f 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/common/SystemPathTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/common/SystemPathTest.java @@ -1,5 +1,7 @@ package com.devonfw.tools.ide.common; +import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; @@ -143,6 +145,52 @@ void testFindBinaryFindsNothingWithoutFilter() { assertThat(result).isEqualTo(test); } + @Test + void testFindBinaryFindsBinaryInExtraPathEntries() throws IOException { + // arrange + IdeTestContext context = newContext(PROJECT_BASIC); + Path binDir = context.getIdeHome().resolve("scratch-bin"); + Files.createDirectories(binDir); + // create a plain binary name (no extension) so it works on both Linux and Windows + Path fakeToolFile = binDir.resolve("faketool"); + Files.writeString(fakeToolFile, "@echo hi"); + + // empty PATH and no software folder, so tool2pathMap and paths stay empty + SystemPath base = new SystemPath(context, "", null, null, ';', List.of()); + SystemPath merged = base.withPath(null, List.of(binDir)); + + // assert + assertThat(merged.toString()).contains(binDir.toString()); + Path resolved = merged.findBinary(Path.of("faketool")); + assertThat(resolved).isNotEqualTo(Path.of("faketool")); + assertThat(resolved).isEqualTo(fakeToolFile); + } + + @Test + void testFindBinaryExtraPathEntriesWinsOverTool2pathMap() throws IOException { + // arrange - create two directories, both with a binary named "mytool" + // tool2pathMap collects subdirectories of softwarePath, so mytool must be a subdirectory + IdeTestContext context = newContext(PROJECT_BASIC); + Path toolDir = context.getIdeHome().resolve("software-tool"); + Files.createDirectories(toolDir); + Path mytoolInToolDir = toolDir.resolve("mytool"); + Files.createDirectories(mytoolInToolDir); + Files.writeString(mytoolInToolDir.resolve("mytool"), "tool-version"); + + Path extraDir = context.getIdeHome().resolve("extra-path"); + Files.createDirectories(extraDir); + Files.writeString(extraDir.resolve("mytool"), "extra-version"); + + // tool2pathMap has "software-tool" (mytool is a subdirectory → registered), extraPathEntries has "extraDir" + SystemPath base = new SystemPath(context, "", null, toolDir, ';', List.of()); + SystemPath merged = base.withPath(null, List.of(extraDir)); + + // assert - findBinary should return the one from extraPathEntries, NOT from tool2pathMap + Path resolved = merged.findBinary(Path.of("mytool")); + assertThat(resolved).isEqualTo(extraDir.resolve("mytool")); + assertThat(resolved).isNotEqualTo(mytoolInToolDir.resolve("mytool")); + } + @Test void testConstructorNormalizesPathEntryWithControlCharactersAndKeepsIt() { // arrange