66from pathlib import Path
77from textwrap import dedent
88
9+ from cpp_dev .common .version import SemanticVersionWithOptionalParts
910from cpp_dev .dependency .provider import DependencyProvider
11+ from cpp_dev .dependency .specifier import DependencySpecifier
12+ from cpp_dev .dependency .types import DependencySpecifierParts , VersionSpecBound , VersionSpecBoundOperand
1013
11- from .config import ProjectConfig , create_project_config
14+ from .config import DependencyType , ProjectConfig , create_project_config , load_project_config , update_dependencies
1215from .lockfile import create_initial_lock_file
1316from .path_composition import compose_include_file , compose_source_file
1417
@@ -29,6 +32,12 @@ def project_dir(self) -> Path:
2932 """Return the path to the project directory."""
3033 return self ._project_dir
3134
35+ def add_package_dependency (self , deps : list [DependencySpecifier ], dep_type : DependencyType ) -> None :
36+ """Add package dependencies to the project for the given type."""
37+ refined_deps = _refine_package_dependencies (self ._dependency_provider , deps )
38+ project_config = load_project_config (self .project_dir )
39+ update_dependencies (project_config , refined_deps , dep_type )
40+
3241
3342def setup_project (
3443 project_config : ProjectConfig ,
@@ -124,3 +133,38 @@ def _create_library_test_file(project_dir: Path, name: str) -> None:
124133def _add_default_cpd_dependencies (project_dir : Path ) -> None :
125134 # add_package_dependency(project_dir, [PackageDependency("llvm"), PackageDependency("gtest")], "cpd") # noqa: ERA001
126135 ...
136+
137+
138+ DEFAULT_REPOSITORY = "official"
139+
140+
141+ def _refine_package_dependencies (
142+ dep_provider : DependencyProvider , deps : list [DependencySpecifier ]
143+ ) -> list [DependencySpecifier ]:
144+ """Refine the package dependencies in case of defaults were chosen.
145+
146+ The refinement includes (in order):
147+ o Default repository "official"
148+ o Latest resolved version in case of "latest"
149+
150+ This step is performed to assure that package dependencies with "latest" do not get an older version
151+ than the latest one at the time of resolution. This is important in case a versions gets removed.
152+ """
153+ updated_deps = []
154+ for dep in deps :
155+ repository = dep .repository if dep .repository is not None else DEFAULT_REPOSITORY
156+ version_spec = dep .version_spec
157+ if dep .version_spec == "latest" :
158+ available_versions = dep_provider .fetch_versions (repository , dep .name )
159+ if len (available_versions ) == 0 :
160+ raise ValueError (f"No available versions for package { dep .name } at repository { dep .repository } ." )
161+ version_spec = [
162+ VersionSpecBound (
163+ operand = VersionSpecBoundOperand .GREATER_THAN_OR_EQUAL ,
164+ version = SemanticVersionWithOptionalParts .from_semantic_version (available_versions [0 ]),
165+ )
166+ ]
167+ updated_deps .append (
168+ DependencySpecifier .from_parts (DependencySpecifierParts (repository , dep .name , version_spec ))
169+ )
170+ return updated_deps
0 commit comments