Skip to content

Commit 5ea2697

Browse files
committed
fix: inject version for path dependencies in workspace virtual manifests
1 parent 54c2015 commit 5ea2697

File tree

5 files changed

+96
-48
lines changed

5 files changed

+96
-48
lines changed

.changelog/_unreleased.toml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[[entries]]
2+
id = "1fddba58-dd61-4906-baca-f1a41e3b534f"
3+
type = "fix"
4+
description = "inject version for path dependencies in workspace virtual manifests"
5+

kraken-build/src/kraken/std/cargo/manifest.py

+61-39
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@
66
import logging
77
import os
88
import subprocess
9-
from dataclasses import dataclass, fields
9+
from dataclasses import dataclass
1010
from enum import Enum
1111
from pathlib import Path
1212
from typing import Any
1313

1414
import tomli
1515
import tomli_w
16+
from deprecated import deprecated
1617

1718
logger = logging.getLogger(__name__)
1819

@@ -21,15 +22,20 @@
2122
class Bin:
2223
name: str
2324
path: str
24-
_remainder: dict[str, Any]
25+
_raw: dict[str, Any]
2526

2627
def to_json(self) -> dict[str, Any]:
27-
return {"name": self.name, "path": self.path, **self._remainder}
28+
return self._raw
2829

2930
@staticmethod
3031
def from_json(data: dict[str, Any]) -> Bin:
3132
data = dict(data)
32-
return Bin(data.pop("name"), data.pop("path"), _remainder=data)
33+
return Bin(data.get("name", ""), data.get("path", ""), _raw=data)
34+
35+
@property
36+
@deprecated(reason="use Bin._raw instead", version="0.37.0")
37+
def _remainder(self) -> dict[str, Any]:
38+
return self._raw
3339

3440

3541
# TODO: Differentiate between lib kinds?
@@ -63,7 +69,7 @@ class WorkspaceMember:
6369
@dataclass
6470
class CargoMetadata:
6571
_path: Path
66-
_data: dict[str, Any]
72+
_raw: dict[str, Any]
6773

6874
workspaceMembers: list[WorkspaceMember]
6975
artifacts: list[Artifact]
@@ -144,70 +150,81 @@ def of(cls, path: Path, data: dict[str, Any]) -> CargoMetadata:
144150

145151
return cls(path, data, workspace_members, artifacts, Path(data["target_directory"]))
146152

153+
@property
154+
@deprecated(reason="use CargoMetadata._raw instead", version="0.37.0")
155+
def _data(self) -> dict[str, Any]:
156+
return self._raw
157+
147158

148159
@dataclass
149160
class Package:
150161
name: str
151162
version: str | None
152163
edition: str | None
153-
unhandled: dict[str, Any] | None
164+
_raw: dict[str, Any]
154165

155166
@classmethod
156-
def from_json(cls, json: dict[str, str]) -> Package:
157-
cloned = dict(json)
158-
name = cloned.pop("name")
159-
version = cloned.pop("version", None)
160-
edition = cloned.pop("edition", None)
161-
return Package(name, version, edition, cloned)
167+
def from_json(cls, json: dict[str, Any]) -> Package:
168+
_raw = dict(json)
169+
name = _raw.get("name", "")
170+
version = _raw.get("version", None)
171+
edition = _raw.get("edition", None)
172+
return Package(name, version, edition, _raw)
162173

163-
def to_json(self) -> dict[str, str]:
164-
values = {f.name: getattr(self, f.name) for f in fields(self) if f.name != "unhandled"}
165-
if self.unhandled is not None:
166-
values.update({k: v for k, v in self.unhandled.items() if v is not None})
167-
return {k: v for k, v in values.items() if v is not None}
174+
def to_json(self) -> dict[str, Any]:
175+
return {k: v for k, v in self._raw.items() if v is not None}
176+
177+
@property
178+
@deprecated(reason="use Package._raw instead", version="0.37.0")
179+
def unhandled(self) -> dict[str, Any]:
180+
return self._raw
168181

169182

