Skip to content

CMakePreset Directory Layout #51

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 18 additions & 44 deletions cppython/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import logging
from importlib import metadata
from pathlib import Path
from typing import Any, Type, TypeVar

from cppython_core.core import cppython_logger
Expand All @@ -19,8 +18,8 @@
)
from pydantic import create_model

from cppython.schema import API, CMakePresets, ConfigurePreset, ProjectConfiguration
from cppython.utility import write_preset
from cppython.schema import API, ProjectConfiguration
from cppython.utility import write_preset, write_presets


class ProjectBuilder:
Expand Down Expand Up @@ -188,31 +187,6 @@ def download(self):
else:
cppython_logger.info(f"The {generator.name()} generator is already downloaded")

def _write_generator_presets(self, tool_path: Path, generator: Generator, toolchain_path: Path) -> Path:
"""
Write a generator preset.
@returns - The written directory
"""
generator_tool_path = tool_path / generator.name()
generator_tool_path.mkdir(parents=True, exist_ok=True)

configure_preset = ConfigurePreset(name=generator.name(), hidden=True, toolchainFile=toolchain_path)
presets = CMakePresets(configurePresets=[configure_preset])

write_preset(generator_tool_path, presets)

return generator_tool_path

def _write_presets(self, tool_path: Path, names: list[str], includes: list[Path]) -> None:
"""
Write the cppython main preset
"""

configure_preset = ConfigurePreset(name="cppython", hidden=True, inherits=names)
presets = CMakePresets(configurePresets=[configure_preset], include=includes)

write_preset(tool_path, presets)

# API Contract
def install(self) -> None:
"""
Expand All @@ -228,20 +202,20 @@ def install(self) -> None:
tool_path = self.pyproject.tool.cppython.tool_path
tool_path.mkdir(parents=True, exist_ok=True)

names = []
includes = []
generator_output = []

# TODO: Async
for generator in self._generators:
cppython_logger.info(f"Installing {generator.name()} generator")

toolchain_path = generator.install()

directory = self._write_generator_presets(tool_path, generator, toolchain_path)
includes.append(directory)
names.append(generator.name())
try:
toolchain_path = generator.install()
generator_output.append((generator.name(), toolchain_path))
except Exception as exception:
cppython_logger.error(f"Generator {generator.name()} failed to install")
raise exception

self._write_presets(tool_path, names, includes)
write_presets(tool_path, generator_output)

def update(self) -> None:
"""
Expand All @@ -256,17 +230,17 @@ def update(self) -> None:
tool_path = self.pyproject.tool.cppython.tool_path
tool_path.mkdir(parents=True, exist_ok=True)

names = []
includes = []
generator_output = []

# TODO: Async
for generator in self._generators:
cppython_logger.info(f"Updating {generator.name()} generator")

toolchain_path = generator.update()

directory = self._write_generator_presets(tool_path, generator, toolchain_path)
includes.append(directory)
names.append(generator.name())
try:
toolchain_path = generator.update()
generator_output.append((generator.name(), toolchain_path))
except Exception as exception:
cppython_logger.error(f"Generator {generator.name()} failed to update")
raise exception

self._write_presets(tool_path, names, includes)
write_presets(tool_path, generator_output)
33 changes: 22 additions & 11 deletions cppython/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from pathlib import Path
from typing import Any, Optional

from pydantic import BaseModel, Extra, Field
from pydantic import BaseModel, Extra, Field, validator


