From 0f3f56756fa7c97f3070f176ac32b2e7706544cf Mon Sep 17 00:00:00 2001 From: 2031 Date: Wed, 23 Sep 2026 20:10:26 +0300 Subject: [PATCH 1/2] Fix legacy variable at start of value skipped when value ends with '$' ProjectConfigBase._expand_interpolations rewrites the brace-less legacy variable `\` into `\` before interpolation. The guard that skips an escaped occurrence (`\$\`) read `value[x - 1]`; when the variable is at the start of the value `x` is 0, so `value[-1]` inspected the last character instead of a preceding one. A value that both starts with `\` and ends with `\$` (e.g. `\-\$`) was therefore treated as escaped and left unexpanded. Only skip when there is a real preceding character (`x > 0`). Mid-string variables, escaped `\$\$` occurrences, and non-matches are unaffected. --- platformio/project/config.py | 2 +- tests/project/test_config.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/platformio/project/config.py b/platformio/project/config.py index 82b76abf09..176180dd5d 100644 --- a/platformio/project/config.py +++ b/platformio/project/config.py @@ -323,7 +323,7 @@ def _expand_interpolations(self, section, option, value): stop = True for name in legacy_vars: x = value.find(f"${name}") - if x < 0 or value[x - 1] == "$": + if x < 0 or (x > 0 and value[x - 1] == "$"): continue value = "%s${%s}%s" % (value[:x], name, value[x + len(name) + 1 :]) stop = False diff --git a/tests/project/test_config.py b/tests/project/test_config.py index d21fd22e5b..bd01b81f07 100644 --- a/tests/project/test_config.py +++ b/tests/project/test_config.py @@ -672,6 +672,23 @@ def test_nested_interpolation(tmp_path: Path): assert testing_command[5] == '${UPLOAD_PORT and "-p "+UPLOAD_PORT}' +def test_legacy_variable_at_value_start(tmp_path: Path): + # A legacy (brace-less) $PROJECT_HASH at the start of a value must be expanded + # even when the value ends with "$". The escaped-variable guard used to read the + # last character (value[-1]) for a match at index 0 and wrongly skip expansion. + project_conf = tmp_path / "platformio.ini" + project_conf.write_text(""" +[env:myenv] +build_flags = $PROJECT_HASH-$ +""") + with fs.cd(str(tmp_path)): + config = ProjectConfig(str(project_conf)) + value = config.get("env:myenv", "build_flags")[0] + assert "$PROJECT_HASH" not in value + assert value.startswith(os.path.basename(str(tmp_path)) + "-") + assert value.endswith("-$") + + def test_extends_order(tmp_path: Path): project_conf = tmp_path / "platformio.ini" project_conf.write_text(""" From bc78dac2eab81038c901e0201af4a01b769d2864 Mon Sep 17 00:00:00 2001 From: 2031 Date: Wed, 23 Sep 2026 20:13:50 +0300 Subject: [PATCH 2/2] Add changelog entry for issue #5520 --- HISTORY.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/HISTORY.rst b/HISTORY.rst index 3b4ee12eb7..714af4b22e 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -26,6 +26,7 @@ test-driven methodologies, and modern toolchains for unrivaled success. * Preserved custom formatting, comments, and settings in ``.vscode/extensions.json`` during project IDE initialization instead of unconditionally overwriting the file (`issue #5473 `_) * Fixed path parsing in `pio ci `__ on Windows by using OS-native path separators for the ``PLATFORMIO_CI_SRC`` environment variable (`pull #5514 `_) * Fixed an issue where undefine flags with spaces (e.g., ``-U MACRO``) in ``build_flags`` were parsed incorrectly, passing only a bare ``-U`` to the compiler (`issue #5237 `_) +* Fixed an issue where a legacy ``$PROJECT_HASH`` variable at the start of an option value was not expanded when the value also ended with a ``$`` character (`issue #5520 `_) 6.2.0 (2026-09-05) ~~~~~~~~~~~~~~~~~~