Add some primops to lib

This commit is contained in:
Eelco Dolstra 2013-11-12 13:48:19 +01:00
parent 39e9fabae0
commit 785eaf2cea
17 changed files with 70 additions and 58 deletions

View File

@ -1,7 +1,7 @@
# Operations on attribute sets. # Operations on attribute sets.
with { with {
inherit (builtins) head tail isString; inherit (builtins) head tail;
inherit (import ./trivial.nix) or; inherit (import ./trivial.nix) or;
inherit (import ./default.nix) fold; inherit (import ./default.nix) fold;
inherit (import ./strings.nix) concatStringsSep; inherit (import ./strings.nix) concatStringsSep;
@ -100,7 +100,7 @@ rec {
(AttrSet -> Bool) -> AttrSet -> AttrSet (AttrSet -> Bool) -> AttrSet -> AttrSet
Example: Example:
collect builtins.isList { a = { b = ["b"]; }; c = [1]; } collect isList { a = { b = ["b"]; }; c = [1]; }
=> [["b"] [1]] => [["b"] [1]]
collect (x: x ? outPath) collect (x: x ? outPath)

View File

@ -21,8 +21,6 @@ let
in in
{ inherit trivial lists strings stringsWithDeps attrsets sources options { inherit trivial lists strings stringsWithDeps attrsets sources options
modules types meta debug maintainers licenses platforms systems; modules types meta debug maintainers licenses platforms systems;
# Pull in some builtins not included elsewhere.
inherit (builtins) pathExists readFile;
} }
# !!! don't include everything at top-level; perhaps only the most # !!! don't include everything at top-level; perhaps only the most
# commonly used functions. # commonly used functions.

View File

@ -1,14 +1,16 @@
# General list operations. # General list operations.
let
inherit (import ./trivial.nix) deepSeq; with import ./trivial.nix;
let
inc = builtins.add 1; inc = builtins.add 1;
dec = n: builtins.sub n 1; dec = n: builtins.sub n 1;
in rec { in rec {
inherit (builtins) head tail length isList add sub lessThan elemAt;
inherit (builtins) head tail length isList elemAt;
# Create a list consisting of a single element. `singleton x' is # Create a list consisting of a single element. `singleton x' is
@ -55,7 +57,7 @@ in rec {
else [ (f (inc n) (elemAt list n)) ] ++ imap' (inc n); else [ (f (inc n) (elemAt list n)) ] ++ imap' (inc n);
in imap' 0; in imap' 0;
# Concatenate a list of lists. # Concatenate a list of lists.
concatLists = builtins.concatLists or (fold (x: y: x ++ y) []); concatLists = builtins.concatLists or (fold (x: y: x ++ y) []);
@ -72,7 +74,7 @@ in rec {
then fold (x: y: (flatten x) ++ y) [] x then fold (x: y: (flatten x) ++ y) [] x
else [x]; else [x];
# Filter a list using a predicate; that is, return a list containing # Filter a list using a predicate; that is, return a list containing
# every element from `list' for which `pred' returns true. # every element from `list' for which `pred' returns true.
filter = filter =
@ -80,11 +82,11 @@ in rec {
(pred: list: (pred: list:
fold (x: y: if pred x then [x] ++ y else y) [] list); fold (x: y: if pred x then [x] ++ y else y) [] list);
# Remove elements equal to 'e' from a list. Useful for buildInputs. # Remove elements equal to 'e' from a list. Useful for buildInputs.
remove = e: filter (x: x != e); remove = e: filter (x: x != e);
# Return true if `list' has an element `x'. # Return true if `list' has an element `x'.
elem = elem =
builtins.elem or builtins.elem or
@ -106,7 +108,7 @@ in rec {
findFirst = pred: default: list: findFirst = pred: default: list:
let found = filter pred list; let found = filter pred list;
in if found == [] then default else head found; in if found == [] then default else head found;
# Return true iff function `pred' returns true for at least element # Return true iff function `pred' returns true for at least element
# of `list'. # of `list'.
@ -136,16 +138,16 @@ in rec {
# If argument is a list, return it; else, wrap it in a singleton # If argument is a list, return it; else, wrap it in a singleton
# list. If you're using this, you should almost certainly # list. If you're using this, you should almost certainly
# reconsider if there isn't a more "well-typed" approach. # reconsider if there isn't a more "well-typed" approach.
toList = x: if builtins.isList x then x else [x]; toList = x: if isList x then x else [x];
# Return a list of integers from `first' up to and including `last'. # Return a list of integers from `first' up to and including `last'.
range = first: last: range = first: last:
if builtins.lessThan last first if lessThan last first
then [] then []
else [first] ++ range (builtins.add first 1) last; else [first] ++ range (add first 1) last;
# Partition the elements of a list in two lists, `right' and # Partition the elements of a list in two lists, `right' and
# `wrong', depending on the evaluation of a predicate. # `wrong', depending on the evaluation of a predicate.
partition = pred: partition = pred:
@ -160,7 +162,7 @@ in rec {
let let
len1 = length fst; len1 = length fst;
len2 = length snd; len2 = length snd;
len = if builtins.lessThan len1 len2 then len1 else len2; len = if lessThan len1 len2 then len1 else len2;
zipListsWith' = n: zipListsWith' = n:
if n != len then if n != len then
[ (f (elemAt fst n) (elemAt snd n)) ] [ (f (elemAt fst n) (elemAt snd n)) ]
@ -207,7 +209,7 @@ in rec {
[ (elemAt list n) ] ++ take' (inc n); [ (elemAt list n) ] ++ take' (inc n);
in take' 0; in take' 0;
# Remove the first (at most) N elements of a list. # Remove the first (at most) N elements of a list.
drop = count: list: drop = count: list:
let let
@ -219,7 +221,8 @@ in rec {
drop' (dec n) ++ [ (elemAt list n) ]; drop' (dec n) ++ [ (elemAt list n) ];
in drop' (dec len); in drop' (dec len);
# Return the last element of a list.
last = list: last = list:
assert list != []; elemAt list (dec (length list)); assert list != []; elemAt list (dec (length list));
@ -237,5 +240,7 @@ in rec {
else []; else [];
in zipTwoLists' 0; in zipTwoLists' 0;
deepSeqList = xs: y: if any (x: deepSeq x false) xs then y else y; deepSeqList = xs: y: if any (x: deepSeq x false) xs then y else y;
} }

View File

@ -42,7 +42,7 @@ rec {
closeModules = modules: args: closeModules = modules: args:
let let
toClosureList = file: parentKey: imap (n: x: toClosureList = file: parentKey: imap (n: x:
if isAttrs x || builtins.isFunction x then if isAttrs x || isFunction x then
unifyModuleSyntax file "${parentKey}:anon-${toString n}" (applyIfFunction x args) unifyModuleSyntax file "${parentKey}:anon-${toString n}" (applyIfFunction x args)
else else
unifyModuleSyntax (toString x) (toString x) (applyIfFunction (import x) args)); unifyModuleSyntax (toString x) (toString x) (applyIfFunction (import x) args));
@ -74,7 +74,7 @@ rec {
config = removeAttrs m ["key" "_file" "require" "imports"]; config = removeAttrs m ["key" "_file" "require" "imports"];
}; };
applyIfFunction = f: arg: if builtins.isFunction f then f arg else f; applyIfFunction = f: arg: if isFunction f then f arg else f;
/* Merge a list of modules. This will recurse over the option /* Merge a list of modules. This will recurse over the option
declarations in all modules, combining them into a single set. declarations in all modules, combining them into a single set.
@ -260,7 +260,7 @@ rec {
options' = opt.options or options' = opt.options or
(throw "Option `${showOption loc'}' has type optionSet but has no option attribute."); (throw "Option `${showOption loc'}' has type optionSet but has no option attribute.");
coerce = x: coerce = x:
if builtins.isFunction x then x if isFunction x then x
else { config, ... }: { options = x; }; else { config, ... }: { options = x; };
options = map coerce (flatten options'); options = map coerce (flatten options');
f = tp: f = tp:

View File

@ -34,12 +34,12 @@ rec {
mergeDefaultOption = loc: defs: mergeDefaultOption = loc: defs:
let list = getValues defs; in let list = getValues defs; in
if length list == 1 then head list if length list == 1 then head list
else if all builtins.isFunction list then x: mergeDefaultOption loc (map (f: f x) list) else if all isFunction list then x: mergeDefaultOption loc (map (f: f x) list)
else if all isList list then concatLists list else if all isList list then concatLists list
else if all isAttrs list then fold lib.mergeAttrs {} list else if all isAttrs list then fold lib.mergeAttrs {} list
else if all builtins.isBool list then fold lib.or false list else if all isBool list then fold lib.or false list
else if all builtins.isString list then lib.concatStrings list else if all isString list then lib.concatStrings list
else if all builtins.isInt list && all (x: x == head list) list then head list else if all isInt list && all (x: x == head list) list then head list
else throw "Cannot merge definitions of `${showOption loc}' given in ${showFiles (getFiles defs)}."; else throw "Cannot merge definitions of `${showOption loc}' given in ${showFiles (getFiles defs)}.";
/* Obsolete, will remove soon. Specify an option type or apply /* Obsolete, will remove soon. Specify an option type or apply
@ -54,7 +54,7 @@ rec {
mergeListOption = mergeTypedOption "list" isList concatLists; mergeListOption = mergeTypedOption "list" isList concatLists;
mergeStringOption = mergeTypedOption "string" builtins.isString lib.concatStrings; mergeStringOption = mergeTypedOption "string" isString lib.concatStrings;
mergeOneOption = loc: defs: mergeOneOption = loc: defs:
if defs == [] then abort "This case should never happen." if defs == [] then abort "This case should never happen."

View File

@ -7,7 +7,8 @@ inherit (builtins) add sub lessThan length;
in in
rec { rec {
inherit (builtins) stringLength substring head tail;
inherit (builtins) stringLength substring head tail isString;
# Concatenate a list of strings. # Concatenate a list of strings.

View File

@ -16,7 +16,7 @@ rec {
or = x: y: x || y; or = x: y: x || y;
and = x: y: x && y; and = x: y: x && y;
mergeAttrs = x: y: x // y; mergeAttrs = x: y: x // y;
# Take a function and evaluate it with its own returned value. # Take a function and evaluate it with its own returned value.
fix = f: let result = f result; in result; fix = f: let result = f result; in result;
@ -26,7 +26,7 @@ rec {
# `seq x y' evaluates x, then returns y. That is, it forces strict # `seq x y' evaluates x, then returns y. That is, it forces strict
# evaluation of its first argument. # evaluation of its first argument.
seq = x: y: if x == null then y else y; seq = x: y: if x == null then y else y;
# Like `seq', but recurses into lists and attribute sets to force evaluation # Like `seq', but recurses into lists and attribute sets to force evaluation
# of all list elements/attributes. # of all list elements/attributes.
deepSeq = x: y: deepSeq = x: y:
@ -35,4 +35,10 @@ rec {
else if builtins.isAttrs x else if builtins.isAttrs x
then deepSeqAttrs x y then deepSeqAttrs x y
else seq x y; else seq x y;
# Pull in some builtins not included elsewhere.
inherit (builtins)
pathExists readFile isBool isFunction
isInt add sub lessThan;
} }

View File

@ -48,19 +48,19 @@ rec {
bool = mkOptionType { bool = mkOptionType {
name = "boolean"; name = "boolean";
check = builtins.isBool; check = isBool;
merge = loc: fold (x: y: x.value || y) false; merge = loc: fold (x: y: x.value || y) false;
}; };
int = mkOptionType { int = mkOptionType {
name = "integer"; name = "integer";
check = builtins.isInt; check = isInt;
merge = mergeOneOption; merge = mergeOneOption;
}; };
str = mkOptionType { str = mkOptionType {
name = "string"; name = "string";
check = builtins.isString; check = isString;
merge = mergeOneOption; merge = mergeOneOption;
}; };
@ -68,7 +68,7 @@ rec {
# separator between the values). # separator between the values).
separatedString = sep: mkOptionType { separatedString = sep: mkOptionType {
name = "string"; name = "string";
check = builtins.isString; check = isString;
merge = loc: defs: concatStringsSep sep (getValues defs); merge = loc: defs: concatStringsSep sep (getValues defs);
}; };
@ -170,7 +170,7 @@ rec {
functionTo = elemType: mkOptionType { functionTo = elemType: mkOptionType {
name = "function that evaluates to a(n) ${elemType.name}"; name = "function that evaluates to a(n) ${elemType.name}";
check = builtins.isFunction; check = isFunction;
merge = loc: defs: merge = loc: defs:
fnArgs: elemType.merge loc (map (fn: { inherit (fn) file; value = fn.value fnArgs; }) defs); fnArgs: elemType.merge loc (map (fn: { inherit (fn) file; value = fn.value fnArgs; }) defs);
getSubOptions = elemType.getSubOptions; getSubOptions = elemType.getSubOptions;
@ -183,10 +183,10 @@ rec {
in in
mkOptionType rec { mkOptionType rec {
name = "submodule"; name = "submodule";
check = x: isAttrs x || builtins.isFunction x; check = x: isAttrs x || isFunction x;
merge = loc: defs: merge = loc: defs:
let let
coerce = def: if builtins.isFunction def then def else { config = def; }; coerce = def: if isFunction def then def else { config = def; };
modules = opts' ++ map (def: { _file = def.file; imports = [(coerce def.value)]; }) defs; modules = opts' ++ map (def: { _file = def.file; imports = [(coerce def.value)]; }) defs;
in (evalModules { inherit modules; args.name = last loc; prefix = loc; }).config; in (evalModules { inherit modules; args.name = last loc; prefix = loc; }).config;
getSubOptions = prefix: (evalModules getSubOptions = prefix: (evalModules

View File

@ -31,9 +31,9 @@ in
res = (head defs').value; res = (head defs').value;
in in
if isList res then concatLists (getValues defs') if isList res then concatLists (getValues defs')
else if builtins.lessThan 1 (length defs') then else if lessThan 1 (length defs') then
throw "The option `${showOption loc}' is defined multiple times, in ${showFiles (getFiles defs)}." throw "The option `${showOption loc}' is defined multiple times, in ${showFiles (getFiles defs)}."
else if !builtins.isString res then else if !isString res then
throw "The option `${showOption loc}' does not have a string value, in ${showFiles (getFiles defs)}." throw "The option `${showOption loc}' does not have a string value, in ${showFiles (getFiles defs)}."
else res; else res;
}); });

View File

@ -6,7 +6,7 @@ let
sysctlOption = mkOptionType { sysctlOption = mkOptionType {
name = "sysctl option value"; name = "sysctl option value";
check = x: builtins.isBool x || builtins.isString x || builtins.isInt x; check = x: isBool x || isString x || isInt x;
merge = args: defs: (last defs).value; # FIXME: hacky way to allow overriding in configuration.nix. merge = args: defs: (last defs).value; # FIXME: hacky way to allow overriding in configuration.nix.
}; };

View File

@ -1,4 +1,6 @@
{pkgs, config, ...}: { config, pkgs, ... }:
with pkgs.lib;
let kernelVersion = config.boot.kernelPackages.kernel.version; in let kernelVersion = config.boot.kernelPackages.kernel.version; in
@ -8,9 +10,9 @@ let kernelVersion = config.boot.kernelPackages.kernel.version; in
options = { options = {
networking.enableB43Firmware = pkgs.lib.mkOption { networking.enableB43Firmware = mkOption {
default = false; default = false;
type = pkgs.lib.types.bool; type = types.bool;
description = '' description = ''
Turn on this option if you want firmware for the NICs supported by the b43 module. Turn on this option if you want firmware for the NICs supported by the b43 module.
''; '';
@ -21,11 +23,11 @@ let kernelVersion = config.boot.kernelPackages.kernel.version; in
###### implementation ###### implementation
config = pkgs.lib.mkIf config.networking.enableB43Firmware { config = mkIf config.networking.enableB43Firmware {
assertions = [ { assertions = singleton
assertion = builtins.lessThan 0 (builtins.compareVersions kernelVersion "3.2"); { assertion = lessThan 0 (builtins.compareVersions kernelVersion "3.2");
message = "b43 firmware for kernels older than 3.2 not packaged yet!"; message = "b43 firmware for kernels older than 3.2 not packaged yet!";
} ]; };
hardware.firmware = [ pkgs.b43Firmware_5_1_138 ]; hardware.firmware = [ pkgs.b43Firmware_5_1_138 ];
}; };

View File

@ -11,7 +11,7 @@ let
# CD. These are installed into the "nixos" channel of the root # CD. These are installed into the "nixos" channel of the root
# user, as expected by nixos-rebuild/nixos-install. # user, as expected by nixos-rebuild/nixos-install.
channelSources = pkgs.runCommand "nixos-${config.system.nixosVersion}" channelSources = pkgs.runCommand "nixos-${config.system.nixosVersion}"
{ expr = builtins.readFile ../../../lib/channel-expr.nix; } { expr = readFile ../../../lib/channel-expr.nix; }
'' ''
mkdir -p $out/nixos mkdir -p $out/nixos
cp -prd ${pkgs.path} $out/nixos/nixpkgs cp -prd ${pkgs.path} $out/nixos/nixpkgs

View File

@ -111,7 +111,7 @@ in
// optionalAttrs (config.services.tomcat.enable) { tomcatPort = 8080; } // optionalAttrs (config.services.tomcat.enable) { tomcatPort = 8080; }
// optionalAttrs (config.services.svnserve.enable) { svnBaseDir = config.services.svnserve.svnBaseDir; } // optionalAttrs (config.services.svnserve.enable) { svnBaseDir = config.services.svnserve.svnBaseDir; }
// optionalAttrs (cfg.publishInfrastructure.enableAuthentication) ( // optionalAttrs (cfg.publishInfrastructure.enableAuthentication) (
optionalAttrs (config.services.mysql.enable) { mysqlUsername = "root"; mysqlPassword = builtins.readFile config.services.mysql.rootPassword; }) optionalAttrs (config.services.mysql.enable) { mysqlUsername = "root"; mysqlPassword = readFile config.services.mysql.rootPassword; })
) )
; ;
@ -152,7 +152,7 @@ in
${concatMapStrings (infrastructureAttrName: ${concatMapStrings (infrastructureAttrName:
let infrastructureAttrValue = getAttr infrastructureAttrName (cfg.infrastructure); let infrastructureAttrValue = getAttr infrastructureAttrName (cfg.infrastructure);
in in
if builtins.isInt infrastructureAttrValue then if isInt infrastructureAttrValue then
''${infrastructureAttrName}=${toString infrastructureAttrValue} \ ''${infrastructureAttrName}=${toString infrastructureAttrValue} \
'' ''
else else

View File

@ -19,7 +19,7 @@ let
knownHostsFile = pkgs.writeText "ssh_known_hosts" ( knownHostsFile = pkgs.writeText "ssh_known_hosts" (
flip concatMapStrings knownHosts (h: flip concatMapStrings knownHosts (h:
"${concatStringsSep "," h.hostNames} ${builtins.readFile h.publicKeyFile}" "${concatStringsSep "," h.hostNames} ${readFile h.publicKeyFile}"
) )
); );
@ -59,7 +59,7 @@ let
mode = "0444"; mode = "0444";
source = pkgs.writeText "${u.name}-authorized_keys" '' source = pkgs.writeText "${u.name}-authorized_keys" ''
${concatStringsSep "\n" u.openssh.authorizedKeys.keys} ${concatStringsSep "\n" u.openssh.authorizedKeys.keys}
${concatMapStrings (f: builtins.readFile f + "\n") u.openssh.authorizedKeys.keyFiles} ${concatMapStrings (f: readFile f + "\n") u.openssh.authorizedKeys.keyFiles}
''; '';
}; };
usersWithKeys = attrValues (flip filterAttrs config.users.extraUsers (n: u: usersWithKeys = attrValues (flip filterAttrs config.users.extraUsers (n: u:

View File

@ -15,7 +15,7 @@ let
toOption = x: toOption = x:
if x == true then "true" if x == true then "true"
else if x == false then "false" else if x == false then "false"
else if builtins.isInt x then toString x else if isInt x then toString x
else toString ''\"${x}\"''; else toString ''\"${x}\"'';
# All lines in settings.json end with a ',' (comma), except for the last # All lines in settings.json end with a ',' (comma), except for the last

View File

@ -17,8 +17,8 @@ let
getPort = cfg: if cfg.port != 0 then cfg.port else if cfg.enableSSL then 443 else 80; getPort = cfg: if cfg.port != 0 then cfg.port else if cfg.enableSSL then 443 else 80;
extraModules = attrByPath ["extraModules"] [] mainCfg; extraModules = attrByPath ["extraModules"] [] mainCfg;
extraForeignModules = filter builtins.isAttrs extraModules; extraForeignModules = filter isAttrs extraModules;
extraApacheModules = filter (x: !(builtins.isAttrs x)) extraModules; # I'd prefer using builtins.isString here, but doesn't exist yet extraApacheModules = filter isString extraModules;
makeServerInfo = cfg: { makeServerInfo = cfg: {

View File

@ -71,7 +71,7 @@ in
${ ${
let let
set' = mapAttrs (n: v: if builtins.isString v then noDepEntry v else v) set; set' = mapAttrs (n: v: if isString v then noDepEntry v else v) set;
withHeadlines = addAttributeName set'; withHeadlines = addAttributeName set';
in textClosureMap id (withHeadlines) (attrNames withHeadlines) in textClosureMap id (withHeadlines) (attrNames withHeadlines)
} }