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; };
|
pkgs = import ./pkgs.nix { inherit system nixpkgs; };
|
||||||
inherit (pkgs) lib;
|
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 ./..;
|
nixvimPath = toString ./..;
|
||||||
|
|
||||||
gitHubDeclaration = user: repo: branch: subpath: {
|
gitHubDeclaration = user: repo: branch: subpath: {
|
||||||
|
@ -37,7 +87,7 @@ let
|
||||||
modules = [
|
modules = [
|
||||||
{
|
{
|
||||||
isDocs = true;
|
isDocs = true;
|
||||||
nixpkgs.pkgs = pkgs;
|
_module.args.pkgs = lib.mkForce noPkgs;
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
|
@ -44,7 +44,6 @@ in
|
||||||
nixpkgs-module = callTest ./nixpkgs-module.nix { };
|
nixpkgs-module = callTest ./nixpkgs-module.nix { };
|
||||||
plugins-by-name = callTest ./plugins-by-name.nix { };
|
plugins-by-name = callTest ./plugins-by-name.nix { };
|
||||||
generated = callTest ./generated.nix { };
|
generated = callTest ./generated.nix { };
|
||||||
package-options = callTest ./package-options.nix { };
|
|
||||||
lsp-all-servers = callTest ./lsp-servers.nix { };
|
lsp-all-servers = callTest ./lsp-servers.nix { };
|
||||||
}
|
}
|
||||||
# Expose some tests from the docs as flake-checks too
|
# 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