diff --git a/tools/idf_py_actions/mcp_ext.py b/tools/idf_py_actions/mcp_ext.py index 5a7432bcc4d..73dcc6420ed 100644 --- a/tools/idf_py_actions/mcp_ext.py +++ b/tools/idf_py_actions/mcp_ext.py @@ -47,10 +47,16 @@ def _is_valid_project_dir(directory: str) -> bool: if not cmakelists_path.is_file(): return False + # Normalised patterns (whitespace removed) for whitespace-insensitive matching. + # CMake treats whitespace inside include(...) as insignificant, so + # `include( $ENV{...} )` must be accepted alongside `include($ENV{...})`. + normalised_patterns = [''.join(p.split()) for p in CMAKE_PROJECT_LINE] + try: with open(str(cmakelists_path), encoding='utf-8') as f: for line in f: - if any(proj_line in line for proj_line in CMAKE_PROJECT_LINE): + line_normalised = ''.join(line.split()) + if any(line_normalised.startswith(pattern) for pattern in normalised_patterns): return True except Exception: return False diff --git a/tools/test_idf_py/test_mcp_ext.py b/tools/test_idf_py/test_mcp_ext.py index d5dea6c5d56..0e5e0ac6fb9 100644 --- a/tools/test_idf_py/test_mcp_ext.py +++ b/tools/test_idf_py/test_mcp_ext.py @@ -189,6 +189,34 @@ class TestIsValidProjectDir: proj = _make_invalid_project(tmp_path / 'plain') assert mod._is_valid_project_dir(str(proj)) is False + def test_cmakelists_with_spaces_in_include( + self, tmp_path: Path, mcp_ext: tuple[types.ModuleType, _MockFastMCP] + ) -> None: + mod, _ = mcp_ext + path = tmp_path / 'spaced' + path.mkdir() + (path / 'CMakeLists.txt').write_text( + 'cmake_minimum_required(VERSION 3.16)\n' + 'include( $ENV{IDF_PATH}/tools/cmake/project.cmake )\n' + 'project(hello_world)\n', + encoding='utf-8', + ) + assert mod._is_valid_project_dir(str(path)) is True + + def test_commented_out_include_is_rejected( + self, tmp_path: Path, mcp_ext: tuple[types.ModuleType, _MockFastMCP] + ) -> None: + mod, _ = mcp_ext + path = tmp_path / 'commented' + path.mkdir() + (path / 'CMakeLists.txt').write_text( + 'cmake_minimum_required(VERSION 3.16)\n' + '# include($ENV{IDF_PATH}/tools/cmake/project.cmake)\n' + 'project(hello_world)\n', + encoding='utf-8', + ) + assert mod._is_valid_project_dir(str(path)) is False + def test_empty_string(self, mcp_ext: tuple[types.ModuleType, _MockFastMCP]) -> None: mod, _ = mcp_ext assert mod._is_valid_project_dir('') is False