Coverage for rust2rpm/generator.py: 75%

388 statements  

« 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""" 

4 

5import time 

6from typing import Optional 

7 

8from cargo2rpm.metadata import FeatureFlags, Metadata, Package 

9from cargo2rpm.semver import Version 

10from cargo2rpm import rpm 

11import jinja2 

12 

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 

17 

18 

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} 

27 

28 

29RUST_PACKAGING_TARGET_MIN: dict[str, int] = { 

30 "fedora": 24, 

31 "mageia": 21, 

32 "opensuse": 21, 

33 "plain": 21, 

34} 

35 

36 

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 ) 

46 

47 

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 

67 

68 return max((min_dep, RUST_PACKAGING_TARGET_MIN[target])) 

69 

70 

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 [] 

74 

75 return [ 

76 f"mv %{ buildroot} /%{ _bindir} /{old} %{ buildroot} /%{ _bindir} /{new}" for old, new in bin_name_map.items() 

77 ] 

78 

79 

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" 

85 

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) 

91 

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) 

97 

98 if feature_flags.no_default_features: 

99 cargo_args_list = ["-n"] 

100 else: 

101 cargo_args_list = [] 

102 

103 if len(enabled_features) > 0: 

104 cargo_args_list.append(f"-f {','.join(enabled_features)}") 

105 

106 if cargo_args_list: 

107 cargo_args = " " + " ".join(cargo_args_list) 

108 else: 

109 cargo_args = "" 

110 

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 = [] 

117 

118 cargo_args_list.append(f"-f {','.join(feature_flags.features)}") 

119 cargo_args = " " + " ".join(cargo_args_list) 

120 

121 elif feature_flags.no_default_features: 

122 cargo_args = " -n" 

123 

124 else: 

125 cargo_args = "" 

126 

127 return cargo_args 

128 

129 

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 ) 

137 

138 return env.get_template(filename) 

139 

140 

141def template_args_fedora(date: Optional[time.struct_time], packager: Optional[str], rpmautospec: bool) -> dict: 

142 kwargs: dict[str, str | bool] = dict() 

143 

144 kwargs["include_build_requires"] = False 

145 kwargs["include_provides"] = False 

146 kwargs["include_requires"] = False 

147 

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}" 

152 

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) 

158 

159 kwargs["rpm_changelog_packager"] = packager or "rust2rpm <nobody@fedoraproject.org>" 

160 

161 return kwargs 

162 

163 

164def template_args_epel8(date: Optional[time.struct_time], packager: Optional[str], rpmautospec: bool) -> dict: 

165 kwargs: dict[str, str | bool] = dict() 

166 

167 kwargs["include_build_requires"] = False 

168 

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}" 

173 

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) 

179 

180 kwargs["rpm_changelog_packager"] = packager or "rust2rpm <nobody@fedoraproject.org>" 

181 

182 return kwargs 

183 

184 

185def template_args_mageia(date: Optional[time.struct_time], packager: Optional[str]) -> dict: 

186 kwargs: dict[str, str | bool] = dict() 

187 

188 kwargs["include_build_requires"] = True 

189 kwargs["include_provides"] = False 

190 kwargs["include_requires"] = False 

191 

192 kwargs["rpm_release"] = "%mkrel 1" 

193 kwargs["rpm_group"] = "Development/Rust" 

194 

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) 

200 

201 kwargs["rpm_changelog_packager"] = packager or "rust2rpm <nobody@mageia.org>" 

202 

203 return kwargs 

204 

205 

206def template_args_opensuse(date: Optional[time.struct_time], packager: Optional[str]) -> dict: 

207 kwargs: dict[str, str | bool] = dict() 

208 

209 kwargs["include_build_requires"] = True 

210 kwargs["include_provides"] = False 

211 kwargs["include_requires"] = False 

212 

213 kwargs["spec_copyright_year"] = time.strftime("%Y") 

214 kwargs["rpm_release"] = "0" 

215 kwargs["rpm_group"] = "Development/Libraries/Rust" 

216 

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) 

222 

223 kwargs["rpm_changelog_packager"] = packager or "rust2rpm <opensuse-packaging@opensuse.org>" 

224 

225 return kwargs 

226 

227 

228def template_args_plain(date: Optional[time.struct_time], packager: Optional[str]) -> dict: 

229 kwargs: dict[str, str | bool] = dict() 

230 

231 kwargs["include_build_requires"] = True 

232 kwargs["include_provides"] = True 

233 kwargs["include_requires"] = True 

234 

235 kwargs["rpm_release"] = "1%{?dist}" 

236 

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) 

242 

243 kwargs["rpm_changelog_packager"] = packager or "rust2rpm <packager@example.com>" 

244 

245 return kwargs 

246 

247 

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") 

269 

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() 

281 

282 is_bin = metadata.is_bin() 

283 is_lib = metadata.is_lib() 

284 is_cdylib = metadata.is_cdylib() 

285 

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) 

288 

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 

293 

294 package = metadata.packages[0] 

295 

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" 

308 

309 rpm_description = tomlconf.package_description or package.get_description() 

310 

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") 

317 

318 generator_version = __version__.split(".")[0] 

319 feature_flags = tomlconf.to_feature_flags() 

320 

321 try: 

322 buildrequires_with_dev = rpm.buildrequires(package, feature_flags, True) 

323 buildrequires_without_dev = rpm.buildrequires(package, feature_flags, False) 

324 

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 

331 

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} 

336 

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() 

348 

349 if features_hide := tomlconf.features_hide: 

350 for feature in features_hide: 

351 features.remove(feature) 

352 

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 ] 

356 

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) 

360 

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." 

367 

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 

372 

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() 

376 

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 } 

448 

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)") 

460 

461 spec_contents = template.render( 

462 **template_args_common, 

463 **template_args_target, 

464 ) 

465 

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" 

468 

469 return spec_contents 

470 

471 

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") 

488 

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() 

500 

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 

505 

506 package = metadata.packages[0] 

507 

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" 

520 

521 rpm_description = tomlconf.package_description or package.get_description() 

522 

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") 

529 

530 generator_version = __version__.split(".")[0] 

531 feature_flags = tomlconf.to_feature_flags() 

532 

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() 

544 

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) 

548 

549 rust_packaging_dep = RUST_PACKAGING_DEPS[0] 

550 

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) 

554 

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." 

561 

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() 

565 

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 } 

617 

618 template_args_target = template_args_epel8(date, packager, rpmautospec) 

619 

620 spec_contents = template.render( 

621 **template_args_common, 

622 **template_args_target, 

623 ) 

624 

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" 

627 

628 return spec_contents 

629 

630 

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") 

650 

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() 

662 

663 is_bin = metadata.is_bin() 

664 is_cdylib = metadata.is_cdylib() 

665 

666 package = metadata.packages[0] 

667 

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" 

680 

681 rpm_description = tomlconf.package_description or package.get_description() 

682 

683 generator_version = __version__.split(".")[0] 

684 feature_flags = tomlconf.to_feature_flags() 

685 

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 ) 

690 

691 rpm_buildrequires = list(sorted(buildrequires)) 

692 rpm_test_requires = list(sorted(test_requires)) 

693 

694 rust_packaging_dep = RUST_PACKAGING_DEPS[ 

695 min_rust_packaging_dep(package, target, is_bin, is_cdylib, vendor_tarball, False, True) 

696 ] 

697 

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) 

701 

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." 

708 

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 

713 

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() 

717 

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 } 

782 

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)") 

794 

795 spec_contents = template.render( 

796 **template_args_common, 

797 **template_args_target, 

798 ) 

799 

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" 

802 

803 return spec_contents 

804 

805 

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") 

824 

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() 

836 

837 is_cdylib = metadata.is_cdylib() 

838 

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 

844 

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" 

857 

858 rpm_description = tomlconf.package_description or main_package.get_description() 

859 

860 generator_version = __version__.split(".")[0] 

861 feature_flags = tomlconf.to_feature_flags() 

862 

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 ) 

868 

869 rpm_buildrequires = list(sorted(buildrequires)) 

870 rpm_test_requires = list(sorted(test_requires)) 

871 

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 ] 

885 

886 cargo_args = cargo_args_from_flags(feature_flags, set(), set()) 

887 

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) 

900 

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() 

904 

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 } 

959 

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)") 

971 

972 spec_contents = template.render( 

973 **template_args_common, 

974 **template_args_target, 

975 ) 

976 

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" 

979 

980 return spec_contents