Revert "Minor check-meta.nix optimisations and cleanups"
This commit is contained in:
+148
-125
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user