Coverage for rust2rpm/generator.py: 75%
388 statements
« prev ^ index » next coverage.py v7.6.4, created at 2024-10-27 15:21 +0100
« prev ^ index » next coverage.py v7.6.4, created at 2024-10-27 15:21 +0100
1"""
2Functionality for rendering the spec file template.
3"""
5import time
6from typing import Optional
8from cargo2rpm.metadata import FeatureFlags, Metadata, Package
9from cargo2rpm.semver import Version
10from cargo2rpm import rpm
11import jinja2
13from rust2rpm import __version__, log
14from rust2rpm.conf import TomlConf
15from rust2rpm.licensing import translate_license
16from rust2rpm.metadata import package_uses_rust_1_60_feature_syntax, get_required_features_for_binaries
19RUST_PACKAGING_DEPS: dict[int, str] = {
20 0: "rust-toolset",
21 21: "rust-packaging >= 21",
22 23: "rust-packaging >= 23",
23 24: "cargo-rpm-macros >= 24",
24 25: "cargo-rpm-macros >= 25",
25 26: "cargo-rpm-macros >= 26",
26}
29RUST_PACKAGING_TARGET_MIN: dict[str, int] = {
30 "fedora": 24,
31 "mageia": 21,
32 "opensuse": 21,
33 "plain": 21,
34}
37def license_is_composite(license: str) -> bool:
38 return (
39 " " in license
40 and " WITH " not in license
41 and "(" not in license
42 and ")" not in license
43 or "(" in license
44 or ")" in license
45 )
48def min_rust_packaging_dep(
49 package: Package,
50 target: str,
51 is_bin: bool,
52 is_cdylib: bool,
53 vendor_tarball: Optional[str],
54 cargo_install_lib: bool,
55 cargo_install_bin: bool,
56) -> int:
57 if (not cargo_install_lib) or (not cargo_install_bin):
58 min_dep = 26
59 elif vendor_tarball:
60 min_dep = 25
61 elif package_uses_rust_1_60_feature_syntax(package.features): 61 ↛ 62line 61 didn't jump to line 62 because the condition on line 61 was never true
62 min_dep = 24
63 elif is_bin or is_cdylib:
64 min_dep = 23
65 else:
66 min_dep = 21
68 return max((min_dep, RUST_PACKAGING_TARGET_MIN[target]))
71def renames_from_bin_name_map(bin_name_map: Optional[dict[str, str]]) -> list[str]:
72 if bin_name_map is None: 72 ↛ 75line 72 didn't jump to line 75 because the condition on line 72 was always true
73 return []
75 return [
76 f"mv %{ buildroot} /%{ _bindir} /{old} %{ buildroot} /%{ _bindir} /{new}" for old, new in bin_name_map.items()
77 ]
80def cargo_args_from_flags(
81 feature_flags: FeatureFlags, required_features: set[str], enabled_by_default: set[str]
82) -> str:
83 if feature_flags.all_features:
84 cargo_args = " -a"
86 elif required_features:
87 # remove required features that are already part of the enabled feature set
88 for f in enabled_by_default:
89 if f in required_features:
90 required_features.remove(f)
92 # merge, de-duplicate, and re-sort lists of enabled features
93 if features_enable := feature_flags.features:
94 enabled_features = sorted(set.union(set(required_features), set(features_enable)))
95 else:
96 enabled_features = sorted(required_features)
98 if feature_flags.no_default_features:
99 cargo_args_list = ["-n"]
100 else:
101 cargo_args_list = []
103 if len(enabled_features) > 0:
104 cargo_args_list.append(f"-f {','.join(enabled_features)}")
106 if cargo_args_list:
107 cargo_args = " " + " ".join(cargo_args_list)
108 else:
109 cargo_args = ""
111 elif feature_flags.features:
112 # list of features is already sorted when parsing the configuration file
113 if feature_flags.no_default_features:
114 cargo_args_list = ["-n"]
115 else:
116 cargo_args_list = []
118 cargo_args_list.append(f"-f {','.join(feature_flags.features)}")
119 cargo_args = " " + " ".join(cargo_args_list)
121 elif feature_flags.no_default_features:
122 cargo_args = " -n"
124 else:
125 cargo_args = ""
127 return cargo_args
130def spec_file_template(filename: str):
131 env = jinja2.Environment(
132 loader=jinja2.ChoiceLoader([jinja2.FileSystemLoader(["/"]), jinja2.PackageLoader("rust2rpm", "templates")]),
133 extensions=["jinja2.ext.do"],
134 trim_blocks=True,
135 lstrip_blocks=True,
136 )
138 return env.get_template(filename)
141def template_args_fedora(date: Optional[time.struct_time], packager: Optional[str], rpmautospec: bool) -> dict:
142 kwargs: dict[str, str | bool] = dict()
144 kwargs["include_build_requires"] = False
145 kwargs["include_provides"] = False
146 kwargs["include_requires"] = False
148 if rpmautospec: 148 ↛ 151line 148 didn't jump to line 151 because the condition on line 148 was always true
149 kwargs["rpm_release"] = "%autorelease"
150 else:
151 kwargs["rpm_release"] = "1%{?dist}"
153 rpm_changelog_date_format = "%a %b %d %Y"
154 if date: 154 ↛ 157line 154 didn't jump to line 157 because the condition on line 154 was always true
155 kwargs["rpm_changelog_date"] = time.strftime(rpm_changelog_date_format, date)
156 else:
157 kwargs["rpm_changelog_date"] = time.strftime(rpm_changelog_date_format)
159 kwargs["rpm_changelog_packager"] = packager or "rust2rpm <nobody@fedoraproject.org>"
161 return kwargs
164def template_args_epel8(date: Optional[time.struct_time], packager: Optional[str], rpmautospec: bool) -> dict:
165 kwargs: dict[str, str | bool] = dict()
167 kwargs["include_build_requires"] = False
169 if rpmautospec: 169 ↛ 172line 169 didn't jump to line 172 because the condition on line 169 was always true
170 kwargs["rpm_release"] = "%autorelease"
171 else:
172 kwargs["rpm_release"] = "1%{?dist}"
174 rpm_changelog_date_format = "%a %b %d %Y"
175 if date: 175 ↛ 178line 175 didn't jump to line 178 because the condition on line 175 was always true
176 kwargs["rpm_changelog_date"] = time.strftime(rpm_changelog_date_format, date)
177 else:
178 kwargs["rpm_changelog_date"] = time.strftime(rpm_changelog_date_format)
180 kwargs["rpm_changelog_packager"] = packager or "rust2rpm <nobody@fedoraproject.org>"
182 return kwargs
185def template_args_mageia(date: Optional[time.struct_time], packager: Optional[str]) -> dict:
186 kwargs: dict[str, str | bool] = dict()
188 kwargs["include_build_requires"] = True
189 kwargs["include_provides"] = False
190 kwargs["include_requires"] = False
192 kwargs["rpm_release"] = "%mkrel 1"
193 kwargs["rpm_group"] = "Development/Rust"
195 rpm_changelog_date_format = "%a %b %d %Y"
196 if date: 196 ↛ 199line 196 didn't jump to line 199 because the condition on line 196 was always true
197 kwargs["rpm_changelog_date"] = time.strftime(rpm_changelog_date_format, date)
198 else:
199 kwargs["rpm_changelog_date"] = time.strftime(rpm_changelog_date_format)
201 kwargs["rpm_changelog_packager"] = packager or "rust2rpm <nobody@mageia.org>"
203 return kwargs
206def template_args_opensuse(date: Optional[time.struct_time], packager: Optional[str]) -> dict:
207 kwargs: dict[str, str | bool] = dict()
209 kwargs["include_build_requires"] = True
210 kwargs["include_provides"] = False
211 kwargs["include_requires"] = False
213 kwargs["spec_copyright_year"] = time.strftime("%Y")
214 kwargs["rpm_release"] = "0"
215 kwargs["rpm_group"] = "Development/Libraries/Rust"
217 rpm_changelog_date_format = "%a %b %d %T %Z %Y"
218 if date: 218 ↛ 221line 218 didn't jump to line 221 because the condition on line 218 was always true
219 kwargs["rpm_changelog_date"] = time.strftime(rpm_changelog_date_format, date)
220 else:
221 kwargs["rpm_changelog_date"] = time.strftime(rpm_changelog_date_format)
223 kwargs["rpm_changelog_packager"] = packager or "rust2rpm <opensuse-packaging@opensuse.org>"
225 return kwargs
228def template_args_plain(date: Optional[time.struct_time], packager: Optional[str]) -> dict:
229 kwargs: dict[str, str | bool] = dict()
231 kwargs["include_build_requires"] = True
232 kwargs["include_provides"] = True
233 kwargs["include_requires"] = True
235 kwargs["rpm_release"] = "1%{?dist}"
237 rpm_changelog_date_format = "%a %b %d %Y"
238 if date: 238 ↛ 241line 238 didn't jump to line 241 because the condition on line 238 was always true
239 kwargs["rpm_changelog_date"] = time.strftime(rpm_changelog_date_format, date)
240 else:
241 kwargs["rpm_changelog_date"] = time.strftime(rpm_changelog_date_format)
243 kwargs["rpm_changelog_packager"] = packager or "rust2rpm <packager@example.com>"
245 return kwargs
248def spec_render_crate(
249 *,
250 metadata: Metadata,
251 upstream_version: str,
252 target: str,
253 legacy: bool,
254 rpm_name: str,
255 compat: bool,
256 patch_file_automatic: Optional[str],
257 patch_file_manual: Optional[str],
258 license_files: list[str],
259 doc_files: list[str],
260 vendor_tarball: Optional[str],
261 tomlconf: TomlConf,
262 relative_license_paths: bool,
263 rpmautospec: bool,
264 auto_changelog_entry: bool,
265 date: Optional[time.struct_time] = None,
266 packager: Optional[str],
267) -> str:
268 template = spec_file_template("crate.spec")
270 # enforce consistent ordering of binaries
271 if bin_renames := tomlconf.package_bin_renames: 271 ↛ 272line 271 didn't jump to line 272 because the condition on line 271 was never true
272 binaries = []
273 for old_name in metadata.get_binaries():
274 if new_name := bin_renames.get(old_name):
275 binaries.append(new_name)
276 else:
277 binaries.append(old_name)
278 else:
279 binaries = [*metadata.get_binaries()]
280 binaries.sort()
282 is_bin = metadata.is_bin()
283 is_lib = metadata.is_lib()
284 is_cdylib = metadata.is_cdylib()
286 cargo_install_lib = (tomlconf.package_cargo_install_lib is not False) and (vendor_tarball is None)
287 cargo_install_bin = (tomlconf.package_cargo_install_bin is not False) and (not compat if is_bin else True)
289 if tomlconf.package_bin_package_name is None: 289 ↛ 292line 289 didn't jump to line 292 because the condition on line 289 was always true
290 bin_name = "%{crate}"
291 else:
292 bin_name = tomlconf.package_bin_package_name
294 package = metadata.packages[0]
296 if rpm_summary := tomlconf.package_summary: 296 ↛ 297line 296 didn't jump to line 297 because the condition on line 296 was never true
297 if len(rpm_summary) > 80:
298 log.warn("The package Summary specified in rust2rpm.toml is too long (>80 characters).")
299 elif rpm_summary := package.get_summary(): 299 ↛ 307line 299 didn't jump to line 307 because the condition on line 299 was always true
300 if len(rpm_summary) > 80:
301 log.warn(
302 "Heuristics for generating a short Summary failed. "
303 "The generated Summary string is too long (>80 characters) and needs to be shortened manually. "
304 "This setting can be persisted with a 'package.summary' setting in 'rust2rpm.toml'."
305 )
306 else:
307 rpm_summary = "# FIXME"
309 rpm_description = tomlconf.package_description or package.get_description()
311 # enforce consistent ordering of feature subpackages
312 features: list[Optional[str]] = list(sorted(package.get_feature_names()))
313 if "default" in features:
314 features.remove("default")
315 features.insert(0, None)
316 features.insert(1, "default")
318 generator_version = __version__.split(".")[0]
319 feature_flags = tomlconf.to_feature_flags()
321 try:
322 buildrequires_with_dev = rpm.buildrequires(package, feature_flags, True)
323 buildrequires_without_dev = rpm.buildrequires(package, feature_flags, False)
325 buildrequires = buildrequires_without_dev
326 test_requires = set.difference(buildrequires_with_dev, buildrequires_without_dev)
327 except ValueError:
328 # some ancient Rust crates have metadata that might be considered "invalid" by today's standards,
329 # causing generation of BuildRequires to fail
330 raise
332 rpm_buildrequires = list(sorted(buildrequires))
333 rpm_test_requires = list(sorted(test_requires))
334 rpm_requires = {feature: list(sorted(rpm.requires(package, feature))) for feature in features}
335 rpm_provides = {feature: rpm.provides(package, feature) for feature in features}
337 conf_lib_requires = dict()
338 for feature in features:
339 if feature is None:
340 conf_key = "lib"
341 conf_lib_requires[conf_key] = tomlconf.requires_lib or list()
342 else:
343 conf_key = f"lib+{feature}"
344 if requires_features := tomlconf.requires_features:
345 conf_lib_requires[conf_key] = requires_features.get(feature) or list()
346 else:
347 conf_lib_requires[conf_key] = list()
349 if features_hide := tomlconf.features_hide:
350 for feature in features_hide:
351 features.remove(feature)
353 rust_packaging_dep = RUST_PACKAGING_DEPS[
354 min_rust_packaging_dep(package, target, is_bin, is_cdylib, vendor_tarball, cargo_install_lib, cargo_install_bin)
355 ]
357 required_features = get_required_features_for_binaries(package)
358 features_enabled_by_default = package.get_enabled_features_transitive(feature_flags)[0]
359 cargo_args = cargo_args_from_flags(feature_flags, required_features, features_enabled_by_default)
361 if license_str := metadata.packages[0].license: 361 ↛ 364line 361 didn't jump to line 364 because the condition on line 361 was always true
362 rpm_license, rpm_license_comments = translate_license(target, license_str)
363 else:
364 log.warn("No license information in crate metadata.")
365 rpm_license = None
366 rpm_license_comments = "# FIXME: No license information in crate metadata."
368 if supported_arches := tomlconf.package_supported_arches: 368 ↛ 369line 368 didn't jump to line 369 because the condition on line 368 was never true
369 conf_supported_arches = " ".join(supported_arches)
370 else:
371 conf_supported_arches = None
373 rpm_bcond_check = tomlconf.to_bcond_check()
374 rpm_test_comments = tomlconf.tests_comment_lines
375 cargo_test_args = tomlconf.to_cargo_test_args()
377 template_args_common = {
378 # Parameters specific to rust2rpm
379 "rust2rpm_version": generator_version,
380 "rust2rpm_target": target,
381 "rust2rpm_legacy": legacy,
382 "rust_packaging_dep": rust_packaging_dep,
383 # Paramters that control compiler flags
384 "build_rustflags_debuginfo": tomlconf.package_debuginfo_level,
385 # Parameters for RPM package metadata
386 "rpm_name": rpm_name,
387 "rpm_version": Version.parse(package.version).to_rpm(),
388 "rpm_summary": rpm_summary,
389 "rpm_description": rpm_description,
390 "rpm_license": rpm_license,
391 "rpm_license_comments": rpm_license_comments,
392 "rpm_patch_file_automatic": patch_file_automatic,
393 "rpm_patch_file_manual": patch_file_manual,
394 "rpm_patch_file_comments": tomlconf.package_cargo_toml_patch_comment_lines,
395 "rpm_buildrequires": rpm_buildrequires,
396 "rpm_test_requires": rpm_test_requires,
397 "rpm_requires": rpm_requires,
398 "rpm_provides": rpm_provides,
399 "rpm_license_files": license_files,
400 "rpm_doc_files": doc_files,
401 "rpm_bcond_check": rpm_bcond_check,
402 "rpm_test_comments": rpm_test_comments,
403 "rpm_vendor_source": vendor_tarball,
404 "rpm_extra_sources": tomlconf.package_extra_sources or list(),
405 "rpm_extra_patches": tomlconf.package_extra_patches or list(),
406 "rpm_extra_files": tomlconf.package_extra_files or list(),
407 # Parameters that control generation of subpackages
408 "rpm_binary_package": is_bin,
409 "rpm_binary_package_name": bin_name,
410 "rpm_cdylib_package": is_cdylib,
411 "rpm_library_package": is_lib,
412 "rpm_binary_names": binaries,
413 "crate_features": features,
414 "cargo_install_lib": cargo_install_lib,
415 "cargo_install_bin": cargo_install_bin,
416 # Parameters that allow injecting additional commands into scriptlets
417 "rpm_prep_pre": tomlconf.scripts_prep_pre or list(),
418 "rpm_prep_post": tomlconf.scripts_prep_post or list(),
419 "rpm_build_pre": tomlconf.scripts_build_pre or list(),
420 "rpm_build_post": tomlconf.scripts_build_post or list(),
421 "rpm_install_pre": tomlconf.scripts_install_pre or list(),
422 "rpm_install_post": tomlconf.scripts_install_post or list(),
423 "rpm_check_pre": tomlconf.scripts_check_pre or list(),
424 "rpm_check_post": tomlconf.scripts_check_post or list(),
425 # Parameters for crate metadata
426 "crate_name": package.name,
427 "crate_version": package.version,
428 "crate_license": package.license,
429 "upstream_version": upstream_version,
430 # Parameters for RPM macros
431 "rpm_autosetup_args": " -a1" if vendor_tarball else "",
432 "cargo_args": cargo_args,
433 "cargo_prep_args": " -v vendor" if vendor_tarball else "",
434 "cargo_test_args": cargo_test_args,
435 # Parameters derived from rust2rpm.toml
436 "conf_buildrequires": tomlconf.requires_build or list(),
437 "conf_test_requires": tomlconf.requires_test or list(),
438 "conf_bin_requires": tomlconf.requires_bin or list(),
439 "conf_lib_requires": conf_lib_requires,
440 "conf_supported_arches": conf_supported_arches,
441 "rpm_bin_renames": renames_from_bin_name_map(tomlconf.package_bin_renames),
442 # Parameters derived from command-line flags
443 "use_vendor_tarball": vendor_tarball is not None,
444 "use_relative_license_paths": relative_license_paths,
445 "use_rpmautospec": rpmautospec,
446 "make_changelog_entry": auto_changelog_entry,
447 }
449 match target:
450 case "fedora":
451 template_args_target = template_args_fedora(date, packager, rpmautospec)
452 case "mageia":
453 template_args_target = template_args_mageia(date, packager)
454 case "opensuse":
455 template_args_target = template_args_opensuse(date, packager)
456 case "plain": 456 ↛ 458line 456 didn't jump to line 458 because the pattern on line 456 always matched
457 template_args_target = template_args_plain(date, packager)
458 case _:
459 raise ValueError(f"Unknown target {target!r} (this should never happen)")
461 spec_contents = template.render(
462 **template_args_common,
463 **template_args_target,
464 )
466 if not spec_contents.endswith("\n"): 466 ↛ 469line 466 didn't jump to line 469 because the condition on line 466 was always true
467 spec_contents += "\n"
469 return spec_contents
472def spec_render_epel8(
473 *,
474 metadata: Metadata,
475 rpm_name: str,
476 patch_file_automatic: Optional[str],
477 patch_file_manual: Optional[str],
478 license_files: list[str],
479 doc_files: list[str],
480 vendor_tarball: Optional[str],
481 tomlconf: TomlConf,
482 rpmautospec: bool,
483 auto_changelog_entry: bool,
484 date: Optional[time.struct_time] = None,
485 packager: Optional[str],
486) -> str:
487 template = spec_file_template("epel8.spec")
489 # enforce consistent ordering of binaries
490 if bin_renames := tomlconf.package_bin_renames: 490 ↛ 491line 490 didn't jump to line 491 because the condition on line 490 was never true
491 binaries = []
492 for old_name in metadata.get_binaries():
493 if new_name := bin_renames.get(old_name):
494 binaries.append(new_name)
495 else:
496 binaries.append(old_name)
497 else:
498 binaries = [*metadata.get_binaries()]
499 binaries.sort()
501 if tomlconf.package_bin_package_name is None: 501 ↛ 504line 501 didn't jump to line 504 because the condition on line 501 was always true
502 bin_name = "%{crate}"
503 else:
504 bin_name = tomlconf.package_bin_package_name
506 package = metadata.packages[0]
508 if rpm_summary := tomlconf.package_summary: 508 ↛ 509line 508 didn't jump to line 509 because the condition on line 508 was never true
509 if len(rpm_summary) > 80:
510 log.warn("The package Summary specified in rust2rpm.toml is too long (>80 characters).")
511 elif rpm_summary := package.get_summary(): 511 ↛ 519line 511 didn't jump to line 519 because the condition on line 511 was always true
512 if len(rpm_summary) > 80: 512 ↛ 513line 512 didn't jump to line 513 because the condition on line 512 was never true
513 log.warn(
514 "Heuristics for generating a short Summary failed. "
515 "The generated Summary string is too long (>80 characters) and needs to be shortened manually. "
516 "This setting can be persisted with a 'package.summary' setting in 'rust2rpm.toml'."
517 )
518 else:
519 rpm_summary = "# FIXME"
521 rpm_description = tomlconf.package_description or package.get_description()
523 # enforce consistent ordering of feature subpackages
524 features: list[Optional[str]] = list(sorted(package.get_feature_names()))
525 if "default" in features: 525 ↛ 527line 525 didn't jump to line 527 because the condition on line 525 was always true
526 features.remove("default")
527 features.insert(0, None)
528 features.insert(1, "default")
530 generator_version = __version__.split(".")[0]
531 feature_flags = tomlconf.to_feature_flags()
533 conf_lib_requires = dict()
534 for feature in features:
535 if feature is None:
536 conf_key = "lib"
537 conf_lib_requires[conf_key] = tomlconf.requires_lib or list()
538 else:
539 conf_key = f"lib+{feature}"
540 if requires_features := tomlconf.requires_features: 540 ↛ 541line 540 didn't jump to line 541 because the condition on line 540 was never true
541 conf_lib_requires[conf_key] = requires_features.get(feature) or list()
542 else:
543 conf_lib_requires[conf_key] = list()
545 if features_hide := tomlconf.features_hide: 545 ↛ 546line 545 didn't jump to line 546 because the condition on line 545 was never true
546 for feature in features_hide:
547 features.remove(feature)
549 rust_packaging_dep = RUST_PACKAGING_DEPS[0]
551 required_features = get_required_features_for_binaries(package)
552 features_enabled_by_default = package.get_enabled_features_transitive(feature_flags)[0]
553 cargo_args = cargo_args_from_flags(feature_flags, required_features, features_enabled_by_default)
555 if license_str := metadata.packages[0].license: 555 ↛ 558line 555 didn't jump to line 558 because the condition on line 555 was always true
556 rpm_license, rpm_license_comments = translate_license("fedora", license_str)
557 else:
558 log.warn("No license information in crate metadata.")
559 rpm_license = None
560 rpm_license_comments = "# FIXME: No license information in crate metadata."
562 rpm_bcond_check = tomlconf.to_bcond_check()
563 rpm_test_comments = tomlconf.tests_comment_lines
564 cargo_test_args = tomlconf.to_cargo_test_args()
566 template_args_common = {
567 # Parameters specific to rust2rpm
568 "rust2rpm_version": generator_version,
569 "rust_packaging_dep": rust_packaging_dep,
570 # Paramters that control compiler flags
571 "build_rustflags_debuginfo": tomlconf.package_debuginfo_level,
572 # Parameters for RPM package metadata
573 "rpm_name": rpm_name,
574 "rpm_version": Version.parse(package.version).to_rpm(),
575 "rpm_summary": rpm_summary,
576 "rpm_description": rpm_description,
577 "rpm_license": rpm_license,
578 "rpm_license_comments": rpm_license_comments,
579 "rpm_patch_file_automatic": patch_file_automatic,
580 "rpm_patch_file_manual": patch_file_manual,
581 "rpm_patch_file_comments": tomlconf.package_cargo_toml_patch_comment_lines,
582 "rpm_license_files": license_files,
583 "rpm_doc_files": doc_files,
584 "rpm_bcond_check": rpm_bcond_check,
585 "rpm_test_comments": rpm_test_comments,
586 "rpm_vendor_source": vendor_tarball,
587 "rpm_extra_sources": tomlconf.package_extra_sources or list(),
588 "rpm_extra_patches": tomlconf.package_extra_patches or list(),
589 "rpm_extra_files": tomlconf.package_extra_files or list(),
590 # Parameters that control generation of subpackages
591 "rpm_binary_package_name": bin_name,
592 "rpm_binary_names": binaries,
593 # Parameters that allow injecting additional commands into scriptlets
594 "rpm_prep_pre": tomlconf.scripts_prep_pre or list(),
595 "rpm_prep_post": tomlconf.scripts_prep_post or list(),
596 "rpm_build_pre": tomlconf.scripts_build_pre or list(),
597 "rpm_build_post": tomlconf.scripts_build_post or list(),
598 "rpm_install_pre": tomlconf.scripts_install_pre or list(),
599 "rpm_install_post": tomlconf.scripts_install_post or list(),
600 "rpm_check_pre": tomlconf.scripts_check_pre or list(),
601 "rpm_check_post": tomlconf.scripts_check_post or list(),
602 # Parameters for crate metadata
603 "crate_name": package.name,
604 "crate_license": package.license,
605 # Parameters for RPM macros
606 "cargo_args": cargo_args,
607 "cargo_test_args": cargo_test_args,
608 # Parameters derived from rust2rpm.toml
609 "conf_buildrequires": tomlconf.requires_build or list(),
610 "conf_test_requires": tomlconf.requires_test or list(),
611 "conf_bin_requires": tomlconf.requires_bin or list(),
612 "rpm_bin_renames": renames_from_bin_name_map(tomlconf.package_bin_renames),
613 # Parameters derived from command-line flags
614 "use_rpmautospec": rpmautospec,
615 "make_changelog_entry": auto_changelog_entry,
616 }
618 template_args_target = template_args_epel8(date, packager, rpmautospec)
620 spec_contents = template.render(
621 **template_args_common,
622 **template_args_target,
623 )
625 if not spec_contents.endswith("\n"): 625 ↛ 628line 625 didn't jump to line 628 because the condition on line 625 was always true
626 spec_contents += "\n"
628 return spec_contents
631def spec_render_project(
632 *,
633 metadata: Metadata,
634 upstream_version: str,
635 target: str,
636 legacy: bool,
637 rpm_name: str,
638 patch_file_automatic: Optional[str],
639 patch_file_manual: Optional[str],
640 license_files: list[str],
641 doc_files: list[str],
642 vendor_tarball: Optional[str],
643 tomlconf: TomlConf,
644 rpmautospec: bool,
645 auto_changelog_entry: bool,
646 date: Optional[time.struct_time] = None,
647 packager: Optional[str],
648) -> str:
649 template = spec_file_template("project.spec")
651 # enforce consistent ordering of binaries
652 if bin_renames := tomlconf.package_bin_renames: 652 ↛ 653line 652 didn't jump to line 653 because the condition on line 652 was never true
653 binaries = []
654 for old_name in metadata.get_binaries():
655 if new_name := bin_renames.get(old_name):
656 binaries.append(new_name)
657 else:
658 binaries.append(old_name)
659 else:
660 binaries = [*metadata.get_binaries()]
661 binaries.sort()
663 is_bin = metadata.is_bin()
664 is_cdylib = metadata.is_cdylib()
666 package = metadata.packages[0]
668 if rpm_summary := tomlconf.package_summary: 668 ↛ 669line 668 didn't jump to line 669 because the condition on line 668 was never true
669 if len(rpm_summary) > 80:
670 log.warn("The package Summary specified in rust2rpm.toml is too long (>80 characters).")
671 elif rpm_summary := package.get_summary(): 671 ↛ 679line 671 didn't jump to line 679 because the condition on line 671 was always true
672 if len(rpm_summary) > 80: 672 ↛ 673line 672 didn't jump to line 673 because the condition on line 672 was never true
673 log.warn(
674 "Heuristics for generating a short Summary failed. "
675 "The generated Summary string is too long (>80 characters) and needs to be shortened manually. "
676 "This setting can be persisted with a 'package.summary' setting in 'rust2rpm.toml'."
677 )
678 else:
679 rpm_summary = "# FIXME"
681 rpm_description = tomlconf.package_description or package.get_description()
683 generator_version = __version__.split(".")[0]
684 feature_flags = tomlconf.to_feature_flags()
686 buildrequires = rpm.buildrequires(package, feature_flags, False)
687 test_requires = set.difference(
688 rpm.buildrequires(package, feature_flags, True), rpm.buildrequires(package, feature_flags, False)
689 )
691 rpm_buildrequires = list(sorted(buildrequires))
692 rpm_test_requires = list(sorted(test_requires))
694 rust_packaging_dep = RUST_PACKAGING_DEPS[
695 min_rust_packaging_dep(package, target, is_bin, is_cdylib, vendor_tarball, False, True)
696 ]
698 required_features = get_required_features_for_binaries(package)
699 features_enabled_by_default = package.get_enabled_features_transitive(feature_flags)[0]
700 cargo_args = cargo_args_from_flags(feature_flags, required_features, features_enabled_by_default)
702 if license_str := metadata.packages[0].license: 702 ↛ 705line 702 didn't jump to line 705 because the condition on line 702 was always true
703 rpm_license, rpm_license_comments = translate_license(target, license_str)
704 else:
705 log.warn("No license information in crate metadata.")
706 rpm_license = None
707 rpm_license_comments = "# FIXME: No license information in crate metadata."
709 if supported_arches := tomlconf.package_supported_arches: 709 ↛ 710line 709 didn't jump to line 710 because the condition on line 709 was never true
710 conf_supported_arches = " ".join(supported_arches)
711 else:
712 conf_supported_arches = None
714 rpm_bcond_check = tomlconf.to_bcond_check()
715 rpm_test_comments = tomlconf.tests_comment_lines
716 cargo_test_args = tomlconf.to_cargo_test_args()
718 template_args_common = {
719 # Parameters specific to rust2rpm
720 "rust2rpm_version": generator_version,
721 "rust2rpm_target": target,
722 "rust2rpm_legacy": legacy,
723 "rust_packaging_dep": rust_packaging_dep,
724 # Paramters that control compiler flags
725 "build_rustflags_debuginfo": tomlconf.package_debuginfo_level,
726 # Parameters for RPM package metadata
727 "rpm_name": rpm_name,
728 "rpm_version": Version.parse(package.version).to_rpm(),
729 "rpm_summary": rpm_summary,
730 "rpm_description": rpm_description,
731 "rpm_url": tomlconf.package_url or package.repository or package.homepage or "# FIXME",
732 "rpm_source_url": tomlconf.package_source_url or "# FIXME",
733 "rpm_license": rpm_license,
734 "rpm_license_comments": rpm_license_comments,
735 "rpm_patch_file_automatic": patch_file_automatic,
736 "rpm_patch_file_manual": patch_file_manual,
737 "rpm_patch_file_comments": tomlconf.package_cargo_toml_patch_comment_lines,
738 "rpm_buildrequires": rpm_buildrequires,
739 "rpm_test_requires": rpm_test_requires,
740 "rpm_license_files": license_files,
741 "rpm_doc_files": doc_files,
742 "rpm_bcond_check": rpm_bcond_check,
743 "rpm_test_comments": rpm_test_comments,
744 "rpm_vendor_source": vendor_tarball,
745 "rpm_extra_sources": tomlconf.package_extra_sources or list(),
746 "rpm_extra_patches": tomlconf.package_extra_patches or list(),
747 "rpm_extra_files": tomlconf.package_extra_files or list(),
748 # Parameters that control generation of subpackages
749 "rpm_binary_package": is_bin,
750 "rpm_cdylib_package": is_cdylib,
751 "rpm_binary_names": binaries,
752 # Parameters that allow injecting additional commands into scriptlets
753 "rpm_prep_pre": tomlconf.scripts_prep_pre or list(),
754 "rpm_prep_post": tomlconf.scripts_prep_post or list(),
755 "rpm_build_pre": tomlconf.scripts_build_pre or list(),
756 "rpm_build_post": tomlconf.scripts_build_post or list(),
757 "rpm_install_pre": tomlconf.scripts_install_pre or list(),
758 "rpm_install_post": tomlconf.scripts_install_post or list(),
759 "rpm_check_pre": tomlconf.scripts_check_pre or list(),
760 "rpm_check_post": tomlconf.scripts_check_post or list(),
761 # Parameters for crate metadata
762 "crate_name": package.name,
763 "crate_version": package.version,
764 "crate_license": package.license,
765 "upstream_version": upstream_version,
766 # Parameters for RPM macros
767 "rpm_autosetup_args": " -a1" if vendor_tarball else "",
768 "cargo_args": cargo_args,
769 "cargo_prep_args": " -v vendor" if vendor_tarball else "",
770 "cargo_test_args": cargo_test_args,
771 # Parameters derived from rust2rpm.toml
772 "conf_buildrequires": tomlconf.requires_build or list(),
773 "conf_test_requires": tomlconf.requires_test or list(),
774 "conf_bin_requires": tomlconf.requires_bin or list(),
775 "conf_supported_arches": conf_supported_arches,
776 "rpm_bin_renames": renames_from_bin_name_map(tomlconf.package_bin_renames),
777 # Parameters derived from command-line flags
778 "use_vendor_tarball": vendor_tarball is not None,
779 "use_rpmautospec": rpmautospec,
780 "make_changelog_entry": auto_changelog_entry,
781 }
783 match target:
784 case "fedora":
785 template_args_target = template_args_fedora(date, packager, rpmautospec)
786 case "mageia":
787 template_args_target = template_args_mageia(date, packager)
788 case "opensuse":
789 template_args_target = template_args_opensuse(date, packager)
790 case "plain": 790 ↛ 792line 790 didn't jump to line 792 because the pattern on line 790 always matched
791 template_args_target = template_args_plain(date, packager)
792 case _:
793 raise ValueError(f"Unknown target {target!r} (this should never happen)")
795 spec_contents = template.render(
796 **template_args_common,
797 **template_args_target,
798 )
800 if not spec_contents.endswith("\n"): 800 ↛ 803line 800 didn't jump to line 803 because the condition on line 800 was always true
801 spec_contents += "\n"
803 return spec_contents
806def spec_render_workspace(
807 *,
808 metadata: Metadata,
809 main_package: Package,
810 upstream_version: str,
811 target: str,
812 legacy: bool,
813 rpm_name: str,
814 license_files: list[str],
815 doc_files: list[str],
816 vendor_tarball: Optional[str],
817 tomlconf: TomlConf,
818 rpmautospec: bool,
819 auto_changelog_entry: bool,
820 date: Optional[time.struct_time] = None,
821 packager: Optional[str],
822) -> str:
823 template = spec_file_template("workspace.spec")
825 # enforce consistent ordering of binaries
826 if bin_renames := tomlconf.package_bin_renames: 826 ↛ 827line 826 didn't jump to line 827 because the condition on line 826 was never true
827 binaries = []
828 for old_name in metadata.get_binaries():
829 if new_name := bin_renames.get(old_name):
830 binaries.append(new_name)
831 else:
832 binaries.append(old_name)
833 else:
834 binaries = [*metadata.get_binaries()]
835 binaries.sort()
837 is_cdylib = metadata.is_cdylib()
839 try:
840 rpm_version = Version.parse(upstream_version).to_rpm()
841 except ValueError:
842 log.warn(f"Version {upstream_version!r} is not valid according to SemVer.")
843 rpm_version = upstream_version
845 if rpm_summary := tomlconf.package_summary: 845 ↛ 846line 845 didn't jump to line 846 because the condition on line 845 was never true
846 if len(rpm_summary) > 80:
847 log.warn("The package Summary specified in rust2rpm.toml is too long (>80 characters).")
848 elif rpm_summary := main_package.get_summary():
849 if len(rpm_summary) > 80: 849 ↛ 850line 849 didn't jump to line 850 because the condition on line 849 was never true
850 log.warn(
851 "Heuristics for generating a short Summary failed. "
852 "The generated Summary string is too long (>80 characters) and needs to be shortened manually. "
853 "This setting can be persisted with a 'package.summary' setting in rust2rpm.toml."
854 )
855 else:
856 rpm_summary = "# FIXME"
858 rpm_description = tomlconf.package_description or main_package.get_description()
860 generator_version = __version__.split(".")[0]
861 feature_flags = tomlconf.to_feature_flags()
863 buildrequires = rpm.workspace_buildrequires(metadata, feature_flags, False)
864 test_requires = set.difference(
865 rpm.workspace_buildrequires(metadata, feature_flags, True),
866 rpm.workspace_buildrequires(metadata, feature_flags, False),
867 )
869 rpm_buildrequires = list(sorted(buildrequires))
870 rpm_test_requires = list(sorted(test_requires))
872 rust_packaging_dep = RUST_PACKAGING_DEPS[
873 max(
874 (
875 24,
876 max(
877 min_rust_packaging_dep(
878 package, target, package.is_bin(), package.is_cdylib(), vendor_tarball, True, True
879 )
880 for package in metadata.packages
881 ),
882 )
883 )
884 ]
886 cargo_args = cargo_args_from_flags(feature_flags, set(), set())
888 license_strs = list({package.license for package in metadata.packages if package.license})
889 if len(license_strs) == 1: 889 ↛ 892line 889 didn't jump to line 892 because the condition on line 889 was always true
890 rpm_license_tag, rpm_license_comments = translate_license(target, license_strs[0])
891 else:
892 license_strs = [
893 license_str if not license_is_composite(license_str) else f"({license_str})"
894 for license_str in license_strs
895 if license_str is not None
896 ]
897 license_strs.sort()
898 license_str = " AND ".join(license_strs)
899 rpm_license_tag, rpm_license_comments = translate_license(target, license_str)
901 rpm_bcond_check = tomlconf.to_bcond_check()
902 rpm_test_comments = tomlconf.tests_comment_lines
903 cargo_test_args = tomlconf.to_cargo_test_args()
905 template_args_common = {
906 # Parameters specific to rust2rpm
907 "rust2rpm_version": generator_version,
908 "rust2rpm_target": target,
909 "rust2rpm_legacy": legacy,
910 "rust_packaging_dep": rust_packaging_dep,
911 # Paramters that control compiler flags
912 "build_rustflags_debuginfo": tomlconf.package_debuginfo_level,
913 # Parameters for RPM package metadata
914 "rpm_name": rpm_name,
915 "rpm_version": rpm_version,
916 "rpm_summary": rpm_summary,
917 "rpm_description": rpm_description,
918 "rpm_url": tomlconf.package_url or "# FIXME",
919 "rpm_source_url": tomlconf.package_source_url or "# FIXME",
920 "rpm_license": rpm_license_tag,
921 "rpm_license_comments": rpm_license_comments,
922 "rpm_buildrequires": rpm_buildrequires,
923 "rpm_test_requires": rpm_test_requires,
924 "rpm_license_files": license_files,
925 "rpm_doc_files": doc_files,
926 "rpm_binary_names": binaries,
927 "rpm_cdylib_package": is_cdylib,
928 "upstream_version": upstream_version,
929 "rpm_bcond_check": rpm_bcond_check,
930 "rpm_test_comments": rpm_test_comments,
931 "rpm_vendor_source": vendor_tarball,
932 "rpm_extra_sources": tomlconf.package_extra_sources or list(),
933 "rpm_extra_patches": tomlconf.package_extra_patches or list(),
934 "rpm_extra_files": tomlconf.package_extra_files or list(),
935 # Parameters that allow injecting additional commands into scriptlets
936 "rpm_prep_pre": tomlconf.scripts_prep_pre or list(),
937 "rpm_prep_post": tomlconf.scripts_prep_post or list(),
938 "rpm_build_pre": tomlconf.scripts_build_pre or list(),
939 "rpm_build_post": tomlconf.scripts_build_post or list(),
940 "rpm_install_pre": tomlconf.scripts_install_pre or list(),
941 "rpm_install_post": tomlconf.scripts_install_post or list(),
942 "rpm_check_pre": tomlconf.scripts_check_pre or list(),
943 "rpm_check_post": tomlconf.scripts_check_post or list(),
944 # Parameters for RPM macros
945 "rpm_autosetup_args": " -a1" if vendor_tarball else "",
946 "cargo_args": cargo_args,
947 "cargo_prep_args": " -v vendor" if vendor_tarball else "",
948 "cargo_test_args": cargo_test_args,
949 # Parameters derived from rust2rpm.toml
950 "conf_buildrequires": tomlconf.requires_build or list(),
951 "conf_test_requires": tomlconf.requires_test or list(),
952 "conf_bin_requires": tomlconf.requires_bin or list(),
953 "rpm_bin_renames": renames_from_bin_name_map(tomlconf.package_bin_renames),
954 # Parameters derived from command-line flags
955 "use_vendor_tarball": vendor_tarball is not None,
956 "use_rpmautospec": rpmautospec,
957 "make_changelog_entry": auto_changelog_entry,
958 }
960 match target:
961 case "fedora":
962 template_args_target = template_args_fedora(date, packager, rpmautospec)
963 case "mageia":
964 template_args_target = template_args_mageia(date, packager)
965 case "opensuse":
966 template_args_target = template_args_opensuse(date, packager)
967 case "plain": 967 ↛ 969line 967 didn't jump to line 969 because the pattern on line 967 always matched
968 template_args_target = template_args_plain(date, packager)
969 case _:
970 raise ValueError(f"Unknown target {target!r} (this should never happen)")
972 spec_contents = template.render(
973 **template_args_common,
974 **template_args_target,
975 )
977 if not spec_contents.endswith("\n"): 977 ↛ 980line 977 didn't jump to line 980 because the condition on line 977 was always true
978 spec_contents += "\n"
980 return spec_contents