From 943592f69850fd07dd2422da062b1c1ebc45974d Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Wed, 31 Jan 2018 14:02:19 -0500 Subject: [PATCH] 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. --- lib/customisation.nix | 14 +++++----- lib/debug.nix | 4 +-- lib/default.nix | 4 +-- lib/deprecated.nix | 8 +++--- lib/generators.nix | 4 ++- lib/modules.nix | 2 +- lib/trivial.nix | 27 ++++++++++++++++++- nixos/doc/manual/default.nix | 2 +- nixos/lib/testing.nix | 2 +- nixos/modules/misc/nixpkgs.nix | 6 ++--- nixos/modules/profiles/clone-config.nix | 2 +- nixos/tests/make-test.nix | 2 +- pkgs/build-support/emacs/wrapper.nix | 2 +- pkgs/development/beam-modules/lib.nix | 4 +-- .../haskell-modules/make-package-set.nix | 4 +-- .../darwin/apple-source-releases/default.nix | 2 +- pkgs/top-level/default.nix | 2 +- pkgs/top-level/python-packages.nix | 2 +- 18 files changed, 60 insertions(+), 33 deletions(-) diff --git a/lib/customisation.nix b/lib/customisation.nix index 3988f4e9b69..823395f04d4 100644 --- a/lib/customisation.nix +++ b/lib/customisation.nix @@ -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; diff --git a/lib/debug.nix b/lib/debug.nix index 646ef220ad0..d163e60b695 100644 --- a/lib/debug.nix +++ b/lib/debug.nix @@ -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 diff --git a/lib/default.nix b/lib/default.nix index 6d2a95e559c..97d7c10192a 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -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; diff --git a/lib/deprecated.nix b/lib/deprecated.nix index 2a0f5a55bf1..34cf336d1f4 100644 --- a/lib/deprecated.nix +++ b/lib/deprecated.nix @@ -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" diff --git a/lib/generators.nix b/lib/generators.nix index f207033c955..73017f2c679 100644 --- a/lib/generators.nix +++ b/lib/generators.nix @@ -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); diff --git a/lib/modules.nix b/lib/modules.nix index 8c3584bbbf4..654c4c588de 100644 --- a/lib/modules.nix +++ b/lib/modules.nix @@ -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; diff --git a/lib/trivial.nix b/lib/trivial.nix index c452c7b65bc..d8d51298143 100644 --- a/lib/trivial.nix +++ b/lib/trivial.nix @@ -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)); } diff --git a/nixos/doc/manual/default.nix b/nixos/doc/manual/default.nix index 9bc83be6610..8079a2feb29 100644 --- a/nixos/doc/manual/default.nix +++ b/nixos/doc/manual/default.nix @@ -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 "" + else if lib.isFunction x then "" else x; # Clean up declaration sites to not refer to the NixOS source tree. diff --git a/nixos/lib/testing.nix b/nixos/lib/testing.nix index 532fff681d3..cf213d906f5 100644 --- a/nixos/lib/testing.nix +++ b/nixos/lib/testing.nix @@ -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; diff --git a/nixos/modules/misc/nixpkgs.nix b/nixos/modules/misc/nixpkgs.nix index 1793c1447d6..b01f5431909 100644 --- a/nixos/modules/misc/nixpkgs.nix +++ b/nixos/modules/misc/nixpkgs.nix @@ -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; }; diff --git a/nixos/modules/profiles/clone-config.nix b/nixos/modules/profiles/clone-config.nix index 77d86f8d740..5b4e68beb6a 100644 --- a/nixos/modules/profiles/clone-config.nix +++ b/nixos/modules/profiles/clone-config.nix @@ -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. diff --git a/nixos/tests/make-test.nix b/nixos/tests/make-test.nix index f3e26aa7e74..1b571a008e0 100644 --- a/nixos/tests/make-test.nix +++ b/nixos/tests/make-test.nix @@ -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) diff --git a/pkgs/build-support/emacs/wrapper.nix b/pkgs/build-support/emacs/wrapper.nix index 27633c912b2..4e780b104b0 100644 --- a/pkgs/build-support/emacs/wrapper.nix +++ b/pkgs/build-support/emacs/wrapper.nix @@ -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 diff --git a/pkgs/development/beam-modules/lib.nix b/pkgs/development/beam-modules/lib.nix index 26d868a8e7c..d6b83cb1af0 100644 --- a/pkgs/development/beam-modules/lib.nix +++ b/pkgs/development/beam-modules/lib.nix @@ -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; diff --git a/pkgs/development/haskell-modules/make-package-set.nix b/pkgs/development/haskell-modules/make-package-set.nix index 223f0652887..0f866a96e71 100644 --- a/pkgs/development/haskell-modules/make-package-set.nix +++ b/pkgs/development/haskell-modules/make-package-set.nix @@ -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 // { diff --git a/pkgs/os-specific/darwin/apple-source-releases/default.nix b/pkgs/os-specific/darwin/apple-source-releases/default.nix index 478f9e7e303..cca729016c2 100644 --- a/pkgs/os-specific/darwin/apple-source-releases/default.nix +++ b/pkgs/os-specific/darwin/apple-source-releases/default.nix @@ -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" {}; diff --git a/pkgs/top-level/default.nix b/pkgs/top-level/default.nix index 96d5e1fe283..9cf9eb4db65 100644 --- a/pkgs/top-level/default.nix +++ b/pkgs/top-level/default.nix @@ -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; diff --git a/pkgs/top-level/python-packages.nix b/pkgs/top-level/python-packages.nix index 1820125b0a5..bc3ea1027e7 100644 --- a/pkgs/top-level/python-packages.nix +++ b/pkgs/top-level/python-packages.nix @@ -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);