170183
@dataclass
171184
class WorkspacePackage:
172185
version: str
173-
unhandled: dict[str, Any] | None
186+
_raw: dict[str, Any]
174187

175188
@classmethod
176-
def from_json(cls, json: dict[str, str]) -> WorkspacePackage:
189+
def from_json(cls, json: dict[str, Any]) -> WorkspacePackage:
177190
cloned = dict(json)
178-
version = cloned.pop("version")
191+
version = cloned.get("version", "")
179192
return WorkspacePackage(version, cloned)
180193

181-
def to_json(self) -> dict[str, str]:
182-
values = {f.name: getattr(self, f.name) for f in fields(self) if f.name != "unhandled"}
183-
if self.unhandled is not None:
184-
values.update({k: v for k, v in self.unhandled.items() if v is not None})
185-
return {k: v for k, v in values.items() if v is not None}
194+
def to_json(self) -> dict[str, Any]:
195+
return {k: v for k, v in self._raw.items() if v is not None}
196+
197+
@property
198+
@deprecated(reason="use WorkspacePackage._raw instead", version="0.37.0")
199+
def unhandled(self) -> dict[str, Any]:
200+
return self._raw
186201

187202

188203
@dataclass
189204
class Workspace:
190205
package: WorkspacePackage | None
191206
members: list[str] | None
192-
unhandled: dict[str, Any] | None
207+
dependencies: Dependencies | None
208+
build_dependencies: Dependencies | None
209+
_raw: dict[str, Any]
193210

194211
@classmethod
195212
def from_json(cls, json: dict[str, Any]) -> Workspace:
196-
cloned = dict(json)
197213
return Workspace(
198-
WorkspacePackage.from_json(cloned.pop("package")) if "package" in cloned else None,
199-
cloned.pop("members") if "members" in cloned else None,
200-
cloned,
214+
WorkspacePackage.from_json(json["package"]) if "package" in json else None,
215+
json.get("members"),
216+
Dependencies.from_json(json["dependencies"]) if "dependencies" in json else None,
217+
Dependencies.from_json(json["build-dependencies"]) if "build-dependencies" in json else None,
218+
json,
201219
)
202220

203221
def to_json(self) -> dict[str, Any]:
204-
values = {
205-
"package": self.package.to_json() if self.package else None,
206-
"members": self.members if self.members else None,
207-
}
208-
if self.unhandled is not None:
209-
values.update({k: v for k, v in self.unhandled.items() if v is not None})
210-
return {k: v for k, v in values.items() if v is not None}
222+
return {k: v for k, v in self._raw.items() if v is not None}
223+
224+
@property
225+
@deprecated(reason="use Workspace._raw instead", version="0.37.0")
226+
def unhandled(self) -> dict[str, Any]:
227+
return self._raw
211228

212229

213230
@dataclass
@@ -226,7 +243,7 @@ def to_json(self) -> dict[str, Any]:
226243
@dataclass
227244
class CargoManifest:
228245
_path: Path
229-
_data: dict[str, Any]
246+
_raw: dict[str, Any]
230247

231248
package: Package | None
232249
workspace: Workspace | None
@@ -255,7 +272,7 @@ def of(cls, path: Path, data: dict[str, Any]) -> CargoManifest:
255272
)
256273

257274
def to_json(self) -> dict[str, Any]:
258-
result = self._data.copy()
275+
result = self._raw.copy()
259276
if self.bin:
260277
result["bin"] = [x.to_json() for x in self.bin]
261278
else:
@@ -277,3 +294,8 @@ def save(self, path: Path | None = None) -> None:
277294
path = path or self._path
278295
with path.open("wb") as fp:
279296
tomli_w.dump(self.to_json(), fp)
297+
298+
@property
299+
@deprecated(reason="use CargoManifest._raw instead", version="0.37.0")
300+
def _data(self) -> dict[str, Any]:
301+
return self._raw

kraken-build/src/kraken/std/cargo/tasks/cargo_publish_task.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class CargoPublishTask(CargoBuildTask):
1919
#: Path to the Cargo configuration file (defaults to `.cargo/config.toml`).
2020
cargo_config_file: Property[Path] = Property.default(".cargo/config.toml")
2121

