mirror of
https://github.com/nix-community/nixvim.git
synced 2025-06-20 16:15:43 +02:00
docs: eval modules without access to pkgs
Replace the `package-options` test with a stricter implementation. When evaluating modules for use in the docs, provide them with a stubbed `pkgs` instance that throws an error whenever a package is evaluated. This ensures we don't accidentally use any packages in defaults or examples.
This commit is contained in:
parent
0b4a4e8327
commit
d7df583211
3 changed files with 51 additions and 96 deletions
|
@ -9,6 +9,56 @@ let
|
|||
pkgs = import ./pkgs.nix { inherit system nixpkgs; };
|
||||
inherit (pkgs) lib;
|
||||
|
||||
# A stub pkgs instance used while evaluating the nixvim modules for the docs
|
||||
# If any non-meta attr is accessed, the eval will throw
|
||||
noPkgs =
|
||||
let
|
||||
# Known suffixes for package sets
|
||||
suffixes = [
|
||||
"Plugins"
|
||||
"Packages"
|
||||
];
|
||||
|
||||
# Predicate for whether an attr name looks like a package set
|
||||
# Determines whether stubPackage should recurse
|
||||
isPackageSet = name: builtins.any (lib.flip lib.strings.hasSuffix name) suffixes;
|
||||
|
||||
# Need to retain `meta.homepage` if present
|
||||
stubPackage =
|
||||
prefix: name: package:
|
||||
let
|
||||
loc = prefix ++ [ name ];
|
||||
in
|
||||
if isPackageSet name then
|
||||
lib.mapAttrs (stubPackage loc) package
|
||||
else
|
||||
lib.mapAttrs (_: throwAccessError loc) package
|
||||
// lib.optionalAttrs (package ? meta) { inherit (package) meta; };
|
||||
|
||||
throwAccessError =
|
||||
loc:
|
||||
throw "Attempted to access `${
|
||||
lib.concatStringsSep "." ([ "pkgs" ] ++ loc)
|
||||
}` while rendering the docs.";
|
||||
in
|
||||
lib.fix (
|
||||
self:
|
||||
lib.mapAttrs (stubPackage [ ]) pkgs
|
||||
// {
|
||||
pkgs = self;
|
||||
# The following pkgs attrs are required to eval nixvim, even for the docs:
|
||||
inherit (pkgs)
|
||||
_type
|
||||
stdenv
|
||||
stdenvNoCC
|
||||
symlinkJoin
|
||||
runCommand
|
||||
runCommandLocal
|
||||
writeShellApplication
|
||||
;
|
||||
}
|
||||
);
|
||||
|
||||
nixvimPath = toString ./..;
|
||||
|
||||
gitHubDeclaration = user: repo: branch: subpath: {
|
||||
|
@ -37,7 +87,7 @@ let
|
|||
modules = [
|
||||
{
|
||||
isDocs = true;
|
||||
nixpkgs.pkgs = pkgs;
|
||||
_module.args.pkgs = lib.mkForce noPkgs;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
|
|
@ -44,7 +44,6 @@ in
|
|||
nixpkgs-module = callTest ./nixpkgs-module.nix { };
|
||||
plugins-by-name = callTest ./plugins-by-name.nix { };
|
||||
generated = callTest ./generated.nix { };
|
||||
package-options = callTest ./package-options.nix { };
|
||||
lsp-all-servers = callTest ./lsp-servers.nix { };
|
||||
}
|
||||
# Expose some tests from the docs as flake-checks too
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
# This test ensures "package" options use a "literalExpression" in their defaultText
|
||||
# I.e. it validates `lib.mkPackageOption` was used to build the package options.
|
||||
{
|
||||
nixvimConfiguration,
|
||||
lib,
|
||||
runCommandLocal,
|
||||
}:
|
||||
let
|
||||
inherit (builtins)
|
||||
filter
|
||||
head
|
||||
map
|
||||
match
|
||||
;
|
||||
inherit (lib.strings) concatMapStringsSep removePrefix removeSuffix;
|
||||
inherit (lib.attrsets) isDerivation;
|
||||
inherit (lib.options)
|
||||
isOption
|
||||
renderOptionValue
|
||||
showOption
|
||||
;
|
||||
|
||||
# This doesn't collect any submodule sub-options,
|
||||
# but that's fine since most of our "package" options are in the top level module eval
|
||||
options = lib.collect isOption nixvimConfiguration.options;
|
||||
|
||||
# All visible non-sub options that default to a derivation
|
||||
drvOptions = filter (
|
||||
{
|
||||
default ? null,
|
||||
visible ? true,
|
||||
internal ? false,
|
||||
...
|
||||
}:
|
||||
let
|
||||
# Some options have defaults that throw when evaluated
|
||||
default' = (builtins.tryEval default).value;
|
||||
in
|
||||
visible && !internal && isDerivation default'
|
||||
) options;
|
||||
|
||||
# Bad options do not use `literalExpression` in their `defaultText`,
|
||||
# or have a `defaultText` that doesn't start with "pkgs."
|
||||
badOptions = filter (
|
||||
opt:
|
||||
opt.defaultText._type or null != "literalExpression"
|
||||
|| match ''pkgs[.].*'' (opt.defaultText.text or "") == null
|
||||
) drvOptions;
|
||||
in
|
||||
runCommandLocal "validate-package-options"
|
||||
{
|
||||
# Use structuredAttrs to avoid "Argument List Too Long" errors
|
||||
# and get proper bash array support.
|
||||
__structuredAttrs = true;
|
||||
|
||||
# Passthroughs for debugging purposes
|
||||
passthru = {
|
||||
inherit nixvimConfiguration drvOptions badOptions;
|
||||
};
|
||||
|
||||
# Error strings to print
|
||||
errors =
|
||||
let
|
||||
# A little hack to get the flake's source in the nix store
|
||||
# We will use this to make the option declaration sources more readable
|
||||
src = removeSuffix "modules/top-level/output.nix" (
|
||||
head nixvimConfiguration.options.package.declarations
|
||||
);
|
||||
in
|
||||
map (
|
||||
opt:
|
||||
let
|
||||
# The default, as rendered in documentation. Will always be a literalExpression.
|
||||
default = builtins.addErrorContext "while evaluating the default text for `${showOption opt.loc}`" (
|
||||
renderOptionValue (opt.defaultText or opt.default)
|
||||
);
|
||||
in
|
||||
''
|
||||
- ${showOption opt.loc} (${default.text}), declared in:
|
||||
${concatMapStringsSep "\n" (file: " - ${removePrefix src file}") opt.declarations}
|
||||
''
|
||||
) badOptions;
|
||||
}
|
||||
''
|
||||
if [ -n "$errors" ]; then
|
||||
echo "Found ''${#errors[@]} errors:"
|
||||
for err in "''${errors[@]}"; do
|
||||
echo "$err"
|
||||
done
|
||||
echo "(''${#errors[@]} options with errors)"
|
||||
exit 1
|
||||
fi
|
||||
touch $out
|
||||
''
|
Loading…
Add table
Add a link
Reference in a new issue