From a78d55c9ec4221c4404879c26df4152b9b636223 Mon Sep 17 00:00:00 2001 From: krystynaShatkovska Date: Wed, 12 Aug 2026 12:58:25 +0200 Subject: [PATCH 1/5] #2286: Fix SystemPath.findBinary to search extraPathEntries --- .../devonfw/tools/ide/common/SystemPath.java | 6 ++++++ .../tools/ide/common/SystemPathTest.java | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) 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..ad77b42768 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 @@ -143,6 +143,25 @@ void testFindBinaryFindsNothingWithoutFilter() { assertThat(result).isEqualTo(test); } + @Test + void testFindBinaryFindsBinaryInExtraPathEntries() throws java.io.IOException { + // arrange + IdeTestContext context = newContext(PROJECT_BASIC); + Path binDir = context.getIdeHome().resolve("scratch-bin"); + java.nio.file.Files.createDirectories(binDir); + java.nio.file.Files.writeString(binDir.resolve("faketool.cmd"), "@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(binDir.resolve("faketool.cmd")); + } + @Test void testConstructorNormalizesPathEntryWithControlCharactersAndKeepsIt() { // arrange From 3c134291b5ca27c6d802d782702ab400c439bc07 Mon Sep 17 00:00:00 2001 From: krystynaShatkovska Date: Thu, 13 Aug 2026 09:20:32 +0200 Subject: [PATCH 2/5] #2286: Fix SystemPathTest.testFindBinaryFindsBinaryInExtraPathEntries to work on Linux The test created 'faketool.cmd' which only exists on Windows. On Linux, findBinaryInOrder doesn't try .cmd extensions, so the file was never found, causing the assertion to fail. Fixed by creating a plain 'faketool' file without extension, which works on both Linux (no extension search) and Windows (falls through EXTENSION_PRIORITY to empty extension). --- .../java/com/devonfw/tools/ide/common/SystemPathTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 ad77b42768..958fd83e49 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 @@ -149,7 +149,9 @@ void testFindBinaryFindsBinaryInExtraPathEntries() throws java.io.IOException { IdeTestContext context = newContext(PROJECT_BASIC); Path binDir = context.getIdeHome().resolve("scratch-bin"); java.nio.file.Files.createDirectories(binDir); - java.nio.file.Files.writeString(binDir.resolve("faketool.cmd"), "@echo hi"); + // create a plain binary name (no extension) so it works on both Linux and Windows + Path fakeToolFile = binDir.resolve("faketool"); + java.nio.file.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()); @@ -159,7 +161,7 @@ void testFindBinaryFindsBinaryInExtraPathEntries() throws java.io.IOException { assertThat(merged.toString()).contains(binDir.toString()); Path resolved = merged.findBinary(Path.of("faketool")); assertThat(resolved).isNotEqualTo(Path.of("faketool")); - assertThat(resolved).isEqualTo(binDir.resolve("faketool.cmd")); + assertThat(resolved).isEqualTo(fakeToolFile); } @Test From fa6dff45cf4bcdb9758eee5a0030d9e5d9ddc1f9 Mon Sep 17 00:00:00 2001 From: krystynaShatkovska Date: Fri, 14 Aug 2026 09:35:49 +0200 Subject: [PATCH 3/5] #2286: Fix imports and add precedence test for extraPathEntries over tool2pathMap --- .../tools/ide/common/SystemPathTest.java | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) 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 958fd83e49..3cf587edda 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; @@ -144,14 +146,14 @@ void testFindBinaryFindsNothingWithoutFilter() { } @Test - void testFindBinaryFindsBinaryInExtraPathEntries() throws java.io.IOException { + void testFindBinaryFindsBinaryInExtraPathEntries() throws IOException { // arrange IdeTestContext context = newContext(PROJECT_BASIC); Path binDir = context.getIdeHome().resolve("scratch-bin"); - java.nio.file.Files.createDirectories(binDir); + Files.createDirectories(binDir); // create a plain binary name (no extension) so it works on both Linux and Windows Path fakeToolFile = binDir.resolve("faketool"); - java.nio.file.Files.writeString(fakeToolFile, "@echo hi"); + 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()); @@ -164,6 +166,28 @@ void testFindBinaryFindsBinaryInExtraPathEntries() throws java.io.IOException { assertThat(resolved).isEqualTo(fakeToolFile); } + @Test + void testFindBinaryExtraPathEntriesWinsOverTool2pathMap() throws IOException { + // arrange - create two directories, both with a binary named "mytool" + IdeTestContext context = newContext(PROJECT_BASIC); + Path toolDir = context.getIdeHome().resolve("software-tool"); + Files.createDirectories(toolDir); + Files.writeString(toolDir.resolve("mytool"), "tool-version"); + + Path extraDir = context.getIdeHome().resolve("extra-path"); + Files.createDirectories(extraDir); + Files.writeString(extraDir.resolve("mytool"), "extra-version"); + + // tool2pathMap has "toolDir", 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(toolDir.resolve("mytool")); + } + @Test void testConstructorNormalizesPathEntryWithControlCharactersAndKeepsIt() { // arrange From 65051e2063f2b772dc3bbcbbe5a8384d87985d7d Mon Sep 17 00:00:00 2001 From: krystynaShatkovska Date: Fri, 14 Aug 2026 09:41:11 +0200 Subject: [PATCH 4/5] #2286: Add CHANGELOG entry and fix formatting --- CHANGELOG.adoc | 2 ++ 1 file changed, 2 insertions(+) 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]. From 7ee800b4c30ab093e792198e67e24776ad0602dd Mon Sep 17 00:00:00 2001 From: krystynaShatkovska Date: Fri, 14 Aug 2026 10:40:49 +0200 Subject: [PATCH 5/5] Fix testFindBinaryExtraPathEntriesWinsOverTool2pathMap test setup The test created 'mytool' as a plain file, but collectToolPath only registers subdirectories (checks Files.isDirectory before adding to tool2pathMap). Changed to create 'mytool' as a subdirectory with the binary file inside, so it's properly registered in tool2pathMap and the test correctly verifies extra PATH entries win over tool2pathMap. Fixes reviewer feedback on PR #2286. --- .../com/devonfw/tools/ide/common/SystemPathTest.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) 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 3cf587edda..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 @@ -169,23 +169,26 @@ void testFindBinaryFindsBinaryInExtraPathEntries() throws IOException { @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); - Files.writeString(toolDir.resolve("mytool"), "tool-version"); + 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 "toolDir", extraPathEntries has "extraDir" + // 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(toolDir.resolve("mytool")); + assertThat(resolved).isNotEqualTo(mytoolInToolDir.resolve("mytool")); } @Test