Skip to content

Commit 74bc54d

Browse files
committed
WIP - Allow users to specify instance versions
We add support for specifying instance versions in `parameters.components`. Commodore falls back to the version/url/path specified for the component when the keys are not provided for component aliases. Note that the actual dependency handling doesn't yet support overriding URL/path for aliases.
1 parent 8942dfd commit 74bc54d

File tree

4 files changed

+76
-16
lines changed

4 files changed

+76
-16
lines changed

commodore/compile.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ def setup_compile_environment(config: Config) -> tuple[dict[str, Any], Iterable[
194194
config.register_component_deprecations(cluster_parameters)
195195
# Raise exception if component version override without URL is present in the
196196
# hierarchy.
197-
verify_version_overrides(cluster_parameters)
197+
verify_version_overrides(cluster_parameters, config.get_component_aliases())
198198

199199
for component in config.get_components().values():
200200
ckey = component.parameters_key

commodore/component/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ def version(self, version: str):
8989
def repo_directory(self) -> P:
9090
return self._dir
9191

92+
@property
93+
def sub_path(self) -> str:
94+
return self._sub_path
95+
9296
@property
9397
def target_directory(self) -> P:
9498
return self.alias_directory(self.name)

commodore/dependency_mgmt/__init__.py

+19-7
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ def fetch_components(cfg: Config):
8888
component_names, component_aliases = _discover_components(cfg)
8989
click.secho("Registering component aliases...", bold=True)
9090
cfg.register_component_aliases(component_aliases)
91-
cspecs = _read_components(cfg, component_names)
91+
cspecs = _read_components(cfg, component_aliases)
9292
click.secho("Fetching components...", bold=True)
9393
for cn in component_names:
9494
cspec = cspecs[cn]
@@ -114,8 +114,14 @@ def fetch_components(cfg: Config):
114114
continue
115115

116116
c = components[component]
117-
# TODO: Set alias version instead of component version
118-
c.register_alias(alias, c.version or "")
117+
aspec = cspecs[alias]
118+
if aspec.url != c.repo_url or aspec.path != c._sub_path:
119+
# TODO: Figure out how we'll handle URL/subpath overrides
120+
raise NotImplementedError(
121+
"URL/path override for component alias not supported"
122+
)
123+
print(alias, aspec)
124+
c.register_alias(alias, aspec.version)
119125
c.checkout_alias(alias)
120126

121127
create_alias_symlinks(cfg, c, alias)
@@ -131,7 +137,7 @@ def register_components(cfg: Config):
131137
click.secho("Discovering included components...", bold=True)
132138
try:
133139
components, component_aliases = _discover_components(cfg)
134-
cspecs = _read_components(cfg, components)
140+
cspecs = _read_components(cfg, component_aliases)
135141
except KeyError as e:
136142
raise click.ClickException(f"While discovering components: {e}")
137143
click.secho("Registering components and aliases...", bold=True)
@@ -174,8 +180,10 @@ def register_components(cfg: Config):
174180
continue
175181

176182
c = registered_components[cn]
177-
# TODO: Set alias version
178-
c.register_alias(alias, c.version)
183+
aspec = cspecs[alias]
184+
if aspec.url != c.repo_url or aspec.path != c.sub_path:
185+
raise NotImplementedError("Changing alias sub path / URL NYI")
186+
c.register_alias(alias, aspec.version)
179187
if not component_dir(cfg.work_dir, alias).is_dir():
180188
raise click.ClickException(f"Missing alias checkout for '{alias} as {cn}'")
181189

@@ -238,9 +246,13 @@ def register_packages(cfg: Config):
238246
create_package_symlink(cfg, p, pkg)
239247

240248

241-
def verify_version_overrides(cluster_parameters):
249+
def verify_version_overrides(cluster_parameters, component_aliases: dict[str, str]):
242250
errors = []
251+
aliases = set(component_aliases.keys()) - set(component_aliases.values())
243252
for cname, cspec in cluster_parameters["components"].items():
253+
if cname in aliases:
254+
# We don't require an url in component alias version configs
255+
continue
244256
if "url" not in cspec:
245257
errors.append(f"component '{cname}'")
246258

commodore/dependency_mgmt/version_parsing.py

+52-8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from collections.abc import Iterable
44
from dataclasses import dataclass
5+
from typing import Optional
56

67
from enum import Enum
78

@@ -33,18 +34,31 @@ class DependencySpec:
3334
path: str
3435

3536
@classmethod
36-
def parse(cls, info: dict[str, str]) -> DependencySpec:
37-
if "url" not in info:
37+
def parse(
38+
cls,
39+
info: dict[str, str],
40+
base_config: Optional[DependencySpec] = None,
41+
) -> DependencySpec:
42+
if "url" not in info and not base_config:
3843
raise DependencyParseError("url")
3944

40-
if "version" not in info:
45+
if "version" not in info and not base_config:
4146
raise DependencyParseError("version")
4247

4348
path = info.get("path", "")
4449
if path.startswith("/"):
4550
path = path[1:]
4651

47-
return DependencySpec(info["url"], info["version"], path)
52+
if base_config:
53+
url = info.get("url", base_config.url)
54+
version = info.get("version", base_config.version)
55+
if path not in info:
56+
path = base_config.path
57+
else:
58+
url = info["url"]
59+
version = info["version"]
60+
61+
return DependencySpec(url, version, path)
4862

4963

5064
def _read_versions(
@@ -53,6 +67,8 @@ def _read_versions(
5367
dependency_names: Iterable[str],
5468
require_key: bool = True,
5569
ignore_class_notfound: bool = False,
70+
aliases: dict[str, str] = {},
71+
fallback: dict[str, DependencySpec] = {},
5672
) -> dict[str, DependencySpec]:
5773
deps_key = dependency_type.value
5874
deptype_str = dependency_type.name.lower()
@@ -71,15 +87,26 @@ def _read_versions(
7187
# just set deps to the empty dict.
7288
deps = {}
7389

90+
if aliases:
91+
all_dep_keys = set(aliases.keys())
92+
else:
93+
all_dep_keys = deps.keys()
7494
for depname in dependency_names:
75-
if depname not in deps:
95+
if depname not in all_dep_keys:
7696
raise click.ClickException(
7797
f"Unknown {deptype_str} '{depname}'."
7898
+ f" Please add it to 'parameters.{deps_key}'"
7999
)
80100

81101
try:
82-
dep = DependencySpec.parse(deps[depname])
102+
basename_for_dep = aliases.get(depname, depname)
103+
print(depname, basename_for_dep)
104+
print(deps.get(depname, {}))
105+
print(fallback.get(basename_for_dep))
106+
dep = DependencySpec.parse(
107+
deps.get(depname, {}),
108+
base_config=fallback.get(basename_for_dep),
109+
)
83110
except DependencyParseError as e:
84111
raise click.ClickException(
85112
f"{deptype_cap} '{depname}' is missing field '{e.field}'"
@@ -96,9 +123,26 @@ def _read_versions(
96123

97124

98125
def _read_components(
99-
cfg: Config, component_names: Iterable[str]
126+
cfg: Config, component_aliases: dict[str, str]
100127
) -> dict[str, DependencySpec]:
101-
return _read_versions(cfg, DepType.COMPONENT, component_names)
128+
component_names = set(component_aliases.values())
129+
alias_names = set(component_aliases.keys()) - component_names
130+
131+
component_versions = _read_versions(cfg, DepType.COMPONENT, component_names)
132+
alias_versions = _read_versions(
133+
cfg,
134+
DepType.COMPONENT,
135+
alias_names,
136+
aliases=component_aliases,
137+
fallback=component_versions,
138+
)
139+
140+
for alias, aspec in alias_versions.items():
141+
if alias in component_versions:
142+
raise ValueError("alias name already in component_versions?")
143+
component_versions[alias] = aspec
144+
145+
return component_versions
102146

103147

104148
def _read_packages(

0 commit comments

Comments
 (0)