@samitouri / QOSamiQemu / commits / 4c70b2e539

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