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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -52,7 +52,7 @@ rec {
# Pull in some builtins not included elsewhere. # Pull in some builtins not included elsewhere.
inherit (builtins) inherit (builtins)
pathExists readFile isBool isFunction pathExists readFile isBool
isInt add sub lessThan isInt add sub lessThan
seq deepSeq genericClosure; seq deepSeq genericClosure;
@ -99,4 +99,29 @@ rec {
*/ */
warn = msg: builtins.trace "WARNING: ${msg}"; warn = msg: builtins.trace "WARNING: ${msg}";
info = msg: builtins.trace "INFO: ${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: substFunction = x:
if builtins.isAttrs x then lib.mapAttrs (name: substFunction) x if builtins.isAttrs x then lib.mapAttrs (name: substFunction) x
else if builtins.isList x then map 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; else x;
# Clean up declaration sites to not refer to the NixOS source tree. # Clean up declaration sites to not refer to the NixOS source tree.

View File

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

View File

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

View File

@ -17,7 +17,7 @@ let
# you should use files). # you should use files).
moduleFiles = moduleFiles =
# FIXME: use typeOf (Nix 1.6.1). # 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 # Partition module files because between NixOS and non-NixOS files. NixOS
# files may change if the repository is updated. # 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; }; 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 let
explicitRequires = explicitRequires =
if builtins.isFunction packagesFun if lib.isFunction packagesFun
then packagesFun self then packagesFun self
else packagesFun; else packagesFun;
in in

View File

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

View File

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

View File

@ -186,7 +186,7 @@ let
# There should be an IOVideo here, but they haven't released it :( # 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" {}; adv_cmds = applePackage "adv_cmds" "osx-10.5.8" "102ssayxbg9wb35mdmhswbnw0bg7js3pfd8fcbic83c5q3bqa6c6" {};

View File

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

View File

@ -40,7 +40,7 @@ let
makeOverridablePythonPackage = f: origArgs: makeOverridablePythonPackage = f: origArgs:
let let
ff = f origArgs; 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 in
if builtins.isAttrs ff then (ff // { if builtins.isAttrs ff then (ff // {
overridePythonAttrs = newArgs: makeOverridablePythonPackage f (overrideWith newArgs); overridePythonAttrs = newArgs: makeOverridablePythonPackage f (overrideWith newArgs);