nixpkgs mirror (for testing) github.com/NixOS/nixpkgs
nix
at python-updates 746 lines 24 kB view raw
1# Checks derivation meta and attrs for problems (like brokenness, 2# licenses, etc). 3 4{ 5 lib, 6 config, 7 hostPlatform, 8}: 9 10let 11 inherit (lib) 12 all 13 attrNames 14 attrValues 15 concatMapStrings 16 concatMapStringsSep 17 concatStrings 18 filter 19 findFirst 20 getName 21 isDerivation 22 length 23 concatMap 24 mutuallyExclusive 25 optional 26 optionalString 27 isAttrs 28 isString 29 mapAttrs 30 ; 31 32 inherit (lib.lists) 33 any 34 toList 35 isList 36 elem 37 unique 38 ; 39 40 inherit (lib.meta) 41 availableOn 42 cpeFullVersionWithVendor 43 tryCPEPatchVersionInUpdateWithVendor 44 ; 45 46 inherit (lib.generators) 47 toPretty 48 ; 49 50 inherit (builtins) 51 getEnv 52 trace 53 ; 54 55 # If we're in hydra, we can dispense with the more verbose error 56 # messages and make problems easier to spot. 57 inHydra = config.inHydra or false; 58 # Allow the user to opt-into additional warnings, e.g. 59 # import <nixpkgs> { config = { showDerivationWarnings = [ "maintainerless" ]; }; } 60 showWarnings = config.showDerivationWarnings; 61 62 getNameWithVersion = 63 attrs: attrs.name or "${attrs.pname or "«name-missing»"}-${attrs.version or "«version-missing»"}"; 64 65 allowUnfree = config.allowUnfree || getEnv "NIXPKGS_ALLOW_UNFREE" == "1"; 66 67 allowNonSource = 68 let 69 envVar = getEnv "NIXPKGS_ALLOW_NONSOURCE"; 70 in 71 if envVar != "" then envVar != "0" else config.allowNonSource or true; 72 73 allowlist = config.allowlistedLicenses or config.whitelistedLicenses or [ ]; 74 blocklist = config.blocklistedLicenses or config.blacklistedLicenses or [ ]; 75 76 areLicenseListsValid = 77 if mutuallyExclusive allowlist blocklist then 78 true 79 else 80 throw "allowlistedLicenses and blocklistedLicenses are not mutually exclusive."; 81 82 hasListedLicense = 83 assert areLicenseListsValid; 84 list: 85 if list == [ ] then 86 attrs: false 87 else 88 attrs: 89 attrs ? meta.license 90 && ( 91 if isList attrs.meta.license then 92 any (l: elem l list) attrs.meta.license 93 else 94 elem attrs.meta.license list 95 ); 96 97 hasAllowlistedLicense = hasListedLicense allowlist; 98 99 hasBlocklistedLicense = hasListedLicense blocklist; 100 101 allowBroken = config.allowBroken || getEnv "NIXPKGS_ALLOW_BROKEN" == "1"; 102 103 allowUnsupportedSystem = 104 config.allowUnsupportedSystem || getEnv "NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM" == "1"; 105 106 isUnfree = 107 licenses: 108 if isAttrs licenses then 109 !(licenses.free or true) 110 # TODO: Returning false in the case of a string is a bug that should be fixed. 111 # In a previous implementation of this function the function body 112 # was `licenses: lib.lists.any (l: !l.free or true) licenses;` 113 # which always evaluates to `!true` for strings. 114 else if isString licenses then 115 false 116 else 117 any (l: !(l.free or true)) licenses; 118 119 hasUnfreeLicense = attrs: attrs ? meta.license && isUnfree attrs.meta.license; 120 121 hasNoMaintainers = 122 # To get usable output, we want to avoid flagging "internal" derivations. 123 # Because we do not have a way to reliably decide between internal or 124 # external derivation, some heuristics are required to decide. 125 # 126 # If `outputHash` is defined, the derivation is a FOD, such as the output of a fetcher. 127 # If `description` is not defined, the derivation is probably not a package. 128 # Simply checking whether `meta` is defined is insufficient, 129 # as some fetchers and trivial builders do define meta. 130 attrs: 131 (!attrs ? outputHash) 132 && (attrs ? meta.description) 133 && (attrs.meta.maintainers or [ ] == [ ]) 134 && (attrs.meta.teams or [ ] == [ ]); 135 136 isMarkedBroken = attrs: attrs.meta.broken or false; 137 138 # Allow granular checks to allow only some broken packages 139 # Example: 140 # { pkgs, ... }: 141 # { 142 # allowBroken = false; 143 # allowBrokenPredicate = pkg: builtins.elem (pkgs.lib.getName pkg) [ "hello" ]; 144 # } 145 allowBrokenPredicate = config.allowBrokenPredicate or (x: false); 146 147 hasDeniedBroken = 148 attrs: (attrs.meta.broken or false) && !allowBroken && !allowBrokenPredicate attrs; 149 150 hasUnsupportedPlatform = pkg: !(availableOn hostPlatform pkg); 151 152 isMarkedInsecure = attrs: (attrs.meta.knownVulnerabilities or [ ]) != [ ]; 153 154 # Allow granular checks to allow only some unfree packages 155 # Example: 156 # {pkgs, ...}: 157 # { 158 # allowUnfree = false; 159 # allowUnfreePredicate = (x: pkgs.lib.hasPrefix "vscode" x.name); 160 # } 161 # Defaults to allow all names defined in config.allowUnfreePackages 162 allowUnfreePredicate = 163 let 164 listPredicate = pkg: builtins.elem (lib.getName pkg) (config.allowUnfreePackages or [ ]); 165 166 # Be robust against misconfigured allowUnfreePredicate values such as null 167 explicitPredicate = 168 let 169 raw = config.allowUnfreePredicate or null; 170 in 171 if builtins.isFunction raw then raw else (_: false); 172 in 173 pkg: (listPredicate pkg) || (explicitPredicate pkg); 174 175 # Check whether unfree packages are allowed and if not, whether the 176 # package has an unfree license and is not explicitly allowed by the 177 # `allowUnfreePredicate` function. 178 hasDeniedUnfreeLicense = 179 attrs: hasUnfreeLicense attrs && !allowUnfree && !allowUnfreePredicate attrs; 180 181 allowInsecureDefaultPredicate = 182 x: elem (getNameWithVersion x) (config.permittedInsecurePackages or [ ]); 183 allowInsecurePredicate = config.allowInsecurePredicate or allowInsecureDefaultPredicate; 184 185 allowInsecure = getEnv "NIXPKGS_ALLOW_INSECURE" == "1"; 186 187 hasDisallowedInsecure = 188 attrs: isMarkedInsecure attrs && !allowInsecure && !allowInsecurePredicate attrs; 189 190 # Allow granular checks to allow only some non-source-built packages 191 # Example: 192 # { pkgs, ... }: 193 # { 194 # allowNonSource = false; 195 # allowNonSourcePredicate = with pkgs.lib.lists; pkg: !(any (p: !p.isSource && p != lib.sourceTypes.binaryFirmware) pkg.meta.sourceProvenance); 196 # } 197 allowNonSourcePredicate = config.allowNonSourcePredicate or (x: false); 198 199 # Check whether non-source packages are allowed and if not, whether the 200 # package has non-source provenance and is not explicitly allowed by the 201 # `allowNonSourcePredicate` function. 202 hasDeniedNonSourceProvenance = 203 attrs: 204 attrs ? meta.sourceProvenance 205 && any (t: !t.isSource) attrs.meta.sourceProvenance 206 && !allowNonSource 207 && !allowNonSourcePredicate attrs; 208 209 showLicenseOrSourceType = 210 value: toString (map (v: v.shortName or v.fullName or "unknown") (toList value)); 211 showLicense = showLicenseOrSourceType; 212 showSourceType = showLicenseOrSourceType; 213 214 pos_str = meta: meta.position or "«unknown-file»"; 215 216 remediation_env_var = 217 allow_attr: 218 { 219 Unfree = "NIXPKGS_ALLOW_UNFREE"; 220 Broken = "NIXPKGS_ALLOW_BROKEN"; 221 UnsupportedSystem = "NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM"; 222 NonSource = "NIXPKGS_ALLOW_NONSOURCE"; 223 } 224 .${allow_attr}; 225 remediation_phrase = 226 allow_attr: 227 { 228 Unfree = "unfree packages"; 229 Broken = "broken packages"; 230 UnsupportedSystem = "packages that are unsupported for this system"; 231 NonSource = "packages not built from source"; 232 } 233 .${allow_attr}; 234 remediate_predicate = predicateConfigAttr: attrs: '' 235 236 Alternatively you can configure a predicate to allow specific packages: 237 { nixpkgs.config.${predicateConfigAttr} = pkg: builtins.elem (lib.getName pkg) [ 238 "${getName attrs}" 239 ]; 240 } 241 ''; 242 243 # flakeNote will be printed in the remediation messages below. 244 flakeNote = " 245 Note: When using `nix shell`, `nix build`, `nix develop`, etc with a flake, 246 then pass `--impure` in order to allow use of environment variables. 247 "; 248 249 remediate_allowlist = allow_attr: rebuild_amendment: '' 250 a) To temporarily allow ${remediation_phrase allow_attr}, you can use an environment variable 251 for a single invocation of the nix tools. 252 253 $ export ${remediation_env_var allow_attr}=1 254 ${flakeNote} 255 b) For `nixos-rebuild` you can set 256 { nixpkgs.config.allow${allow_attr} = true; } 257 in configuration.nix to override this. 258 ${rebuild_amendment} 259 c) For `nix-env`, `nix-build`, `nix-shell` or any other Nix command you can add 260 { allow${allow_attr} = true; } 261 to ~/.config/nixpkgs/config.nix. 262 ''; 263 264 remediate_insecure = 265 attrs: 266 '' 267 268 Known issues: 269 '' 270 + (concatStrings (map (issue: " - ${issue}\n") attrs.meta.knownVulnerabilities)) 271 + '' 272 273 You can install it anyway by allowing this package, using the 274 following methods: 275 276 a) To temporarily allow all insecure packages, you can use an environment 277 variable for a single invocation of the nix tools: 278 279 $ export NIXPKGS_ALLOW_INSECURE=1 280 ${flakeNote} 281 b) for `nixos-rebuild` you can add ${getNameWithVersion attrs} to 282 `nixpkgs.config.permittedInsecurePackages` in the configuration.nix, 283 like so: 284 285 { 286 nixpkgs.config.permittedInsecurePackages = [ 287 "${getNameWithVersion attrs}" 288 ]; 289 } 290 291 c) For `nix-env`, `nix-build`, `nix-shell` or any other Nix command you can add 292 ${getNameWithVersion attrs} to `permittedInsecurePackages` in 293 ~/.config/nixpkgs/config.nix, like so: 294 295 { 296 permittedInsecurePackages = [ 297 "${getNameWithVersion attrs}" 298 ]; 299 } 300 301 ''; 302 303 remediateOutputsToInstall = 304 attrs: 305 let 306 expectedOutputs = attrs.meta.outputsToInstall or [ ]; 307 actualOutputs = attrs.outputs or [ "out" ]; 308 missingOutputs = filter (output: !elem output actualOutputs) expectedOutputs; 309 in 310 '' 311 The package ${getNameWithVersion attrs} has set meta.outputsToInstall to: ${builtins.concatStringsSep ", " expectedOutputs} 312 313 however ${getNameWithVersion attrs} only has the outputs: ${builtins.concatStringsSep ", " actualOutputs} 314 315 and is missing the following outputs: 316 317 ${concatStrings (map (output: " - ${output}\n") missingOutputs)} 318 ''; 319 320 metaTypes = 321 let 322 types = import ./meta-types.nix { inherit lib; }; 323 inherit (types) 324 str 325 union 326 int 327 attrs 328 attrsOf 329 any 330 listOf 331 bool 332 ; 333 platforms = listOf (union [ 334 str 335 (attrsOf any) 336 ]); # see lib.meta.platformMatch 337 in 338 { 339 # These keys are documented 340 description = str; 341 mainProgram = str; 342 longDescription = str; 343 branch = str; 344 homepage = union [ 345 (listOf str) 346 str 347 ]; 348 downloadPage = str; 349 changelog = union [ 350 (listOf str) 351 str 352 ]; 353 license = 354 let 355 # TODO disallow `str` licenses, use a module 356 licenseType = union [ 357 (attrsOf any) 358 str 359 ]; 360 in 361 union [ 362 (listOf licenseType) 363 licenseType 364 ]; 365 sourceProvenance = listOf attrs; 366 maintainers = listOf (attrsOf any); # TODO use the maintainer type from lib/tests/maintainer-module.nix 367 teams = listOf (attrsOf any); # TODO similar to maintainers, use a teams type 368 priority = int; 369 pkgConfigModules = listOf str; 370 inherit platforms; 371 hydraPlatforms = listOf str; 372 broken = bool; 373 unfree = bool; 374 unsupported = bool; 375 insecure = bool; 376 timeout = int; 377 knownVulnerabilities = listOf str; 378 badPlatforms = platforms; 379 380 # Needed for Hydra to expose channel tarballs: 381 # https://github.com/NixOS/hydra/blob/53335323ae79ca1a42643f58e520b376898ce641/doc/manual/src/jobs.md#meta-fields 382 isHydraChannel = bool; 383 384 # Weirder stuff that doesn't appear in the documentation? 385 maxSilent = int; 386 name = str; 387 version = str; 388 tag = str; 389 executables = listOf str; 390 outputsToInstall = listOf str; 391 position = str; 392 available = any; 393 isBuildPythonPackage = platforms; 394 schedulingPriority = int; 395 isFcitxEngine = bool; 396 isIbusEngine = bool; 397 isGutenprint = bool; 398 399 # Used for the original location of the maintainer and team attributes to assist with pings. 400 maintainersPosition = any; 401 teamsPosition = any; 402 403 identifiers = attrs; 404 }; 405 406 # Map attrs directly to the verify function for performance 407 metaTypes' = mapAttrs (_: t: t.verify) metaTypes; 408 409 checkMetaAttr = 410 k: v: 411 if metaTypes ? ${k} then 412 if metaTypes'.${k} v then 413 [ ] 414 else 415 [ 416 "key 'meta.${k}' has invalid value; expected ${metaTypes.${k}.name}, got\n ${ 417 toPretty { indent = " "; } v 418 }" 419 ] 420 else 421 [ 422 "key 'meta.${k}' is unrecognized; expected one of: \n [${ 423 concatMapStringsSep ", " (x: "'${x}'") (attrNames metaTypes) 424 }]" 425 ]; 426 427 checkMeta = meta: concatMap (attr: checkMetaAttr attr meta.${attr}) (attrNames meta); 428 429 metaInvalid = 430 if config.checkMeta then 431 meta: !all (attr: metaTypes ? ${attr} && metaTypes'.${attr} meta.${attr}) (attrNames meta) 432 else 433 meta: false; 434 435 checkOutputsToInstall = 436 if config.checkMeta then 437 attrs: 438 let 439 actualOutputs = attrs.outputs or [ "out" ]; 440 in 441 any (output: !elem output actualOutputs) (attrs.meta.outputsToInstall or [ ]) 442 else 443 attrs: false; 444 445 # Check if a derivation is valid, that is whether it passes checks for 446 # e.g brokenness or license. 447 # 448 # Return { valid: "yes", "warn" or "no" } and additionally 449 # { reason: String; errormsg: String, remediation: String } if it is not valid, where 450 # reason is one of "unfree", "blocklisted", "broken", "insecure", ... 451 # !!! reason strings are hardcoded into OfBorg, make sure to keep them in sync 452 # Along with a boolean flag for each reason 453 checkValidity = 454 attrs: 455 # Check meta attribute types first, to make sure it is always called even when there are other issues 456 # Note that this is not a full type check and functions below still need to by careful about their inputs! 457 if metaInvalid (attrs.meta or { }) then 458 { 459 reason = "unknown-meta"; 460 errormsg = "has an invalid meta attrset:${ 461 concatMapStrings (x: "\n - " + x) (checkMeta attrs.meta) 462 }\n"; 463 remediation = ""; 464 } 465 466 # --- Put checks that cannot be ignored here --- 467 else if checkOutputsToInstall attrs then 468 { 469 reason = "broken-outputs"; 470 errormsg = "has invalid meta.outputsToInstall"; 471 remediation = remediateOutputsToInstall attrs; 472 } 473 474 # --- Put checks that can be ignored here --- 475 else if hasDeniedUnfreeLicense attrs && !(hasAllowlistedLicense attrs) then 476 { 477 reason = "unfree"; 478 errormsg = "has an unfree license (${showLicense attrs.meta.license})"; 479 remediation = remediate_allowlist "Unfree" (remediate_predicate "allowUnfreePredicate" attrs); 480 } 481 else if hasBlocklistedLicense attrs then 482 { 483 reason = "blocklisted"; 484 errormsg = "has a blocklisted license (${showLicense attrs.meta.license})"; 485 remediation = ""; 486 } 487 else if hasDeniedNonSourceProvenance attrs then 488 { 489 reason = "non-source"; 490 errormsg = "contains elements not built from source (${showSourceType attrs.meta.sourceProvenance})"; 491 remediation = remediate_allowlist "NonSource" (remediate_predicate "allowNonSourcePredicate" attrs); 492 } 493 else if hasDeniedBroken attrs then 494 { 495 reason = "broken"; 496 errormsg = "is marked as broken"; 497 remediation = remediate_allowlist "Broken" ""; 498 } 499 else if hasUnsupportedPlatform attrs && !allowUnsupportedSystem then 500 let 501 toPretty' = toPretty { 502 allowPrettyValues = true; 503 indent = " "; 504 }; 505 in 506 { 507 reason = "unsupported"; 508 errormsg = '' 509 is not available on the requested hostPlatform: 510 hostPlatform.system = "${hostPlatform.system}" 511 package.meta.platforms = ${toPretty' (attrs.meta.platforms or [ ])} 512 package.meta.badPlatforms = ${toPretty' (attrs.meta.badPlatforms or [ ])} 513 ''; 514 remediation = remediate_allowlist "UnsupportedSystem" ""; 515 } 516 else if hasDisallowedInsecure attrs then 517 { 518 reason = "insecure"; 519 errormsg = "is marked as insecure"; 520 remediation = remediate_insecure attrs; 521 } 522 else 523 null; 524 525 # Please also update the type in /pkgs/top-level/config.nix alongside this. 526 checkWarnings = 527 attrs: 528 if hasNoMaintainers attrs then 529 { 530 reason = "maintainerless"; 531 errormsg = "has no maintainers or teams"; 532 remediation = ""; 533 } 534 else 535 null; 536 537 # Helper functions and declarations to handle identifiers, extracted to reduce allocations 538 hasAllCPEParts = 539 cpeParts: 540 let 541 values = attrValues cpeParts; 542 in 543 (length values == 11) && !any isNull values; 544 makeCPE = 545 { 546 part, 547 vendor, 548 product, 549 version, 550 update, 551 edition, 552 sw_edition, 553 target_sw, 554 target_hw, 555 language, 556 other, 557 }: 558 "cpe:2.3:${part}:${vendor}:${product}:${version}:${update}:${edition}:${sw_edition}:${target_sw}:${target_hw}:${language}:${other}"; 559 possibleCPEPartsFuns = [ 560 (vendor: version: { 561 success = true; 562 value = cpeFullVersionWithVendor vendor version; 563 }) 564 tryCPEPatchVersionInUpdateWithVendor 565 ]; 566 567 # The meta attribute is passed in the resulting attribute set, 568 # but it's not part of the actual derivation, i.e., it's not 569 # passed to the builder and is not a dependency. But since we 570 # include it in the result, it *is* available to nix-env for queries. 571 # Example: 572 # meta = checkMeta.commonMeta { inherit validity attrs pos references; }; 573 # validity = checkMeta.assertValidity { inherit meta attrs; }; 574 commonMeta = 575 { 576 validity, 577 attrs, 578 pos ? null, 579 references ? [ ], 580 }: 581 let 582 outputs = attrs.outputs or [ "out" ]; 583 hasOutput = out: builtins.elem out outputs; 584 maintainersPosition = builtins.unsafeGetAttrPos "maintainers" (attrs.meta or { }); 585 teamsPosition = builtins.unsafeGetAttrPos "teams" (attrs.meta or { }); 586 in 587 { 588 # `name` derivation attribute includes cross-compilation cruft, 589 # is under assert, and is sanitized. 590 # Let's have a clean always accessible version here. 591 name = attrs.name or "${attrs.pname}-${attrs.version}"; 592 593 # If the packager hasn't specified `outputsToInstall`, choose a default, 594 # which is the name of `p.bin or p.out or p` along with `p.man` when 595 # present. 596 # 597 # If the packager has specified it, it will be overridden below in 598 # `// meta`. 599 # 600 # Note: This default probably shouldn't be globally configurable. 601 # Services and users should specify outputs explicitly, 602 # unless they are comfortable with this default. 603 outputsToInstall = [ 604 ( 605 if hasOutput "bin" then 606 "bin" 607 else if hasOutput "out" then 608 "out" 609 else 610 findFirst hasOutput null outputs 611 ) 612 ] 613 ++ optional (hasOutput "man") "man"; 614 615 # CI scripts look at these to determine pings. Note that we should filter nulls out of this, 616 # or nix-env complains: https://github.com/NixOS/nix/blob/2.18.8/src/nix-env/nix-env.cc#L963 617 ${if maintainersPosition == null then null else "maintainersPosition"} = maintainersPosition; 618 ${if teamsPosition == null then null else "teamsPosition"} = teamsPosition; 619 } 620 // attrs.meta or { } 621 // { 622 # Fill `meta.position` to identify the source location of the package. 623 ${if pos == null then null else "position"} = pos.file + ":" + toString pos.line; 624 625 # Maintainers should be inclusive of teams. 626 # Note that there may be external consumers of this API (repology, for instance) - 627 # if you add a new maintainer or team attribute please ensure that this expectation is still met. 628 maintainers = unique ( 629 attrs.meta.maintainers or [ ] ++ concatMap (team: team.members or [ ]) attrs.meta.teams or [ ] 630 ); 631 632 identifiers = 633 let 634 # nix-env writes a warning for each derivation that has null in its meta values, so 635 # fields without known values are removed from the result 636 defaultCPEParts = { 637 part = "a"; 638 #vendor = null; 639 ${if attrs.pname or null != null then "product" else null} = attrs.pname; 640 #version = null; 641 #update = null; 642 edition = "*"; 643 sw_edition = "*"; 644 target_sw = "*"; 645 target_hw = "*"; 646 language = "*"; 647 other = "*"; 648 }; 649 650 cpeParts = defaultCPEParts // attrs.meta.identifiers.cpeParts or { }; 651 cpe = if hasAllCPEParts cpeParts then makeCPE cpeParts else null; 652 653 possibleCPEs = 654 if cpe != null then 655 [ { inherit cpeParts cpe; } ] 656 else if attrs.meta.identifiers.cpeParts.vendor or null == null || attrs.version or null == null then 657 [ ] 658 else 659 concatMap ( 660 f: 661 let 662 result = f attrs.meta.identifiers.cpeParts.vendor attrs.version; 663 # Note that attrs.meta.identifiers.cpeParts at this point can include defaults with user overrides. 664 # Since we can't split them apart, user overrides don't apply to possibleCPEs. 665 guessedParts = cpeParts // result.value; 666 in 667 optional (result.success && hasAllCPEParts guessedParts) { 668 cpeParts = guessedParts; 669 cpe = makeCPE guessedParts; 670 } 671 ) possibleCPEPartsFuns; 672 v1 = { 673 inherit cpeParts possibleCPEs; 674 ${if cpe != null then "cpe" else null} = cpe; 675 }; 676 in 677 v1 678 // { 679 inherit v1; 680 }; 681 682 # Expose the result of the checks for everyone to see. 683 unfree = hasUnfreeLicense attrs; 684 broken = isMarkedBroken attrs; 685 unsupported = hasUnsupportedPlatform attrs; 686 insecure = isMarkedInsecure attrs; 687 688 available = 689 validity.valid != "no" 690 && ((config.checkMetaRecursively or false) -> all (d: d.meta.available or true) references); 691 }; 692 693 validYes = { 694 valid = "yes"; 695 handled = true; 696 }; 697 698 assertValidity = 699 { meta, attrs }: 700 let 701 invalid = checkValidity attrs; 702 warning = checkWarnings attrs; 703 in 704 if isNull invalid then 705 if isNull warning then 706 validYes 707 else 708 let 709 msg = 710 if inHydra then 711 "Warning while evaluating ${getNameWithVersion attrs}: «${warning.reason}»: ${warning.errormsg}" 712 else 713 "Package ${getNameWithVersion attrs} in ${pos_str meta} ${warning.errormsg}, continuing anyway." 714 + (optionalString (warning.remediation != "") "\n${warning.remediation}"); 715 716 handled = if elem warning.reason showWarnings then trace msg true else true; 717 in 718 warning 719 // { 720 valid = "warn"; 721 handled = handled; 722 } 723 else 724 let 725 msg = 726 if inHydra then 727 "Failed to evaluate ${getNameWithVersion attrs}: «${invalid.reason}»: ${invalid.errormsg}" 728 else 729 '' 730 Package ${getNameWithVersion attrs} in ${pos_str meta} ${invalid.errormsg}, refusing to evaluate. 731 732 '' 733 + invalid.remediation; 734 735 handled = if config ? handleEvalIssue then config.handleEvalIssue invalid.reason msg else throw msg; 736 in 737 invalid 738 // { 739 valid = "no"; 740 handled = handled; 741 }; 742 743in 744{ 745 inherit assertValidity commonMeta; 746}