class Preset(BaseModel):
Expand All @@ -18,36 +18,40 @@ class Preset(BaseModel):
"""

name: str
hidden: Optional[bool] = None
hidden: Optional[bool]
inherits: list[str] = []
displayName: Optional[str] = None
description: Optional[str] = None
displayName: Optional[str]
description: Optional[str]


class ConfigurePreset(Preset):
"""
Partial Configure Preset specification
"""

toolchainFile: Optional[Path] = None
toolchainFile: Optional[str]

@validator("toolchainFile")
def validate_path(cls, v):
return Path(v).as_posix()


class BuildPreset(Preset):
"""
Partial Build Preset specification
"""

configurePreset: Optional[str] = None
inheritConfigureEnvironment: Optional[bool] = None
configurePreset: Optional[str]
inheritConfigureEnvironment: Optional[bool]


class TestPreset(Preset):
"""
Partial Test Preset specification
"""

configurePreset: Optional[str] = None
inheritConfigureEnvironment: Optional[bool] = None
configurePreset: Optional[str]
inheritConfigureEnvironment: Optional[bool]


class CMakeVersion(BaseModel, extra=Extra.forbid):
Expand All @@ -67,12 +71,19 @@ class CMakePresets(BaseModel, extra=Extra.forbid):

version: int = Field(default=4, const=True)
cmakeMinimumRequired: CMakeVersion = CMakeVersion() # TODO: 'version' compatability validation
include: list[Path] = []
vendor: Optional[Any] = None
include: list[str] = []
vendor: Optional[Any]
configurePresets: list[ConfigurePreset] = []
buildPresets: list[BuildPreset] = []
testPresets: list[TestPreset] = []

@validator("include")
def validate_path(cls, v):
output = []
for value in v:
output.append(Path(value).as_posix())
return output


@dataclass
class ProjectConfiguration:
Expand Down
55 changes: 49 additions & 6 deletions cppython/utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,64 @@
import json
from pathlib import Path

from cppython.schema import CMakePresets
from cppython.schema import CMakePresets, ConfigurePreset


def read_preset(path: Path) -> CMakePresets:
def read_preset(name: str, path: Path) -> CMakePresets:
"""
Reading routing
"""

preset_path = path / "CMakePresets.json"
preset_path = path / f"{name}.json"
return CMakePresets.parse_file(path=preset_path)


def write_preset(path: Path, presets: CMakePresets) -> None:
def write_preset(name: str, path: Path, presets: CMakePresets) -> Path:
"""
Writing routine
"""
with open(path / "CMakePresets.json", "w", encoding="utf8") as json_file:
json.dump(presets.dict(), json_file, ensure_ascii=False, indent=2)
file = path / f"{name}.json"

serialized = json.loads(presets.json(exclude_none=True))
with open(file, "w", encoding="utf8") as json_file:
json.dump(serialized, json_file, ensure_ascii=False, indent=2)

return file


def write_presets(tool_path: Path, generator_output: list[tuple[str, Path]]) -> None:
"""
Write the cppython presets
"""

def write_generator_presets(tool_path: Path, generator_name: str, toolchain_path: Path) -> Path:
"""
Write a generator preset.
@returns - The written json file
"""
generator_tool_path = tool_path / generator_name
generator_tool_path.mkdir(parents=True, exist_ok=True)

configure_preset = ConfigurePreset(name=generator_name, hidden=True, toolchainFile=str(toolchain_path))
presets = CMakePresets(configurePresets=[configure_preset])

return write_preset(generator_name, generator_tool_path, presets)

names = []
includes = []

tool_path = tool_path / "cppython"

for generator_name, toolchain in generator_output:

preset_file = write_generator_presets(tool_path, generator_name, toolchain)

relative_file = preset_file.relative_to(tool_path)

names.append(generator_name)
includes.append(str(relative_file))

configure_preset = ConfigurePreset(name="cppython", hidden=True, inherits=names)
presets = CMakePresets(configurePresets=[configure_preset], include=includes)

write_preset("cppython", tool_path, presets)
37 changes: 33 additions & 4 deletions tests/unit/test_utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,50 @@
from pathlib import Path

from cppython.schema import CMakePresets
from cppython.utility import read_preset, write_preset
from cppython.utility import read_preset, write_preset, write_presets


class TestBuilder:
"""
TODO
"""

def test_preset_read_write(self, tmpdir: Path):
def test_preset_read_write(self, tmpdir):
"""
TODO
"""

temporary_directory = Path(tmpdir)

presets = CMakePresets()
write_preset(tmpdir, presets)
output = read_preset(tmpdir)
write_preset("test", temporary_directory, presets)
output = read_preset("test", temporary_directory)

assert presets == output

def test_presets(self, tmpdir):
"""
TODO
"""

temporary_directory = Path(tmpdir)

input_toolchain = temporary_directory / "input.cmake"

with open(input_toolchain, "w", encoding="utf8") as file:
file.write("")

generator_output = [("test", input_toolchain)]
write_presets(temporary_directory, generator_output)

cppython_tool = temporary_directory / "cppython"
assert cppython_tool.exists()

cppython_file = cppython_tool / "cppython.json"
assert cppython_file.exists()

test_tool = cppython_tool / "test"
assert test_tool.exists()

test_file = test_tool / "test.json"
assert test_file.exists()