Skip to content

Commit 410822d

Browse files
committed
Add CMake Conditional Inheritance
1 parent 2302a5f commit 410822d

File tree

3 files changed

+73
-15
lines changed

3 files changed

+73
-15
lines changed

cppython/plugins/cmake/builder.py

+26-10
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from pathlib import Path
44

5-
from cppython.plugins.cmake.schema import CMakePresets, CMakeSyncData, ConfigurePreset
5+
from cppython.plugins.cmake.schema import CMakeData, CMakePresets, CMakeSyncData, ConfigurePreset
66

77

88
class Builder:
@@ -114,7 +114,7 @@ def write_cppython_preset(
114114
return cppython_preset_file
115115

116116
@staticmethod
117-
def generate_root_preset(preset_file: Path, cppython_preset_file: Path) -> CMakePresets:
117+
def generate_root_preset(preset_file: Path, cppython_preset_file: Path, cmake_data: CMakeData) -> CMakePresets:
118118
"""Generates the top level root preset with the include reference.
119119
120120
Args:
@@ -124,18 +124,34 @@ def generate_root_preset(preset_file: Path, cppython_preset_file: Path) -> CMake
124124
Returns:
125125
A CMakePresets object
126126
"""
127-
initial_root_preset = None
127+
default_configure_preset = ConfigurePreset(
128+
name=cmake_data.configuration_name,
129+
inherits='cppython',
130+
)
128131

129-
# If the file already exists, we need to compare it
130132
if preset_file.exists():
131133
with open(preset_file, encoding='utf-8') as file:
132134
initial_json = file.read()
133-
initial_root_preset = CMakePresets.model_validate_json(initial_json)
134-
root_preset = initial_root_preset.model_copy(deep=True)
135+
root_preset = CMakePresets.model_validate_json(initial_json)
136+
137+
if root_preset.configurePresets is None:
138+
root_preset.configurePresets = [default_configure_preset]
139+
140+
# Set defaults
141+
preset = next((p for p in root_preset.configurePresets if p.name == default_configure_preset.name), None)
142+
if preset:
143+
# If the name matches, we need to verify it inherits from cppython
144+
if preset.inherits is None:
145+
preset.inherits = 'cppython'
146+
elif isinstance(preset.inherits, str) and preset.inherits != 'cppython':
147+
preset.inherits = [preset.inherits, 'cppython']
148+
elif isinstance(preset.inherits, list) and 'cppython' not in preset.inherits:
149+
preset.inherits.append('cppython')
150+
else:
151+
root_preset.configurePresets.append(default_configure_preset)
152+
135153
else:
136154
# If the file doesn't exist, we need to default it for the user
137-
# TODO: Forward the tool's build directory
138-
default_configure_preset = ConfigurePreset(name='default', inherits='cppython', binaryDir='build')
139155
root_preset = CMakePresets(configurePresets=[default_configure_preset])
140156

141157
# Get the relative path to the cppython preset file
@@ -153,7 +169,7 @@ def generate_root_preset(preset_file: Path, cppython_preset_file: Path) -> CMake
153169
return root_preset
154170

155171
@staticmethod
156-
def write_root_presets(preset_file: Path, cppython_preset_file: Path) -> None:
172+
def write_root_presets(preset_file: Path, cppython_preset_file: Path, cmake_data: CMakeData) -> None:
157173
"""Read the top level json file and insert the include reference.
158174
159175
Receives a relative path to the tool cmake json file
@@ -172,7 +188,7 @@ def write_root_presets(preset_file: Path, cppython_preset_file: Path) -> None:
172188
initial_json = file.read()
173189
initial_root_preset = CMakePresets.model_validate_json(initial_json)
174190

175-
root_preset = Builder.generate_root_preset(preset_file, cppython_preset_file)
191+
root_preset = Builder.generate_root_preset(preset_file, cppython_preset_file, cmake_data)
176192

177193
# Only write the file if the data has changed
178194
if root_preset != initial_root_preset:

cppython/plugins/cmake/plugin.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,6 @@ def sync(self, sync_data: SyncData) -> None:
7171
self._cppython_preset_directory, self._provider_directory, sync_data
7272
)
7373

74-
self.builder.write_root_presets(self.data.preset_file, cppython_preset_file)
74+
self.builder.write_root_presets(self.data.preset_file, cppython_preset_file, self.data)
7575
case _:
7676
raise ValueError('Unsupported sync data type')

tests/unit/plugins/cmake/test_presets.py

+46-4
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,51 @@
33
from pathlib import Path
44

55
from cppython.plugins.cmake.builder import Builder
6-
from cppython.plugins.cmake.schema import CMakePresets, CMakeSyncData
6+
from cppython.plugins.cmake.schema import CMakeData, CMakePresets, CMakeSyncData
77
from cppython.utility.utility import TypeName
88

99

10-
class TestCMakePresets:
10+
class TestBuilder:
1111
"""Tests for the CMakePresets class"""
1212

13+
@staticmethod
14+
def test_generate_root_preset_new(tmp_path: Path) -> None:
15+
"""Test generate_root_preset when the preset file does not exist"""
16+
builder = Builder()
17+
preset_file = tmp_path / 'CMakePresets.json'
18+
cppython_preset_file = tmp_path / 'cppython.json'
19+
cmake_data = CMakeData(preset_file=preset_file, configuration_name='test-configuration')
20+
21+
# The function should create a new preset with the correct name and inheritance
22+
result = builder.generate_root_preset(preset_file, cppython_preset_file, cmake_data)
23+
assert result.configurePresets is not None
24+
assert any(p.name == 'test-configuration' for p in result.configurePresets)
25+
26+
preset = next(p for p in result.configurePresets if p.name == 'test-configuration')
27+
assert preset.inherits == 'cppython'
28+
29+
@staticmethod
30+
def test_generate_root_preset_existing(tmp_path: Path) -> None:
31+
"""Test generate_root_preset when the preset file already exists"""
32+
builder = Builder()
33+
preset_file = tmp_path / 'CMakePresets.json'
34+
cppython_preset_file = tmp_path / 'cppython.json'
35+
cmake_data = CMakeData(preset_file=preset_file, configuration_name='test-configuration')
36+
37+
# Create an initial preset file with a different preset
38+
initial_presets = CMakePresets(configurePresets=[])
39+
with open(preset_file, 'w', encoding='utf-8') as f:
40+
f.write(initial_presets.model_dump_json(exclude_none=True, by_alias=False, indent=4))
41+
42+
# Should add the new preset and include
43+
result = builder.generate_root_preset(preset_file, cppython_preset_file, cmake_data)
44+
assert result.configurePresets is not None
45+
assert any(p.name == 'test-configuration' for p in result.configurePresets)
46+
47+
48+
class TestWrites:
49+
"""Tests for writing the CMakePresets class"""
50+
1351
@staticmethod
1452
def test_provider_write(tmp_path: Path) -> None:
1553
"""Verifies that the provider preset writing works as intended
@@ -78,7 +116,9 @@ def test_root_write(tmp_path: Path) -> None:
78116

79117
cppython_preset_file = builder.write_cppython_preset(cppython_preset_directory, provider_directory, data)
80118

81-
builder.write_root_presets(root_file, cppython_preset_file)
119+
builder.write_root_presets(
120+
root_file, cppython_preset_file, CMakeData(preset_file=root_file, configuration_name='default')
121+
)
82122

83123
@staticmethod
84124
def test_relative_root_write(tmp_path: Path) -> None:
@@ -112,4 +152,6 @@ def test_relative_root_write(tmp_path: Path) -> None:
112152
builder.write_provider_preset(provider_directory, data)
113153

114154
cppython_preset_file = builder.write_cppython_preset(cppython_preset_directory, provider_directory, data)
115-
builder.write_root_presets(root_file, cppython_preset_file)
155+
builder.write_root_presets(
156+
root_file, cppython_preset_file, CMakeData(preset_file=root_file, configuration_name='default')
157+
)

0 commit comments

Comments
 (0)