Add setFunctionArgs lib function.

Among other things, this will allow *2nix tools to output plain data
while still being composable with the traditional
callPackage/.override interfaces.
This commit is contained in:
Shea Levy 2018-01-31 14:02:19 -05:00
parent 0d7a0d7572
commit 943592f698
No known key found for this signature in database
GPG key ID: 5C0BD6957D86FE27
18 changed files with 60 additions and 33 deletions

View file

@ -1,7 +1,7 @@
{ lib }:
let
inherit (builtins) attrNames isFunction;
inherit (builtins) attrNames;
in
@ -72,7 +72,7 @@ rec {
makeOverridable = f: origArgs:
let
ff = f origArgs;
overrideWith = newArgs: origArgs // (if builtins.isFunction newArgs then newArgs origArgs else newArgs);
overrideWith = newArgs: origArgs // (if lib.isFunction newArgs then newArgs origArgs else newArgs);
in
if builtins.isAttrs ff then (ff // {
override = newArgs: makeOverridable f (overrideWith newArgs);
@ -81,7 +81,7 @@ rec {
${if ff ? overrideAttrs then "overrideAttrs" else null} = fdrv:
makeOverridable (args: (f args).overrideAttrs fdrv) origArgs;
})
else if builtins.isFunction ff then {
else if lib.isFunction ff then {
override = newArgs: makeOverridable f (overrideWith newArgs);
__functor = self: ff;
overrideDerivation = throw "overrideDerivation not yet supported for functors";
@ -112,8 +112,8 @@ rec {
*/
callPackageWith = autoArgs: fn: args:
let
f = if builtins.isFunction fn then fn else import fn;
auto = builtins.intersectAttrs (builtins.functionArgs f) autoArgs;
f = if lib.isFunction fn then fn else import fn;
auto = builtins.intersectAttrs (lib.functionArgs f) autoArgs;
in makeOverridable f (auto // args);
@ -122,8 +122,8 @@ rec {
individual attributes. */
callPackagesWith = autoArgs: fn: args:
let
f = if builtins.isFunction fn then fn else import fn;
auto = builtins.intersectAttrs (builtins.functionArgs f) autoArgs;
f = if lib.isFunction fn then fn else import fn;
auto = builtins.intersectAttrs (lib.functionArgs f) autoArgs;
origArgs = auto // args;
pkgs = f origArgs;
mkAttrOverridable = name: pkg: makeOverridable (newArgs: (f newArgs).${name}) origArgs;

View file

@ -2,10 +2,10 @@
let
inherit (builtins) trace attrNamesToStr isAttrs isFunction isList isInt
inherit (builtins) trace attrNamesToStr isAttrs isList isInt
isString isBool head substring attrNames;
inherit (lib) all id mapAttrsFlatten elem;
inherit (lib) all id mapAttrsFlatten elem isFunction;
in

View file

@ -51,12 +51,12 @@ let
inherit (builtins) add addErrorContext attrNames
concatLists deepSeq elem elemAt filter genericClosure genList
getAttr hasAttr head isAttrs isBool isFunction isInt isList
getAttr hasAttr head isAttrs isBool isInt isList
isString length lessThan listToAttrs pathExists readFile
replaceStrings seq stringLength sub substring tail;
inherit (trivial) id const concat or and boolToString mergeAttrs
flip mapNullable inNixShell min max importJSON warn info
nixpkgsVersion mod;
nixpkgsVersion mod functionArgs setFunctionArgs isFunction;
inherit (fixedPoints) fix fix' extends composeExtensions
makeExtensible makeExtensibleWithCustomName;

View file

@ -1,6 +1,6 @@
{ lib }:
let
inherit (builtins) isFunction head tail isList isAttrs isInt attrNames;
inherit (builtins) head tail isList isAttrs isInt attrNames;
in
@ -53,7 +53,7 @@ rec {
f: # the function applied to the arguments
initial: # you pass attrs, the functions below are passing a function taking the fix argument
let
takeFixed = if isFunction initial then initial else (fixed : initial); # transform initial to an expression always taking the fixed argument
takeFixed = if lib.isFunction initial then initial else (fixed : initial); # transform initial to an expression always taking the fixed argument
tidy = args:
let # apply all functions given in "applyPreTidy" in sequence
applyPreTidyFun = fold ( n: a: x: n ( a x ) ) lib.id (maybeAttr "applyPreTidy" [] args);
@ -63,7 +63,7 @@ rec {
let args = takeFixed fixed;
mergeFun = args.${n};
in if isAttrs x then (mergeFun args x)
else assert isFunction x;
else assert lib.isFunction x;
mergeFun args (x ( args // { inherit fixed; }));
in overridableDelayableArgs f newArgs;
in
@ -374,7 +374,7 @@ rec {
if isAttrs x then
if x ? outPath then "derivation"
else "attrs"
else if isFunction x then "function"
else if lib.isFunction x then "function"
else if isList x then "list"
else if x == true then "bool"
else if x == false then "bool"

View file

@ -14,6 +14,8 @@ let
libAttr = lib.attrsets;
flipMapAttrs = flip libAttr.mapAttrs;
inherit (lib) isFunction;
in
rec {
@ -110,7 +112,7 @@ rec {
else if isString v then "\"" + v + "\""
else if null == v then "null"
else if isFunction v then
let fna = functionArgs v;
let fna = lib.functionArgs v;
showFnas = concatStringsSep "," (libAttr.mapAttrsToList
(name: hasDefVal: if hasDefVal then "(${name})" else name)
fna);

View file

@ -155,7 +155,7 @@ rec {
# a module will resolve strictly the attributes used as argument but
# not their values. The values are forwarding the result of the
# evaluation of the option.
requiredArgs = builtins.attrNames (builtins.functionArgs f);
requiredArgs = builtins.attrNames (lib.functionArgs f);
context = name: ''while evaluating the module argument `${name}' in "${key}":'';
extraArgs = builtins.listToAttrs (map (name: {
inherit name;

View file

@ -52,7 +52,7 @@ rec {
# Pull in some builtins not included elsewhere.
inherit (builtins)
pathExists readFile isBool isFunction
pathExists readFile isBool
isInt add sub lessThan
seq deepSeq genericClosure;
@ -99,4 +99,29 @@ rec {
*/
warn = msg: builtins.trace "WARNING: ${msg}";
info = msg: builtins.trace "INFO: ${msg}";
# | Add metadata about expected function arguments to a function.
# The metadata should match the format given by
# builtins.functionArgs, i.e. a set from expected argument to a bool
# representing whether that argument has a default or not.
# setFunctionArgs : (a → b) → Map String Bool → (a → b)
#
# This function is necessary because you can't dynamically create a
# function of the { a, b ? foo, ... }: format, but some facilities
# like callPackage expect to be able to query expected arguments.
setFunctionArgs = f: args:
{ # TODO: Should we add call-time "type" checking like built in?
__functor = self: f;
__functionArgs = args;
};
# | Extract the expected function arguments from a function.
# This works both with nix-native { a, b ? foo, ... }: style
# functions and functions with args set with 'setFunctionArgs'. It
# has the same return type and semantics as builtins.functionArgs.
# setFunctionArgs : (a → b) → Map String Bool.
functionArgs = f: f.__functionArgs or (builtins.functionArgs f);
isFunction = f: builtins.isFunction f ||
(f ? __functor && isFunction (f.__functor f));
}

View file

@ -12,7 +12,7 @@ let
substFunction = x:
if builtins.isAttrs x then lib.mapAttrs (name: substFunction) x
else if builtins.isList x then map substFunction x
else if builtins.isFunction x then "<function>"
else if lib.isFunction x then "<function>"
else x;
# Clean up declaration sites to not refer to the NixOS source tree.

View file

@ -85,7 +85,7 @@ rec {
testScript' =
# Call the test script with the computed nodes.
if builtins.isFunction testScript
if lib.isFunction testScript
then testScript { inherit nodes; }
else testScript;

View file

@ -4,10 +4,10 @@ with lib;
let
isConfig = x:
builtins.isAttrs x || builtins.isFunction x;
builtins.isAttrs x || lib.isFunction x;
optCall = f: x:
if builtins.isFunction f
if lib.isFunction f
then f x
else f;
@ -38,7 +38,7 @@ let
overlayType = mkOptionType {
name = "nixpkgs-overlay";
description = "nixpkgs overlay";
check = builtins.isFunction;
check = lib.isFunction;
merge = lib.mergeOneOption;
};

View file

@ -17,7 +17,7 @@ let
# you should use files).
moduleFiles =
# FIXME: use typeOf (Nix 1.6.1).
filter (x: !isAttrs x && !builtins.isFunction x) modules;
filter (x: !isAttrs x && !lib.isFunction x) modules;
# Partition module files because between NixOS and non-NixOS files. NixOS
# files may change if the repository is updated.

View file

@ -2,4 +2,4 @@ f: { system ? builtins.currentSystem, ... } @ args:
with import ../lib/testing.nix { inherit system; };
makeTest (if builtins.isFunction f then f (args // { inherit pkgs; inherit (pkgs) lib; }) else f)
makeTest (if lib.isFunction f then f (args // { inherit pkgs; inherit (pkgs) lib; }) else f)

View file

@ -40,7 +40,7 @@ packagesFun: # packages explicitly requested by the user
let
explicitRequires =
if builtins.isFunction packagesFun
if lib.isFunction packagesFun
then packagesFun self
else packagesFun;
in

View file

@ -6,8 +6,8 @@ rec {
*/
callPackageWith = autoArgs: fn: args:
let
f = if builtins.isFunction fn then fn else import fn;
auto = builtins.intersectAttrs (builtins.functionArgs f) autoArgs;
f = if pkgs.lib.isFunction fn then fn else import fn;
auto = builtins.intersectAttrs (stdenv.lib.functionArgs f) autoArgs;
in f (auto // args);
callPackage = callPackageWith pkgs;

View file

@ -81,8 +81,8 @@ let
# lost on `.override`) but determine the auto-args based on `drv` (the problem here
# is that nix has no way to "passthrough" args while preserving the reflection
# info that callPackage uses to determine the arguments).
drv = if builtins.isFunction fn then fn else import fn;
auto = builtins.intersectAttrs (builtins.functionArgs drv) scope;
drv = if stdenv.lib.isFunction fn then fn else import fn;
auto = builtins.intersectAttrs (stdenv.lib.functionArgs drv) scope;
# this wraps the `drv` function to add a `overrideScope` function to the result.
drvScope = allArgs: drv allArgs // {

View file

@ -186,7 +186,7 @@ let
# There should be an IOVideo here, but they haven't released it :(
};
IOKitSrcs = stdenv.lib.mapAttrs (name: value: if builtins.isFunction value then value name else value) IOKitSpecs;
IOKitSrcs = stdenv.lib.mapAttrs (name: value: if stdenv.lib.isFunction value then value name else value) IOKitSpecs;
adv_cmds = applePackage "adv_cmds" "osx-10.5.8" "102ssayxbg9wb35mdmhswbnw0bg7js3pfd8fcbic83c5q3bqa6c6" {};

View file

@ -49,7 +49,7 @@ in let
# { /* the config */ } and
# { pkgs, ... } : { /* the config */ }
config =
if builtins.isFunction configExpr
if lib.isFunction configExpr
then configExpr { inherit pkgs; }
else configExpr;

View file

@ -40,7 +40,7 @@ let
makeOverridablePythonPackage = f: origArgs:
let
ff = f origArgs;
overrideWith = newArgs: origArgs // (if builtins.isFunction newArgs then newArgs origArgs else newArgs);
overrideWith = newArgs: origArgs // (if pkgs.lib.isFunction newArgs then newArgs origArgs else newArgs);
in
if builtins.isAttrs ff then (ff // {
overridePythonAttrs = newArgs: makeOverridablePythonPackage f (overrideWith newArgs);