Revert "Minor check-meta.nix optimisations and cleanups"

This commit is contained in:
K900
2025-12-14 18:01:57 +03:00
committed by GitHub
parent f1b5fcb0de
commit 0b90ed8913
+148 -125
View File
@@ -15,15 +15,15 @@ let
concatMapStrings
concatMapStringsSep
concatStrings
filter
findFirst
getName
isDerivation
length
concatMap
mutuallyExclusive
optional
optionalAttrs
optionalString
optionals
isAttrs
isString
mapAttrs
@@ -47,11 +47,6 @@ let
toPretty
;
inherit (builtins)
getEnv
trace
;
# If we're in hydra, we can dispense with the more verbose error
# messages and make problems easier to spot.
inHydra = config.inHydra or false;
@@ -62,11 +57,11 @@ let
getNameWithVersion =
attrs: attrs.name or "${attrs.pname or "«name-missing»"}-${attrs.version or "«version-missing»"}";
allowUnfree = config.allowUnfree || getEnv "NIXPKGS_ALLOW_UNFREE" == "1";
allowUnfree = config.allowUnfree || builtins.getEnv "NIXPKGS_ALLOW_UNFREE" == "1";
allowNonSource =
let
envVar = getEnv "NIXPKGS_ALLOW_NONSOURCE";
envVar = builtins.getEnv "NIXPKGS_ALLOW_NONSOURCE";
in
if envVar != "" then envVar != "0" else config.allowNonSource or true;
@@ -79,34 +74,33 @@ let
else
throw "allowlistedLicenses and blocklistedLicenses are not mutually exclusive.";
hasLicense = attrs: attrs ? meta.license;
hasListedLicense =
assert areLicenseListsValid;
list:
if list == [ ] then
attrs: false
else
attrs:
attrs ? meta.license
&& (
if isList attrs.meta.license then
any (l: elem l list) attrs.meta.license
else
elem attrs.meta.license list
);
list: attrs:
length list > 0
&& hasLicense attrs
&& (
if isList attrs.meta.license then
any (l: elem l list) attrs.meta.license
else
elem attrs.meta.license list
);
hasAllowlistedLicense = hasListedLicense allowlist;
hasAllowlistedLicense = attrs: hasListedLicense allowlist attrs;
hasBlocklistedLicense = hasListedLicense blocklist;
hasBlocklistedLicense = attrs: hasListedLicense blocklist attrs;
allowBroken = config.allowBroken || getEnv "NIXPKGS_ALLOW_BROKEN" == "1";
allowBroken = config.allowBroken || builtins.getEnv "NIXPKGS_ALLOW_BROKEN" == "1";
allowUnsupportedSystem =
config.allowUnsupportedSystem || getEnv "NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM" == "1";
config.allowUnsupportedSystem || builtins.getEnv "NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM" == "1";
isUnfree =
licenses:
if isAttrs licenses then
!(licenses.free or true)
!licenses.free or true
# TODO: Returning false in the case of a string is a bug that should be fixed.
# In a previous implementation of this function the function body
# was `licenses: lib.lists.any (l: !l.free or true) licenses;`
@@ -114,9 +108,9 @@ let
else if isString licenses then
false
else
any (l: !(l.free or true)) licenses;
any (l: !l.free or true) licenses;
hasUnfreeLicense = attrs: attrs ? meta.license && isUnfree attrs.meta.license;
hasUnfreeLicense = attrs: hasLicense attrs && isUnfree attrs.meta.license;
hasNoMaintainers =
# To get usable output, we want to avoid flagging "internal" derivations.
@@ -167,13 +161,19 @@ let
attrs: hasUnfreeLicense attrs && !allowUnfree && !allowUnfreePredicate attrs;
allowInsecureDefaultPredicate =
x: elem (getNameWithVersion x) (config.permittedInsecurePackages or [ ]);
allowInsecurePredicate = config.allowInsecurePredicate or allowInsecureDefaultPredicate;
x: builtins.elem (getNameWithVersion x) (config.permittedInsecurePackages or [ ]);
allowInsecurePredicate = x: (config.allowInsecurePredicate or allowInsecureDefaultPredicate) x;
allowInsecure = getEnv "NIXPKGS_ALLOW_INSECURE" == "1";
hasAllowedInsecure =
attrs:
!(isMarkedInsecure attrs)
|| allowInsecurePredicate attrs
|| builtins.getEnv "NIXPKGS_ALLOW_INSECURE" == "1";
hasDisallowedInsecure =
attrs: isMarkedInsecure attrs && !allowInsecure && !allowInsecurePredicate attrs;
isNonSource = sourceTypes: any (t: !t.isSource) sourceTypes;
hasNonSourceProvenance =
attrs: (attrs ? meta.sourceProvenance) && isNonSource attrs.meta.sourceProvenance;
# Allow granular checks to allow only some non-source-built packages
# Example:
@@ -188,11 +188,7 @@ let
# package has non-source provenance and is not explicitly allowed by the
# `allowNonSourcePredicate` function.
hasDeniedNonSourceProvenance =
attrs:
attrs ? meta.sourceProvenance
&& any (t: !t.isSource) attrs.meta.sourceProvenance
&& !allowNonSource
&& !allowNonSourcePredicate attrs;
attrs: hasNonSourceProvenance attrs && !allowNonSource && !allowNonSourcePredicate attrs;
showLicenseOrSourceType =
value: toString (map (v: v.shortName or v.fullName or "unknown") (toList value));
@@ -201,6 +197,17 @@ let
pos_str = meta: meta.position or "«unknown-file»";
remediation = {
unfree = remediate_allowlist "Unfree" (remediate_predicate "allowUnfreePredicate");
non-source = remediate_allowlist "NonSource" (remediate_predicate "allowNonSourcePredicate");
broken = remediate_allowlist "Broken" (x: "");
unsupported = remediate_allowlist "UnsupportedSystem" (x: "");
blocklisted = x: "";
insecure = remediate_insecure;
broken-outputs = remediateOutputsToInstall;
unknown-meta = x: "";
maintainerless = x: "";
};
remediation_env_var =
allow_attr:
{
@@ -223,7 +230,7 @@ let
Alternatively you can configure a predicate to allow specific packages:
{ nixpkgs.config.${predicateConfigAttr} = pkg: builtins.elem (lib.getName pkg) [
"${getName attrs}"
"${lib.getName attrs}"
];
}
'';
@@ -293,7 +300,7 @@ let
let
expectedOutputs = attrs.meta.outputsToInstall or [ ];
actualOutputs = attrs.outputs or [ "out" ];
missingOutputs = filter (output: !elem output actualOutputs) expectedOutputs;
missingOutputs = builtins.filter (output: !builtins.elem output actualOutputs) expectedOutputs;
in
''
The package ${getNameWithVersion attrs} has set meta.outputsToInstall to: ${builtins.concatStringsSep ", " expectedOutputs}
@@ -305,6 +312,45 @@ let
${concatStrings (map (output: " - ${output}\n") missingOutputs)}
'';
handleEvalIssue =
{ meta, attrs }:
{
reason,
errormsg ? "",
}:
let
msg =
if inHydra then
"Failed to evaluate ${getNameWithVersion attrs}: «${reason}»: ${errormsg}"
else
''
Package ${getNameWithVersion attrs} in ${pos_str meta} ${errormsg}, refusing to evaluate.
''
+ (builtins.getAttr reason remediation) attrs;
handler = if config ? handleEvalIssue then config.handleEvalIssue reason else throw;
in
handler msg;
handleEvalWarning =
{ meta, attrs }:
{
reason,
errormsg ? "",
}:
let
remediationMsg = (builtins.getAttr reason remediation) attrs;
msg =
if inHydra then
"Warning while evaluating ${getNameWithVersion attrs}: «${reason}»: ${errormsg}"
else
"Package ${getNameWithVersion attrs} in ${pos_str meta} ${errormsg}, continuing anyway."
+ (optionalString (remediationMsg != "") "\n${remediationMsg}");
isEnabled = findFirst (x: x == reason) null showWarnings;
in
if isEnabled != null then builtins.trace msg true else true;
metaTypes =
let
types = import ./meta-types.nix { inherit lib; };
@@ -400,10 +446,11 @@ let
identifiers = attrs;
};
# Map attrs directly to the verify function for performance
metaTypes' = mapAttrs (_: t: t.verify) metaTypes;
checkMetaAttr =
let
# Map attrs directly to the verify function for performance
metaTypes' = mapAttrs (_: t: t.verify) metaTypes;
in
k: v:
if metaTypes ? ${k} then
if metaTypes'.${k} v then
@@ -420,80 +467,81 @@ let
concatMapStringsSep ", " (x: "'${x}'") (attrNames metaTypes)
}]"
];
checkMeta = meta: concatMap (attr: checkMetaAttr attr meta.${attr}) (attrNames meta);
metaInvalid =
if config.checkMeta then
meta: !all (attr: metaTypes ? ${attr} && metaTypes'.${attr} meta.${attr}) (attrNames meta)
else
meta: false;
checkMeta =
meta:
optionals config.checkMeta (concatMap (attr: checkMetaAttr attr meta.${attr}) (attrNames meta));
checkOutputsToInstall =
if config.checkMeta then
attrs:
let
actualOutputs = attrs.outputs or [ "out" ];
in
any (output: !elem output actualOutputs) (attrs.meta.outputsToInstall or [ ])
else
attrs: false;
attrs:
let
expectedOutputs = attrs.meta.outputsToInstall or [ ];
actualOutputs = attrs.outputs or [ "out" ];
missingOutputs = builtins.filter (output: !builtins.elem output actualOutputs) expectedOutputs;
in
if config.checkMeta then builtins.length missingOutputs > 0 else false;
# Check if a derivation is valid, that is whether it passes checks for
# e.g brokenness or license.
#
# Return { valid: "yes", "warn" or "no" } and additionally
# { reason: String; errormsg: String, remediation: String } if it is not valid, where
# { reason: String; errormsg: String } if it is not valid, where
# reason is one of "unfree", "blocklisted", "broken", "insecure", ...
# !!! reason strings are hardcoded into OfBorg, make sure to keep them in sync
# Along with a boolean flag for each reason
checkValidity =
let
validYes = {
valid = "yes";
handled = true;
};
in
attrs:
# Check meta attribute types first, to make sure it is always called even when there are other issues
# Note that this is not a full type check and functions below still need to by careful about their inputs!
if metaInvalid (attrs.meta or { }) then
let
res = checkMeta (attrs.meta or { });
in
if res != [ ] then
{
valid = "no";
reason = "unknown-meta";
errormsg = "has an invalid meta attrset:${
concatMapStrings (x: "\n - " + x) (checkMeta attrs.meta)
}\n";
remediation = "";
errormsg = "has an invalid meta attrset:${concatMapStrings (x: "\n - " + x) res}\n";
}
# --- Put checks that cannot be ignored here ---
else if checkOutputsToInstall attrs then
{
valid = "no";
reason = "broken-outputs";
errormsg = "has invalid meta.outputsToInstall";
remediation = remediateOutputsToInstall attrs;
}
# --- Put checks that can be ignored here ---
else if hasDeniedUnfreeLicense attrs && !(hasAllowlistedLicense attrs) then
{
valid = "no";
reason = "unfree";
errormsg = "has an unfree license (${showLicense attrs.meta.license})";
remediation = remediate_allowlist "Unfree" (remediate_predicate "allowUnfreePredicate") attrs;
}
else if hasBlocklistedLicense attrs then
{
valid = "no";
reason = "blocklisted";
errormsg = "has a blocklisted license (${showLicense attrs.meta.license})";
remediation = "";
}
else if hasDeniedNonSourceProvenance attrs then
{
valid = "no";
reason = "non-source";
errormsg = "contains elements not built from source (${showSourceType attrs.meta.sourceProvenance})";
remediation = remediate_allowlist "NonSource" (remediate_predicate "allowNonSourcePredicate") attrs;
}
else if hasDeniedBroken attrs then
{
valid = "no";
reason = "broken";
errormsg = "is marked as broken";
remediation = remediate_allowlist "Broken" (x: "");
}
else if hasUnsupportedPlatform attrs && !allowUnsupportedSystem then
else if !allowUnsupportedSystem && hasUnsupportedPlatform attrs then
let
toPretty' = toPretty {
allowPrettyValues = true;
@@ -501,6 +549,7 @@ let
};
in
{
valid = "no";
reason = "unsupported";
errormsg = ''
is not available on the requested hostPlatform:
@@ -508,28 +557,25 @@ let
package.meta.platforms = ${toPretty' (attrs.meta.platforms or [ ])}
package.meta.badPlatforms = ${toPretty' (attrs.meta.badPlatforms or [ ])}
'';
remediation = remediate_allowlist "UnsupportedSystem" (x: "") attrs;
}
else if hasDisallowedInsecure attrs then
else if !(hasAllowedInsecure attrs) then
{
valid = "no";
reason = "insecure";
errormsg = "is marked as insecure";
remediation = remediate_insecure attrs;
}
else
null;
# Please also update the type in /pkgs/top-level/config.nix alongside this.
checkWarnings =
attrs:
if hasNoMaintainers attrs then
# --- warnings ---
# Please also update the type in /pkgs/top-level/config.nix alongside this.
else if hasNoMaintainers attrs then
{
valid = "warn";
reason = "maintainerless";
errormsg = "has no maintainers or teams";
remediation = "";
}
# -----
else
null;
validYes;
# Helper functions and declarations to handle identifiers, extracted to reduce allocations
hasAllCPEParts =
@@ -684,57 +730,34 @@ let
available =
validity.valid != "no"
&& ((config.checkMetaRecursively or false) -> all (d: d.meta.available or true) references);
&& (
if config.checkMetaRecursively or false then all (d: d.meta.available or true) references else true
);
};
validYes = {
valid = "yes";
handled = true;
};
assertValidity =
{ meta, attrs }:
let
invalid = checkValidity attrs;
warning = checkWarnings attrs;
validity = checkValidity attrs;
inherit (validity) valid;
in
if isNull invalid then
if isNull warning then
validYes
else
let
msg =
if inHydra then
"Warning while evaluating ${getNameWithVersion attrs}: «${warning.reason}»: ${warning.errormsg}"
else
"Package ${getNameWithVersion attrs} in ${pos_str meta} ${warning.errormsg}, continuing anyway."
+ (optionalString (warning.remediation != "") "\n${warning.remediation}");
handled = if elem warning.reason showWarnings then trace msg true else true;
in
warning
// {
valid = "warn";
handled = handled;
}
if validity ? handled then
validity
else
let
msg =
if inHydra then
"Failed to evaluate ${getNameWithVersion attrs}: «${invalid.reason}»: ${invalid.errormsg}"
else
''
Package ${getNameWithVersion attrs} in ${pos_str meta} ${invalid.errormsg}, refusing to evaluate.
''
+ invalid.remediation;
handled = if config ? handleEvalIssue then config.handleEvalIssue invalid.reason msg else throw msg;
in
invalid
validity
// {
valid = "no";
handled = handled;
# Throw an error if trying to evaluate a non-valid derivation
# or, alternatively, just output a warning message.
handled = (
if valid == "yes" then
true
else if valid == "no" then
(handleEvalIssue { inherit meta attrs; } { inherit (validity) reason errormsg; })
else if valid == "warn" then
(handleEvalWarning { inherit meta attrs; } { inherit (validity) reason errormsg; })
else
throw "Unknown validity: '${valid}'"
);
};
in