scripts: introduce CrateSource abstract class
Prepare for making the script able to update .wrap files with versions from Cargo.lock. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Paolo Bonzini committed
Aug 21, 2026 at 09:56 UTC
4c70b2e539439635fad9166d302c6501b706fac7
1 file changed
+38
-11
scripts/get-wraps-from-cargo-registry.py
+38
-11
@@ -29,18 +29,36 @@ def get_name_and_semver(namever: str) -> tuple[str, str]:
29
return parts[0], parts[1]
30
31
32
-class UpdateSubprojects:
33
- cargo_registry: str
34
- top_srcdir: str
35
- dry_run: bool
36
- changes: int = 0
32
+class CrateSource:
33
+ """Class for locating crate versions and pointing wrap files at them.
34
+ Subclasses know where the source of a crate comes from and how to
35
+ rewrite the ``[wrap-file]`` to consume it."""
36
+
37
+ origin: str
38
+
39
+ def find(self, namever: str) -> str | None:
40
+ """Resolve a 'name-semver' prefix to a concrete 'name-version'."""
41
+ raise NotImplementedError
42
+
43
+ def rewrite_source(self, section: configparser.SectionProxy, orig_namever: str, source_namever: str) -> bool:
44
+ """Update the download-related keys of a [wrap-file] section."""
45
+ raise NotImplementedError
46
+
47
+
48
+class CargoRegistry(CrateSource):
49
+ """Locate crates already extracted in a local Cargo registry directory."""
50
38
- def find_installed_crate(self, namever: str) -> str | None:
51
+ origin = "the Cargo registry"
52
+
53
+ def __init__(self, path: str):
54
+ self.path = path
55
+
56
+ def find(self, namever: str) -> str | None:
57
"""Find installed crate matching name and semver prefix"""
58
name, semver = get_name_and_semver(namever)
59
60
# exact version match
43
- path = os.path.join(self.cargo_registry, f"{name}-{semver}")
61
+ path = os.path.join(self.path, f"{name}-{semver}")
62
if os.path.exists(path):
63
return f"{name}-{semver}"
64
@@ -56,6 +74,14 @@ class UpdateSubprojects:
74
del section[key]
75
return True
76
77
+
78
+class UpdateSubprojects:
79
+ cargo_registry: str
80
+ source: CrateSource
81
+ top_srcdir: str
82
+ dry_run: bool
83
+ changes: int = 0
84
+
85
def compare_build_rs(self, orig_dir: str, source_namever: str) -> None:
86
"""Warn if the build.rs in the original directory differs from the registry version."""
87
orig_build_rs = os.path.join(orig_dir, "build.rs")
@@ -102,7 +128,7 @@ class UpdateSubprojects:
128
return
129
130
section["directory"] = source_namever
105
- if self.rewrite_source(section, orig_dir, source_namever):
131
+ if self.source.rewrite_source(section, orig_dir, source_namever):
132
with open(wrap_file, "w") as f:
133
config.write(f)
134
@@ -110,9 +136,9 @@ class UpdateSubprojects:
136
config.write(f)
137
138
if orig_dir == source_namever:
113
- print(f"Installing {orig_dir} from registry.")
139
+ print(f"👉 Installing {orig_dir} from {self.source.origin}.")
140
else:
115
- print(f"Replacing {orig_dir} with {source_namever}.")
141
+ print(f"👉 Replacing {orig_dir} with {source_namever}.")
142
143
subprocess.run(
144
["meson", "subprojects", "download", wrap_name],
@@ -154,6 +180,7 @@ class UpdateSubprojects:
180
self.cargo_registry = args.cargo_registry
181
self.dry_run = args.dry_run
182
self.top_srcdir = os.getcwd()
183
+ self.source = CargoRegistry(args.cargo_registry)
184
185
def main(self) -> None:
186
if not os.path.exists("subprojects"):
@@ -164,7 +191,7 @@ class UpdateSubprojects:
191
for wrap_file in sorted(glob.glob("*-rs.wrap")):
192
namever = wrap_file[:-8] # Remove '-rs.wrap'
193
167
- source_namever = self.find_installed_crate(namever)
194
+ source_namever = self.source.find(namever)
195
if not source_namever:
196
print(f"No installed crate found for {wrap_file}")
197
continue