{ lib, runCommandLocal, pkgs, }: let # Format a list of errors with an error message and trailing newline describeErrors = desc: errors: lib.optionals (errors != [ ]) (lib.toList desc ++ lib.map (v: "- ${v}") errors ++ [ "" ]); # Build error messages for the given declared & generated names checkDeclarations = { # The plugin's name name, # A list of package paths declared in declarationFile # A path can be either a single string, or a list; as expected by `mkPackageOption` packages, # A list of names declared in declarationFile declared, # A list of names generated by generate-files generated, # The filename where names are declared (used in error messages) declarationFile, }: let missingFromPkgs = builtins.concatMap ( loc: lib.optional (!lib.hasAttrByPath loc pkgs) (lib.concatStringsSep "." loc) ) (builtins.map lib.toList packages); undeclared = lib.filter (name: !(lib.elem name declared)) generated; uselesslyDeclared = lib.filter (name: !(lib.elem name generated)) declared; in describeErrors "${name}: The following are not found in `pkgs`, but are declared in ${declarationFile}:" missingFromPkgs ++ describeErrors "${name}: The following are not declared in ${declarationFile}:" undeclared ++ describeErrors "${name}: The following are not listed upstream, but are declared in ${declarationFile}:" uselesslyDeclared; # The error message provided to the derivation. # The test fails if this is non-empty. errors = lib.concatStringsSep "\n" ( checkDeclarations ( let inherit (import ../plugins/lsp/lsp-packages.nix) unpackaged packages customCmd; in { name = "lsp"; declarationFile = "plugins/lsp/lsp-packages.nix"; packages = builtins.attrValues packages; declared = unpackaged ++ lib.attrsets.attrNames (packages // customCmd); generated = lib.pipe ../generated/lspconfig-servers.json [ lib.importJSON (builtins.map (lib.getAttr "name")) lib.lists.unique ]; } ) ++ checkDeclarations ( let inherit (import ../plugins/by-name/none-ls/packages.nix lib) noPackage packaged; in { name = "none-ls"; declarationFile = "plugins/by-name/none-ls/packages.nix"; packages = builtins.filter (pkg: pkg != null) (builtins.attrValues packaged); declared = noPackage ++ lib.attrsets.attrNames packaged; generated = lib.pipe ../generated/none-ls.nix [ import lib.attrsets.attrValues lib.lists.concatLists lib.lists.unique ]; } ) ++ checkDeclarations ( let inherit (import ../plugins/by-name/efmls-configs/packages.nix lib) packaged unpackaged; in { name = "efmls"; declarationFile = "plugins/by-name/efmls-configs/packages.nix"; packages = builtins.attrValues packaged; declared = unpackaged ++ lib.attrsets.attrNames packaged; generated = lib.pipe ../generated/efmls-configs.nix [ import lib.attrsets.attrValues (lib.map ({ linter, formatter }: linter.possible ++ formatter.possible)) lib.lists.concatLists lib.lists.unique ]; } ) ); in runCommandLocal "generated-sources-test" { __structuredAttrs = true; inherit errors; } '' if [ -n "$errors" ]; then echo -n "$errors" exit 1 fi touch "$out" ''