Skip to content

Commit 0bcb308

Browse files
committed
Conan Dep Schema + Conversion
1 parent d35db24 commit 0bcb308

File tree

4 files changed

+117
-2
lines changed

4 files changed

+117
-2
lines changed

cppython/plugins/conan/builder.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
"""Construction of Conan data"""
2+
3+
from pathlib import Path
4+
from string import Template
5+
6+
from pydantic import DirectoryPath
7+
8+
from cppython.plugins.conan.schema import ConanDependency
9+
10+
11+
class Builder:
12+
"""Aids in building the information needed for the Conan plugin"""
13+
14+
def __init__(self) -> None:
15+
"""Initialize the builder"""
16+
self._filename = 'conanfile.py'
17+
18+
@staticmethod
19+
def _create_conanfile(conan_file: Path, dependencies: list[ConanDependency]) -> None:
20+
"""Creates a conanfile.py file with the necessary content."""
21+
template_string = """
22+
from conan import ConanFile
23+
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
24+
25+
class MyProject(ConanFile):
26+
name = myproject
27+
version = "1.0"
28+
settings = "os", "compiler", "build_type", "arch"
29+
requires = "zlib/1.2.13"
30+
generators = "CMakeDeps"
31+
32+
def layout(self):
33+
cmake_layout(self)
34+
35+
def generate(self):
36+
tc = CMakeToolchain(self)
37+
tc.generate()
38+
39+
def build(self):
40+
cmake = CMake(self)
41+
cmake.configure()
42+
cmake.build()"""
43+
44+
template = Template(template_string)
45+
46+
values = {
47+
'dependencies': [dependency.requires() for dependency in dependencies],
48+
}
49+
50+
result = template.substitute(values)
51+
52+
with open(conan_file, 'w', encoding='utf-8') as file:
53+
file.write(result)
54+
55+
def generate_conanfile(self, directory: DirectoryPath, dependencies: list[ConanDependency]) -> None:
56+
"""Generate a conanfile.py file for the project."""
57+
conan_file = directory / self._filename
58+
59+
# If the file exists then we need to inject our information into it
60+
if conan_file.exists():
61+
with open(conan_file, encoding='utf-8') as file:
62+
file_contents = file.read()
63+
64+
else:
65+
directory.mkdir(parents=True, exist_ok=True)
66+
self._create_conanfile(conan_file, dependencies)

cppython/plugins/conan/plugin.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
from cppython.core.schema import CorePluginData, Information, SyncData
1616
from cppython.plugins.cmake.plugin import CMakeGenerator
1717
from cppython.plugins.cmake.schema import CMakeSyncData
18-
from cppython.plugins.conan.resolution import resolve_conan_data
18+
from cppython.plugins.conan.builder import Builder
19+
from cppython.plugins.conan.resolution import resolve_conan_data, resolve_conan_dependency
1920
from cppython.plugins.conan.schema import ConanData
2021
from cppython.utility.exception import NotSupportedError
2122
from cppython.utility.utility import TypeName
@@ -34,6 +35,8 @@ def __init__(
3435
self.core_data: CorePluginData = core_data
3536
self.data: ConanData = resolve_conan_data(configuration_data, core_data)
3637

38+
self.builder = Builder()
39+
3740
@staticmethod
3841
def _download_file(url: str, file: Path) -> None:
3942
"""Replaces the given file with the contents of the url"""
@@ -66,9 +69,15 @@ def information() -> Information:
6669

6770
def install(self) -> None:
6871
"""Installs the provider"""
72+
resolved_dependencies = [resolve_conan_dependency(req) for req in self.core_data.cppython_data.dependencies]
73+
74+
self.builder.generate_conanfile(self.core_data.project_data.project_root, resolved_dependencies)
6975

7076
def update(self) -> None:
7177
"""Updates the provider"""
78+
resolved_dependencies = [resolve_conan_dependency(req) for req in self.core_data.cppython_data.dependencies]
79+
80+
self.builder.generate_conanfile(self.core_data.project_data.project_root, resolved_dependencies)
7281

7382
@staticmethod
7483
def supported_sync_type(sync_type: type[SyncData]) -> bool:

cppython/plugins/conan/resolution.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,33 @@
22

33
from typing import Any
44

5+
from packaging.requirements import Requirement
6+
7+
from cppython.core.exception import ConfigException
58
from cppython.core.schema import CorePluginData
6-
from cppython.plugins.conan.schema import ConanData
9+
from cppython.plugins.conan.schema import ConanData, ConanDependency
10+
11+
12+
def resolve_conan_dependency(requirement: Requirement) -> ConanDependency:
13+
"""Resolves a Conan dependency from a requirement"""
14+
specifiers = requirement.specifier
15+
16+
# If the length of specifiers is greater than one, raise a configuration error
17+
if len(specifiers) > 1:
18+
raise ConfigException('Multiple specifiers are not supported. Please provide a single specifier.', [])
19+
20+
# Extract the version from the single specifier
21+
min_version = None
22+
if len(specifiers) == 1:
23+
specifier = next(iter(specifiers))
24+
if specifier.operator != '>=':
25+
raise ConfigException(f"Unsupported specifier '{specifier.operator}'. Only '>=' is supported.", [])
26+
min_version = specifier.version
27+
28+
return ConanDependency(
29+
name=requirement.name,
30+
version_ge=min_version,
31+
)
732

833

934
def resolve_conan_data(data: dict[str, Any], core_data: CorePluginData) -> ConanData:

cppython/plugins/conan/schema.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,21 @@
88
from cppython.core.schema import CPPythonModel
99

1010

11+
class ConanDependency(CPPythonModel):
12+
"""Dependency information"""
13+
14+
name: str
15+
version_ge: str | None = None
16+
include_prerelease: bool | None = None
17+
18+
def requires(self) -> str:
19+
"""Generate the requires attribute for Conan"""
20+
# TODO: Implement lower and upper bounds per conan documentation
21+
if self.version_ge:
22+
return f'{self.name}/[>={self.version_ge}]'
23+
return self.name
24+
25+
1126
class ConanData(CPPythonModel):
1227
"""Resolved conan data"""
1328

0 commit comments

Comments
 (0)