@ -19,27 +19,24 @@ rec {
} ;
# name (name of the type)
# check (check the config value)
# merge (default merge function)
# getSubOptions (returns sub-options for manual generation)
isOptionType = isType " o p t i o n - t y p e " ;
mkOptionType =
{ name
, check ? ( x : true )
, merge ? mergeDefaultOption
, merge' ? args : merge
, getSubOptions ? prefix : { }
{ # Human-readable representation of the type.
name
, # Function applied to each definition that should return true if
# its type-correct, false otherwise.
check ? ( x : true )
, # Merge a list of definitions together into a single value.
merge ? mergeDefaultOption
, # Return a flat list of sub-options. Used to generate
# documentation.
getSubOptions ? prefix : { }
} :
{ _type = " o p t i o n - t y p e " ;
inherit name check merge merge' getSubOptions ;
inherit name check merge getSubOptions ;
} ;
addToPrefix = args : name : args // { prefix = args . prefix ++ [ name ] ; } ;
types = rec {
unspecified = mkOptionType {
@ -49,7 +46,7 @@ rec {
bool = mkOptionType {
name = " b o o l e a n " ;
check = builtins . isBool ;
merge = fold lib . or false ;
merge = args : fold lib . or false ;
} ;
int = mkOptionType {
@ -60,7 +57,7 @@ rec {
string = mkOptionType {
name = " s t r i n g " ;
check = builtins . isString ;
merge = lib . concatStrings ;
merge = args : lib . concatStrings ;
} ;
# Like ‘string’, but add newlines between every value. Useful for
@ -68,54 +65,56 @@ rec {
lines = mkOptionType {
name = " s t r i n g " ;
check = builtins . isString ;
merge = lib . concatStringsSep " \n " ;
merge = args : lib . concatStringsSep " \n " ;
} ;
commas = mkOptionType {
name = " s t r i n g " ;
check = builtins . isString ;
merge = lib . concatStringsSep " , " ;
merge = args : lib . concatStringsSep " , " ;
} ;
envVar = mkOptionType {
name = " e n v i r o n m e n t v a r i a b l e " ;
inherit ( string ) check ;
merge = lib . concatStringsSep " : " ;
merge = args : lib . concatStringsSep " : " ;
} ;
attrs = mkOptionType {
name = " a t t r i b u t e s e t " ;
check = isAttrs ;
merge = fold lib . mergeAttrs { } ;
merge = args : fold lib . mergeAttrs { } ;
} ;
# derivation is a reserved keyword.
package = mkOptionType {
name = " d e r i v a t i o n " ;
check = isDerivation ;
merge = mergeOneOption ;
} ;
path = mkOptionType {
name = " p a t h " ;
# Hacky: there is no ‘isPath’ primop.
check = x : builtins . unsafeDiscardStringContext ( builtins . substring 0 1 ( toString x ) ) == " / " ;
merge = mergeOneOption ;
} ;
# drop this in the future:
list = builtins . trace " t y p e s . l i s t i s d e p r e c a t e d ; u s e t y p e s . l i s t O f i n s t e a d " types . listOf ;
list = builtins . trace " ` ty p e s . l i s t ' i s d e p r e c a t e d ; u s e ` ty p e s . l i s t O f ' i n s t e a d " types . listOf ;
listOf = elemType : mkOptionType {
name = " l i s t o f ${ elemType . name } s " ;
check = value : isList value && all elemType . check value ;
merge' = args : defs : imap ( n : def : elemType . merge' ( addToPrefix args ( toString n ) ) [ def ] ) ( concatLists defs ) ;
merge = args : defs : imap ( n : def : elemType . merge ( addToPrefix args ( toString n ) ) [ def ] ) ( concatLists defs ) ;
getSubOptions = prefix : elemType . getSubOptions ( prefix ++ [ " * " ] ) ;
} ;
attrsOf = elemType : mkOptionType {
name = " a t t r i b u t e s e t o f ${ elemType . name } s " ;
check = x : isAttrs x && all elemType . check ( lib . attrValues x ) ;
merge' = args : lib . zipAttrsWith ( name :
elemType . merge' ( addToPrefix ( args // { inherit name ; } ) name ) ) ;
merge = args : lib . zipAttrsWith ( name :
elemType . merge ( addToPrefix ( args // { inherit name ; } ) name ) ) ;
getSubOptions = prefix : elemType . getSubOptions ( prefix ++ [ " < n a m e > " ] ) ;
} ;
@ -138,43 +137,39 @@ rec {
if isList x then listOnly . check x
else if isAttrs x then attrOnly . check x
else false ;
merge' = args : defs : attrOnly . merge' args ( imap convertIfList defs ) ;
merge = args : defs : attrOnly . merge args ( imap convertIfList defs ) ;
getSubOptions = prefix : elemType . getSubOptions ( prefix ++ [ " < n a m e ? > " ] ) ;
} ;
uniq = elemType : mkOptionType {
inherit ( elemType ) name check ;
merge = list :
if length list == 1 then
head list
else
throw " M u l t i p l e d e f i n i t i o n s o f ${ elemType . name } . O n l y o n e i s a l l o w e d f o r t h i s o p t i o n . " ;
merge = mergeOneOption ;
getSubOptions = elemType . getSubOptions ;
} ;
none = elemType : mkOptionType {
inherit ( elemType ) name check ;
merge = list :
throw " N o d e f i n i t i o n s a r e a l l o w e d f o r t h i s o p t i o n . " ;
merge = args : list :
throw " N o d e f i n i t i o n s a r e a l l o w e d f o r t h e o p t i o n ` ${ showOption args . prefix } ' . " ;
getSubOptions = elemType . getSubOptions ;
} ;
nullOr = elemType : mkOptionType {
name = " n u l l o r ${ elemType . name } " ;
check = x : builtins . isNull x || elemType . check x ;
merge' = args : defs :
merge = args : defs :
if all isNull defs then null
else if any isNull defs then
throw " S o m e b u t n o t a l l v a l u e s a r e n u l l . "
else elemType . merge' args defs ;
throw " T h e o p t i o n ` ${ showOption args . prefix } ' i s d e f i n e d b o t h n u l l a n d n o t n u l l , i n ${ showFiles args . files } . "
else elemType . merge args defs ;
getSubOptions = elemType . getSubOptions ;
} ;
functionTo = elemType : mkOptionType {
name = " f u n c t i o n t h a t e v a l u a t e s t o a ( n ) ${ elemType . name } " ;
check = builtins . isFunction ;
merge' = args : fns :
fnArgs : elemType . merge' args ( map ( fn : fn fnArgs ) fns ) ;
merge = args : fns :
fnArgs : elemType . merge args ( map ( fn : fn fnArgs ) fns ) ;
getSubOptions = elemType . getSubOptions ;
} ;
@ -183,8 +178,7 @@ rec {
mkOptionType rec {
name = " s u b m o d u l e " ;
check = x : isAttrs x || builtins . isFunction x ;
merge = merge' { } ;
merge' = args : defs :
merge = args : defs :
let
coerce = def : if builtins . isFunction def then def else { config = def ; } ;
modules = opts' ++ map coerce defs ;
@ -204,4 +198,8 @@ rec {
} ;
/* H e l p e r f u n c t i o n . */
addToPrefix = args : name : args // { prefix = args . prefix ++ [ name ] ; } ;
}