22-
#: Name of the package to publish (only requried for publishing packages from workspace)
22+
#: Name of the package to publish (only required for publishing packages from workspace)
2323
package_name: Property[str | None] = Property.default(None)
2424

2525
#: The registry to publish the package to.
@@ -85,6 +85,17 @@ def _get_updated_cargo_toml(self, version: str) -> str:
8585
self._push_version_to_path_deps(fixed_version_string, manifest.dependencies.data, registry.alias)
8686
if manifest.build_dependencies:
8787
self._push_version_to_path_deps(fixed_version_string, manifest.build_dependencies.data, registry.alias)
88+
89+
if manifest.workspace:
90+
if manifest.workspace.dependencies:
91+
self._push_version_to_path_deps(
92+
fixed_version_string, manifest.workspace.dependencies.data, registry.alias
93+
)
94+
if manifest.workspace.build_dependencies:
95+
self._push_version_to_path_deps(
96+
fixed_version_string, manifest.workspace.build_dependencies.data, registry.alias
97+
)
98+
8899
return manifest.to_toml_string()
89100

90101
def _push_version_to_path_deps(
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
11
[workspace]
22
members = ["crates/*"]
3+
4+
[workspace.dependencies]
5+
subcrate.path = "./subcrate"
6+
7+
[workspace.build-dependencies]
8+
other_subcrate.path = "./other_subcrate"

kraken-build/tests/kraken_std/test_cargo_manifest.py

+12-8
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ def test_cargo_manifest_handles_unknown_fields_correctly() -> None:
2525
assert manifest.package.version == "0.1.2"
2626
assert manifest.package.edition == "2021"
2727

28-
assert manifest.package.unhandled is not None
29-
assert len(manifest.package.unhandled) == 2
30-
assert len(manifest.package.unhandled["include"]) == 2
31-
assert manifest.package.unhandled["authors"] == ["author1", "author2"]
28+
assert manifest.package._raw is not None
29+
assert len(manifest.package._raw) == 5
30+
assert len(manifest.package._raw["include"]) == 2
31+
assert manifest.package._raw["authors"] == ["author1", "author2"]
3232

3333

3434
def test_cargo_manifest_writes_json_correctly() -> None:
@@ -61,13 +61,13 @@ def test_cargo_manifest_complex_file() -> None:
6161

6262
assert manifest is not None
6363
assert manifest.package is not None
64-
assert manifest.package.unhandled is not None
65-
assert len(manifest.package.unhandled) > 0
64+
assert manifest.package._raw is not None
65+
assert len(manifest.package._raw) > 0
6666
assert manifest.package.name == "rand"
6767
assert manifest.package.edition == "2018"
6868
assert manifest.package.version == "0.8.5"
69-
assert manifest.package.unhandled["include"] == ["src/", "LICENSE-*", "README.md", "CHANGELOG.md", "COPYRIGHT"]
70-
assert manifest.package.unhandled["autobenches"]
69+
assert manifest.package._raw["include"] == ["src/", "LICENSE-*", "README.md", "CHANGELOG.md", "COPYRIGHT"]
70+
assert manifest.package._raw["autobenches"]
7171

7272

7373
def test_cargo_manifest_workspace_file() -> None:
@@ -83,6 +83,10 @@ def test_cargo_manifest_workspace_file() -> None:
8383
assert manifest.workspace is not None
8484
assert manifest.workspace.members is not None
8585
assert manifest.workspace.members == ["crates/*"]
86+
assert manifest.workspace.dependencies is not None
87+
assert manifest.workspace.dependencies.data == {"subcrate": {"path": "./subcrate"}}
88+
assert manifest.workspace.build_dependencies is not None
89+
assert manifest.workspace.build_dependencies.data == {"other_subcrate": {"path": "./other_subcrate"}}
8690

8791

8892
def test_cargo_manifest_throws_when_no_workspace_or_package() -> None:

0 commit comments

Comments
 (0)