- Enforce that an option declaration has a "defaultText" if and only if the type of the option derives from "package", "packageSet" or "nixpkgsConfig" and if a "default" attribute is defined. - Enforce that the value of the "example" attribute is wrapped with "literalExample" if the type of the option derives from "package", "packageSet" or "nixpkgsConfig". - Warn if a "defaultText" is defined in an option declaration if the type of the option does not derive from "package", "packageSet" or "nixpkgsConfig". - Warn if no "type" is defined in an option declaration.wip/yesman
parent
c483224c82
commit
cad8957eab
@ -0,0 +1,91 @@ |
||||
{ config, lib, pkgs, baseModules, ... }: |
||||
|
||||
with pkgs; |
||||
with pkgs.lib; |
||||
|
||||
let |
||||
|
||||
optionsSpecs = inferenceMode: |
||||
let |
||||
versionModule = |
||||
{ system.nixosVersionSuffix = config.system.nixosVersionSuffix; |
||||
system.nixosRevision = config.system.nixosRevision; |
||||
nixpkgs.system = config.nixpkgs.system; |
||||
}; |
||||
|
||||
internalModule = { _module = config._module; } // (if isNull inferenceMode then {} else { _module.typeInference = mkForce inferenceMode; }); |
||||
|
||||
eval = evalModules { |
||||
modules = [ versionModule ] ++ baseModules ++ [ internalModule ]; |
||||
args = (config._module.args) // { modules = [ ]; }; |
||||
}; |
||||
|
||||
# Remove invisible and internal options. |
||||
optionsSpecs' = filter (opt: opt.visible && !opt.internal) (optionAttrSetToParseableSpecifications config._module eval.options); |
||||
|
||||
# INFO: Please add 'defaultText' or 'literalExample' to the option |
||||
# definition to avoid this exception! |
||||
substFunction = key: decls: x: |
||||
if builtins.isAttrs x then mapAttrs (name: substFunction key decls) x |
||||
else if builtins.isList x then map (substFunction key decls) x |
||||
else if builtins.isFunction x then throw "Found an unexpected <function> in ${key} declared in ${concatStringsSep " and " decls}." |
||||
else x; |
||||
|
||||
prefix = toString ../..; |
||||
|
||||
stripPrefix = fn: |
||||
if substring 0 (stringLength prefix) fn == prefix then |
||||
substring (stringLength prefix + 1) 1000 fn |
||||
else |
||||
fn; |
||||
|
||||
# Clean up declaration sites to not refer to the NixOS source tree. |
||||
cleanupOptions = x: flip map x (opt: |
||||
let substFunction' = y: substFunction opt.name opt.declarations y; |
||||
in opt |
||||
// { declarations = map (fn: stripPrefix fn) opt.declarations; } |
||||
// optionalAttrs (opt ? example) { example = substFunction' opt.example; } |
||||
// optionalAttrs (opt ? default) { default = substFunction' opt.default; } |
||||
// optionalAttrs (opt ? type) { type = substFunction' opt.type; }); |
||||
|
||||
in |
||||
cleanupOptions optionsSpecs'; |
||||
|
||||
in |
||||
|
||||
{ |
||||
|
||||
system.build.typechecker = { |
||||
|
||||
# The NixOS options as machine readable specifications in JSON format. |
||||
specifications = stdenv.mkDerivation { |
||||
name = "options-specs-json"; |
||||
|
||||
buildCommand = '' |
||||
# Export list of options in different format. |
||||
dst=$out/share/doc/nixos |
||||
mkdir -p $dst |
||||
|
||||
cp ${builtins.toFile "options.json" (builtins.unsafeDiscardStringContext (builtins.toJSON |
||||
(listToAttrs (map (o: { name = o.name; value = removeAttrs o ["name" "visible" "internal"]; }) (optionsSpecs null))))) |
||||
} $dst/options-specs.json |
||||
|
||||
mkdir -p $out/nix-support |
||||
echo "file json $dst/options-specs.json" >> $out/nix-support/hydra-build-products |
||||
''; # */ |
||||
|
||||
meta.description = "List of NixOS options specifications in JSON format"; |
||||
}; |
||||
|
||||
silent = listToAttrs (map (o: { name = o.name; value = removeAttrs o ["name" "visible" "internal"]; }) (optionsSpecs "silent")); |
||||
printAll = listToAttrs (map (o: { name = o.name; value = removeAttrs o ["name" "visible" "internal"]; }) (optionsSpecs "printAll")); |
||||
printUnspecified = listToAttrs (map (o: { name = o.name; value = removeAttrs o ["name" "visible" "internal"]; }) (optionsSpecs "printUnspecified")); |
||||
|
||||
}; |
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,52 @@ |
||||
#! /bin/sh |
||||
#! @shell@ |
||||
|
||||
if [ -x "@shell@" ]; then export SHELL="@shell@"; fi; |
||||
|
||||
set -e |
||||
|
||||
showSyntax() { |
||||
cat >&1 << EOF |
||||
nixos-typecheck |
||||
usage: |
||||
nixos-typecheck [action] [args] |
||||
where: |
||||
action = silent | printAll | printUnspecified | getSpecs |
||||
with default action: printUnspecified |
||||
args = any argument supported by nix-build |
||||
EOF |
||||
} |
||||
|
||||
|
||||
# Parse the command line. |
||||
extraArgs=() |
||||
action=printUnspecified |
||||
|
||||
while [ "$#" -gt 0 ]; do |
||||
i="$1"; shift 1 |
||||
case "$i" in |
||||
--help) |
||||
showSyntax |
||||
;; |
||||
silent|printAll|printUnspecified|getSpecs) |
||||
action="$i" |
||||
;; |
||||
*) |
||||
extraArgs="$extraArgs $i" |
||||
;; |
||||
esac |
||||
done |
||||
|
||||
|
||||
if [ "$action" = silent ]; then |
||||
nix-build --no-out-link '<nixpkgs/nixos>' -A typechecker.silent $extraArgs |
||||
elif [ "$action" = printAll ]; then |
||||
nix-build --no-out-link '<nixpkgs/nixos>' -A typechecker.printAll $extraArgs |
||||
elif [ "$action" = printUnspecified ]; then |
||||
nix-build --no-out-link '<nixpkgs/nixos>' -A typechecker.printUnspecified $extraArgs |
||||
elif [ "$action" = getSpecs ]; then |
||||
ln -s $(nix-build --no-out-link '<nixpkgs/nixos>' -A typechecker.specifications $extraArgs)/share/doc/nixos/options-specs.json specifications.json |
||||
else |
||||
showSyntax |
||||
exit 1 |
||||
fi |
Loading…
Reference in new issue