From 2cff5601cbc8d309eef7dadfe0fdff751ed00622 Mon Sep 17 00:00:00 2001 From: Denys Almazov Date: Tue, 14 Jul 2026 09:58:45 +0300 Subject: [PATCH 1/2] feat: adding patch version to the esp-idf manager --- .../idf/core/tools/util/ToolsUtility.java | 78 +++++++++++++++++++ .../idf/core/tools/test/ToolsUtilityTest.java | 68 ++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 tests/com.espressif.idf.core.test/src/com/espressif/idf/core/tools/test/ToolsUtilityTest.java diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/util/ToolsUtility.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/util/ToolsUtility.java index 065c71759..097a8145a 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/util/ToolsUtility.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/util/ToolsUtility.java @@ -7,8 +7,12 @@ import java.io.BufferedReader; import java.io.File; import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.eclipse.core.runtime.Platform; @@ -25,12 +29,86 @@ */ public class ToolsUtility { + private static final Pattern IDF_VERSION_MAJOR_PATTERN = Pattern.compile("IDF_VERSION_MAJOR\\s+(\\d+)"); //$NON-NLS-1$ + private static final Pattern IDF_VERSION_MINOR_PATTERN = Pattern.compile("IDF_VERSION_MINOR\\s+(\\d+)"); //$NON-NLS-1$ + private static final Pattern IDF_VERSION_PATCH_PATTERN = Pattern.compile("IDF_VERSION_PATCH\\s+(\\d+)"); //$NON-NLS-1$ + + /** + * Detects the ESP-IDF version for the given installation. + *

+ * Prefers the full {@code MAJOR.MINOR.PATCH} read directly from {@code tools/cmake/version.cmake} + * under the installation's {@code IDF_PATH}. This is intentionally not derived from the + * {@code ESP_IDF_VERSION} environment variable: ESP-IDF and EIM define that variable as + * {@code MAJOR.MINOR} only (components consume it in Kconfig, e.g. {@code Kconfig.idf_v5.5.in}), so + * it never carries the patch component. When {@code version.cmake} cannot be read, falls back to the + * {@code ESP_IDF_VERSION} value printed by the activation script. + */ public static String getIdfVersion(EimInstallationModel installation) { + String versionFromCMake = readIdfVersionFromCMake(installation.getPath()); + if (!StringUtil.isEmpty(versionFromCMake)) + { + return versionFromCMake; + } + return installation.getActivationScript().map(ToolsUtility::readIdfVersionFromScript) .orElse(StringUtil.EMPTY); } + private static String readIdfVersionFromCMake(String idfPath) + { + if (StringUtil.isEmpty(idfPath)) + { + return StringUtil.EMPTY; + } + + Path versionCMakeFile = Path.of(idfPath, "tools", "cmake", "version.cmake"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + return parseVersionCMake(versionCMakeFile); + } + + /** + * Parses {@code version.cmake} and returns {@code MAJOR.MINOR.PATCH} (or {@code MAJOR.MINOR} when + * the patch entry is absent). Returns an empty string when the file is missing or the required + * major/minor entries cannot be found. + */ + public static String parseVersionCMake(Path versionCMakeFile) + { + if (versionCMakeFile == null || !Files.isRegularFile(versionCMakeFile)) + { + return StringUtil.EMPTY; + } + + try + { + String content = Files.readString(versionCMakeFile); + String major = firstGroup(IDF_VERSION_MAJOR_PATTERN, content); + String minor = firstGroup(IDF_VERSION_MINOR_PATTERN, content); + if (major == null || minor == null) + { + return StringUtil.EMPTY; + } + + String patch = firstGroup(IDF_VERSION_PATCH_PATTERN, content); + if (patch == null) + { + return major + "." + minor; //$NON-NLS-1$ + } + + return major + "." + minor + "." + patch; //$NON-NLS-1$ //$NON-NLS-2$ + } + catch (Exception e) + { + Logger.log(e); + return StringUtil.EMPTY; + } + } + + private static String firstGroup(Pattern pattern, String content) + { + Matcher matcher = pattern.matcher(content); + return matcher.find() ? matcher.group(1) : null; + } + private static String readIdfVersionFromScript(String activationScript) { String espIdfVersion = StringUtil.EMPTY; diff --git a/tests/com.espressif.idf.core.test/src/com/espressif/idf/core/tools/test/ToolsUtilityTest.java b/tests/com.espressif.idf.core.test/src/com/espressif/idf/core/tools/test/ToolsUtilityTest.java new file mode 100644 index 000000000..b9ab6706e --- /dev/null +++ b/tests/com.espressif.idf.core.test/src/com/espressif/idf/core/tools/test/ToolsUtilityTest.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright 2026 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ +package com.espressif.idf.core.tools.test; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import com.espressif.idf.core.tools.util.ToolsUtility; + +/** + * Unit tests for {@link ToolsUtility#parseVersionCMake(Path)}. + */ +public class ToolsUtilityTest +{ + @Test + void full_version_includes_patch(@TempDir Path tempDir) throws IOException + { + Path file = writeVersionCMake(tempDir, """ + set(IDF_VERSION_MAJOR 6) + set(IDF_VERSION_MINOR 0) + set(IDF_VERSION_PATCH 1) + """); + Assertions.assertEquals("6.0.1", ToolsUtility.parseVersionCMake(file)); + } + + @Test + void missing_patch_falls_back_to_major_minor(@TempDir Path tempDir) throws IOException + { + Path file = writeVersionCMake(tempDir, """ + set(IDF_VERSION_MAJOR 5) + set(IDF_VERSION_MINOR 3) + """); + Assertions.assertEquals("5.3", ToolsUtility.parseVersionCMake(file)); + } + + @Test + void missing_minor_returns_empty(@TempDir Path tempDir) throws IOException + { + Path file = writeVersionCMake(tempDir, "set(IDF_VERSION_MAJOR 6)\n"); + Assertions.assertEquals("", ToolsUtility.parseVersionCMake(file)); + } + + @Test + void nonexistent_file_returns_empty(@TempDir Path tempDir) + { + Assertions.assertEquals("", ToolsUtility.parseVersionCMake(tempDir.resolve("version.cmake"))); + } + + @Test + void null_file_returns_empty() + { + Assertions.assertEquals("", ToolsUtility.parseVersionCMake(null)); + } + + private static Path writeVersionCMake(Path dir, String content) throws IOException + { + Path file = dir.resolve("version.cmake"); + Files.writeString(file, content); + return file; + } +} From 679b4a8665be6e7d1b7e42aecf808f1c0c55e71a Mon Sep 17 00:00:00 2001 From: Denys Almazov Date: Tue, 14 Jul 2026 10:26:36 +0300 Subject: [PATCH 2/2] fix: handling potential exception during file parse --- .../idf/core/tools/util/ToolsUtility.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/util/ToolsUtility.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/util/ToolsUtility.java index 097a8145a..de12aafc5 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/util/ToolsUtility.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/tools/util/ToolsUtility.java @@ -6,8 +6,10 @@ import java.io.BufferedReader; import java.io.File; +import java.io.IOException; import java.io.InputStreamReader; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; @@ -62,8 +64,18 @@ private static String readIdfVersionFromCMake(String idfPath) return StringUtil.EMPTY; } - Path versionCMakeFile = Path.of(idfPath, "tools", "cmake", "version.cmake"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - return parseVersionCMake(versionCMakeFile); + try + { + Path versionCMakeFile = Path.of(idfPath, "tools", "cmake", "version.cmake"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + return parseVersionCMake(versionCMakeFile); + + } + catch (InvalidPathException e) + { + Logger.log(e); + return StringUtil.EMPTY; + } + } /** @@ -96,7 +108,7 @@ public static String parseVersionCMake(Path versionCMakeFile) return major + "." + minor + "." + patch; //$NON-NLS-1$ //$NON-NLS-2$ } - catch (Exception e) + catch (IOException e) { Logger.log(e); return StringUtil.EMPTY;