|
| 1 | +# This test ensures "package" options use a "literalExpression" in their defaultText |
| 2 | +# I.e. it validates `lib.mkPackageOption` was used to build the package options. |
| 3 | +{ |
| 4 | + evaluatedNixvim, |
| 5 | + lib, |
| 6 | + runCommandNoCCLocal, |
| 7 | +}: |
| 8 | +let |
| 9 | + inherit (builtins) |
| 10 | + filter |
| 11 | + head |
| 12 | + map |
| 13 | + match |
| 14 | + ; |
| 15 | + inherit (lib.strings) concatMapStringsSep removePrefix removeSuffix; |
| 16 | + inherit (lib.attrsets) isDerivation; |
| 17 | + inherit (lib.options) |
| 18 | + isOption |
| 19 | + renderOptionValue |
| 20 | + showOption |
| 21 | + ; |
| 22 | + |
| 23 | + # This doesn't collect any submodule sub-options, |
| 24 | + # but that's fine since most of our "package" options are in the top level module eval |
| 25 | + options = lib.collect isOption evaluatedNixvim.options; |
| 26 | + |
| 27 | + # All visible non-sub options that default to a derivation |
| 28 | + drvOptions = filter ( |
| 29 | + { |
| 30 | + default ? null, |
| 31 | + visible ? true, |
| 32 | + internal ? false, |
| 33 | + ... |
| 34 | + }: |
| 35 | + visible && !internal && isDerivation default |
| 36 | + ) options; |
| 37 | + |
| 38 | + # Bad options do not use `literalExpression` in their `defaultText`, |
| 39 | + # or have a `defaultText` that doesn't start with "pkgs." |
| 40 | + badOptions = filter ( |
| 41 | + opt: |
| 42 | + opt.defaultText._type or null != "literalExpression" |
| 43 | + || match ''pkgs[.].*'' (opt.defaultText.text or "") == null |
| 44 | + ) drvOptions; |
| 45 | +in |
| 46 | +runCommandNoCCLocal "validate-package-options" |
| 47 | + { |
| 48 | + # Use structuredAttrs to avoid "Argument List Too Long" errors |
| 49 | + # and get proper bash array support. |
| 50 | + __structuredAttrs = true; |
| 51 | + |
| 52 | + # Passthroughs for debugging purposes |
| 53 | + passthru = { |
| 54 | + inherit evaluatedNixvim drvOptions badOptions; |
| 55 | + }; |
| 56 | + |
| 57 | + # Error strings to print |
| 58 | + errors = |
| 59 | + let |
| 60 | + # A little hack to get the flake's source in the nix store |
| 61 | + # We will use this to make the option declaration sources more readable |
| 62 | + src = removeSuffix "modules/top-level/output.nix" ( |
| 63 | + head evaluatedNixvim.options.package.declarations |
| 64 | + ); |
| 65 | + in |
| 66 | + map ( |
| 67 | + opt: |
| 68 | + let |
| 69 | + # The default, as rendered in documentation. Will always be a literalExpression. |
| 70 | + default = builtins.addErrorContext "while evaluating the default text for `${showOption opt.loc}`" ( |
| 71 | + renderOptionValue (opt.defaultText or opt.default) |
| 72 | + ); |
| 73 | + in |
| 74 | + '' |
| 75 | + - ${showOption opt.loc} (${default.text}), declared in: |
| 76 | + ${concatMapStringsSep "\n" (file: " - ${removePrefix src file}") opt.declarations} |
| 77 | + '' |
| 78 | + ) badOptions; |
| 79 | + } |
| 80 | + '' |
| 81 | + if [ -n "$errors" ]; then |
| 82 | + echo "Found ''${#errors[@]} errors:" |
| 83 | + for err in "''${errors[@]}"; do |
| 84 | + echo "$err" |
| 85 | + done |
| 86 | + echo "(''${#errors[@]} options with errors)" |
| 87 | + exit 1 |
| 88 | + fi |
| 89 | + touch $out |
| 90 | + '' |
0 commit comments