Merge branch 'master' into stdenv-updates

Conflicts:
	pkgs/top-level/all-packages.nix
This commit is contained in:
Mathijs Kwik 2013-11-01 08:31:54 +01:00
commit 609f8dc04b
272 changed files with 4690 additions and 2945 deletions

View file

@ -29,9 +29,8 @@ rec {
["x" "y"] applied with some value v returns `x.y = v;' */
setAttrByPath = attrPath: value:
if attrPath == [] then value
else listToAttrs [(
nameValuePair (head attrPath) (setAttrByPath (tail attrPath) value)
)];
else listToAttrs
[ { name = head attrPath; value = setAttrByPath (tail attrPath) value; } ];
getAttrFromPath = attrPath: set:
@ -133,7 +132,7 @@ rec {
=> { x = "x-foo"; y = "y-bar"; }
*/
mapAttrs = f: set:
listToAttrs (map (attr: nameValuePair attr (f attr (getAttr attr set))) (attrNames set));
listToAttrs (map (attr: { name = attr; value = f attr (getAttr attr set); }) (attrNames set));
/* Like `mapAttrs', but allows the name of each attribute to be
@ -240,7 +239,7 @@ rec {
# names, hopefully this does not affect the system because the maximal
# laziness avoid computing twice the same expression and listToAttrs does
# not care about duplicated attribute names.
zipAttrsWith = f: sets: zipWithNames (concatMap attrNames sets) f sets;
zipAttrsWith = f: sets: zipAttrsWithNames (concatMap attrNames sets) f sets;
zipAttrs = zipAttrsWith (name: values: values);

View file

@ -8,7 +8,6 @@ let
sources = import ./sources.nix;
modules = import ./modules.nix;
options = import ./options.nix;
properties = import ./properties.nix;
types = import ./types.nix;
meta = import ./meta.nix;
debug = import ./debug.nix;
@ -21,13 +20,13 @@ let
in
{ inherit trivial lists strings stringsWithDeps attrsets sources options
properties 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
# commonly used functions.
// trivial // lists // strings // stringsWithDeps // attrsets // sources
// properties // options // types // meta // debug // misc // modules
// options // types // meta // debug // misc // modules
// systems
// customisation

View file

@ -118,6 +118,11 @@ in rec {
all = pred: fold (x: y: if pred x then y else false) true;
# Count how many times function `pred' returns true for the elements
# of `list'.
count = pred: fold (x: c: if pred x then inc c else c) 0;
# Return a singleton list or an empty list, depending on a boolean
# value. Useful when building lists with optional elements
# (e.g. `++ optional (system == "i686-linux") flashplayer').
@ -165,10 +170,11 @@ in rec {
zipLists = zipListsWith (fst: snd: { inherit fst snd; });
# Reverse the order of the elements of a list.
# Reverse the order of the elements of a list. FIXME: O(n^2)!
reverseList = fold (e: acc: acc ++ [ e ]) [];
# Sort a list based on a comparator function which compares two
# elements and returns true if the first argument is strictly below
# the second argument. The returned list is sorted in an increasing

View file

@ -1,379 +1,312 @@
# NixOS module handling.
let lib = import ./default.nix; in
with { inherit (builtins) head; };
with import ./trivial.nix;
with import ./lists.nix;
with import ./misc.nix;
with import ./trivial.nix;
with import ./attrsets.nix;
with import ./options.nix;
with import ./properties.nix;
with import ./debug.nix;
with import ./types.nix;
rec {
# Unfortunately this can also be a string.
isPath = x: !(
builtins.isFunction x
|| builtins.isAttrs x
|| builtins.isInt x
|| builtins.isBool x
|| builtins.isList x
);
importIfPath = path:
if isPath path then
import path
else
path;
applyIfFunction = f: arg:
if builtins.isFunction f then
f arg
else
f;
isModule = m:
(m ? config && isAttrs m.config && ! isOption m.config)
|| (m ? options && isAttrs m.options && ! isOption m.options);
# Convert module to a set which has imports / options and config
# attributes.
unifyModuleSyntax = m:
/* Evaluate a set of modules. The result is a set of two
attributes: options: the nested set of all option declarations,
and config: the nested set of all option values. */
evalModules = { modules, prefix ? [], args ? {}, check ? true }:
let
delayedModule = delayProperties m;
getImports =
toList (rmProperties (delayedModule.require or []));
getImportedPaths = filter isPath getImports;
getImportedSets = filter (x: !isPath x) getImports;
getConfig =
removeAttrs delayedModule ["require" "key" "imports"];
args' = args // result;
closed = closeModules modules args';
# Note: the list of modules is reversed to maintain backward
# compatibility with the old module system. Not sure if this is
# the most sensible policy.
options = mergeModules prefix (reverseList closed);
# Traverse options and extract the option values into the final
# config set. At the same time, check whether all option
# definitions have matching declarations.
config = yieldConfig prefix options;
yieldConfig = prefix: set:
let res = removeAttrs (mapAttrs (n: v:
if isOption v then v.value
else yieldConfig (prefix ++ [n]) v) set) ["_definedNames"];
in
if check && set ? _definedNames then
fold (m: res:
fold (name: res:
if hasAttr name set then res else throw "The option `${showOption (prefix ++ [name])}' defined in `${m.file}' does not exist.")
res m.names)
res set._definedNames
else
res;
result = { inherit options config; };
in result;
/* Close a set of modules under the imports relation. */
closeModules = modules: args:
let
toClosureList = file: parentKey: imap (n: x:
if isAttrs x || builtins.isFunction x then
unifyModuleSyntax file "${parentKey}:anon-${toString n}" (applyIfFunction x args)
else
unifyModuleSyntax (toString x) (toString x) (applyIfFunction (import x) args));
in
if isModule m then
{ key = "<unknown location>"; } // m
builtins.genericClosure {
startSet = toClosureList unknownModule "" modules;
operator = m: toClosureList m.file m.key m.imports;
};
/* Massage a module into canonical form, that is, a set consisting
of options, config and imports attributes. */
unifyModuleSyntax = file: key: m:
if m ? config || m ? options then
let badAttrs = removeAttrs m ["imports" "options" "config" "key" "_file"]; in
if badAttrs != {} then
throw "Module `${key}' has an unsupported attribute `${head (attrNames badAttrs)}'."
else
{ key = "<unknown location>";
imports = (m.imports or []) ++ getImportedPaths;
config = getConfig;
} // (
if getImportedSets != [] then
assert length getImportedSets == 1;
{ options = head getImportedSets; }
{ file = m._file or file;
key = toString m.key or key;
imports = m.imports or [];
options = m.options or {};
config = m.config or {};
}
else
{ file = m._file or file;
key = toString m.key or key;
imports = m.require or [] ++ m.imports or [];
options = {};
config = removeAttrs m ["key" "_file" "require" "imports"];
};
applyIfFunction = f: arg: if builtins.isFunction f then f arg else f;
/* Merge a list of modules. This will recurse over the option
declarations in all modules, combining them into a single set.
At the same time, for each option declaration, it will merge the
corresponding option definitions in all machines, returning them
in the value attribute of each option. */
mergeModules = prefix: modules:
mergeModules' prefix modules
(concatMap (m: map (config: { inherit (m) file; inherit config; }) (pushDownProperties m.config)) modules);
mergeModules' = prefix: options: configs:
listToAttrs (map (name: {
# We're descending into attribute name.
inherit name;
value =
let
loc = prefix ++ [name];
# Get all submodules that declare name.
decls = concatLists (map (m:
if hasAttr name m.options
then [ { inherit (m) file; options = getAttr name m.options; } ]
else []
) options);
# Get all submodules that define name.
defns = concatLists (map (m:
if hasAttr name m.config
then map (config: { inherit (m) file; inherit config; })
(pushDownProperties (getAttr name m.config))
else []
) configs);
nrOptions = count (m: isOption m.options) decls;
# Process mkMerge and mkIf properties.
defns' = concatMap (m:
if hasAttr name m.config
then map (m': { inherit (m) file; value = m'; }) (dischargeProperties (getAttr name m.config))
else []
) configs;
in
if nrOptions == length decls then
let opt = fixupOptionType loc (mergeOptionDecls loc decls);
in evalOptionValue loc opt defns'
else if nrOptions != 0 then
let
firstOption = findFirst (m: isOption m.options) "" decls;
firstNonOption = findFirst (m: !isOption m.options) "" decls;
in
throw "The option `${showOption loc}' in `${firstOption.file}' is a prefix of options in `${firstNonOption.file}'."
else
{}
);
mergeModules' loc decls defns;
}) (concatMap (m: attrNames m.options) options))
// { _definedNames = map (m: { inherit (m) file; names = attrNames m.config; }) configs; };
/* Merge multiple option declarations into a single declaration. In
general, there should be only one declaration of each option.
The exception is the options attribute, which specifies
sub-options. These can be specified multiple times to allow one
module to add sub-options to an option declared somewhere else
(e.g. multiple modules define sub-options for fileSystems). */
mergeOptionDecls = loc: opts:
fold (opt: res:
if opt.options ? default && res ? default ||
opt.options ? example && res ? example ||
opt.options ? description && res ? description ||
opt.options ? apply && res ? apply ||
opt.options ? type && res ? type
then
throw "The option `${showOption loc}' in `${opt.file}' is already declared in ${showFiles res.declarations}."
else
opt.options // res //
{ declarations = [opt.file] ++ res.declarations;
options = if opt.options ? options then [(toList opt.options.options ++ res.options)] else [];
}
) { inherit loc; declarations = []; options = []; } opts;
unifyOptionModule = {key ? "<unknown location>"}: name: index: m: (args:
/* Merge all the definitions of an option to produce the final
config value. */
evalOptionValue = loc: opt: defs:
let
module = lib.applyIfFunction m args;
key_ = rec {
file = key;
option = name;
number = index;
outPath = key;
};
in if lib.isModule module then
{ key = key_; } // module
else
{ key = key_; options = module; }
);
moduleClosure = initModules: args:
let
moduleImport = origin: index: m:
let m' = applyIfFunction (importIfPath m) args;
in (unifyModuleSyntax m') // {
# used by generic closure to avoid duplicated imports.
key =
if isPath m then m
else m'.key or (newModuleName origin index);
};
getImports = m: m.imports or [];
newModuleName = origin: index:
"${origin.key}:<import-${toString index}>";
topLevel = {
key = "<top-level>";
# Process mkOverride properties, adding in the default
# value specified in the option declaration (if any).
defsFinal = filterOverrides
((if opt ? default then [{ file = head opt.declarations; value = mkOptionDefault opt.default; }] else []) ++ defs);
files = map (def: def.file) defsFinal;
# Type-check the remaining definitions, and merge them if
# possible.
merged =
if defsFinal == [] then
throw "The option `${showOption loc}' is used but not defined."
else
fold (def: res:
if opt.type.check def.value then res
else throw "The option value `${showOption loc}' in `${def.file}' is not a ${opt.type.name}.")
(opt.type.merge loc defsFinal) defsFinal;
# Finally, apply the apply function to the merged
# value. This allows options to yield a value computed
# from the definitions.
value = (opt.apply or id) merged;
in opt //
{ value = addErrorContext "while evaluating the option `${showOption loc}':" value;
definitions = map (def: def.value) defsFinal;
isDefined = defsFinal != [];
inherit files;
};
in
(lazyGenericClosure {
startSet = imap (moduleImport topLevel) initModules;
operator = m: imap (moduleImport m) (getImports m);
});
/* Given a config set, expand mkMerge properties, and push down the
mkIf properties into the children. The result is a list of
config sets that do not have properties at top-level. For
example,
mkMerge [ { boot = set1; } (mkIf cond { boot = set2; services = set3; }) ]
moduleApply = funs: module:
lib.mapAttrs (name: value:
if builtins.hasAttr name funs then
let fun = lib.getAttr name funs; in
fun value
is transformed into
[ { boot = set1; } { boot = mkIf cond set2; services mkIf cond set3; } ].
This transform is the critical step that allows mkIf conditions
to refer to the full configuration without creating an infinite
recursion.
*/
pushDownProperties = cfg:
if cfg._type or "" == "merge" then
concatMap pushDownProperties cfg.contents
else if cfg._type or "" == "if" then
map (mapAttrs (n: v: mkIf cfg.condition v)) (pushDownProperties cfg.content)
else if cfg._type or "" == "override" then
map (mapAttrs (n: v: mkOverride cfg.priority v)) (pushDownProperties cfg.content)
else
[ cfg ];
/* Given a config value, expand mkMerge properties, and discharge
any mkIf conditions. That is, this is the place where mkIf
conditions are actually evaluated. The result is a list of
config values. For example, mkIf false x yields [],
mkIf true x yields [x], and
mkMerge [ 1 (mkIf true 2) (mkIf true (mkIf false 3)) ]
yields [ 1 2 ].
*/
dischargeProperties = def:
if def._type or "" == "merge" then
concatMap dischargeProperties def.contents
else if def._type or "" == "if" then
if def.condition then
dischargeProperties def.content
else
value
) module;
# Handle mkMerge function left behind after a delay property.
moduleFlattenMerge = module:
if module ? config &&
isProperty module.config &&
isMerge module.config.property
then
(map (cfg: { key = module.key; config = cfg; }) module.config.content)
++ [ (module // { config = {}; }) ]
[ ]
else
[ module ];
[ def ];
/* Given a list of config values, process the mkOverride properties,
that is, return the values that have the highest (that is,
numerically lowest) priority, and strip the mkOverride
properties. For example,
# Handle mkMerge attributes which are left behind by previous delay
# properties and convert them into a list of modules. Delay properties
# inside the config attribute of a module and create a second module if a
# mkMerge attribute was left behind.
#
# Module -> [ Module ]
delayModule = module:
map (moduleApply { config = delayProperties; }) (moduleFlattenMerge module);
[ { file = "/1"; value = mkOverride 10 "a"; }
{ file = "/2"; value = mkOverride 20 "b"; }
{ file = "/3"; value = "z"; }
{ file = "/4"; value = mkOverride 10 "d"; }
]
yields
evalDefinitions = opt: values:
if opt.type.delayOnGlobalEval or false then
map (delayPropertiesWithIter opt.type.iter opt.name)
(evalLocalProperties values)
else
evalProperties values;
[ { file = "/1"; value = "a"; }
{ file = "/4"; value = "d"; }
]
selectModule = name: m:
{ inherit (m) key;
} // (
if m ? options && builtins.hasAttr name m.options then
{ options = lib.getAttr name m.options; }
else {}
) // (
if m ? config && builtins.hasAttr name m.config then
{ config = lib.getAttr name m.config; }
else {}
);
filterModules = name: modules:
filter (m: m ? config || m ? options) (
map (selectModule name) modules
);
modulesNames = modules:
lib.concatMap (m: []
++ optionals (m ? options) (lib.attrNames m.options)
++ optionals (m ? config) (lib.attrNames m.config)
) modules;
moduleZip = funs: modules:
lib.mapAttrs (name: fun:
fun (catAttrs name modules)
) funs;
moduleMerge = path: modules_:
Note that "z" has the default priority 100.
*/
filterOverrides = defs:
let
addName = name:
if path == "" then name else path + "." + name;
defaultPrio = 100;
getPrio = def: if def.value._type or "" == "override" then def.value.priority else defaultPrio;
min = x: y: if builtins.lessThan x y then x else y;
highestPrio = fold (def: prio: min (getPrio def) prio) 9999 defs;
strip = def: if def.value._type or "" == "override" then def // { value = def.value.content; } else def;
in concatMap (def: if getPrio def == highestPrio then [(strip def)] else []) defs;
modules = concatLists (map delayModule modules_);
modulesOf = name: filterModules name modules;
declarationsOf = name: filter (m: m ? options) (modulesOf name);
definitionsOf = name: filter (m: m ? config ) (modulesOf name);
recurseInto = name:
moduleMerge (addName name) (modulesOf name);
recurseForOption = name: modules: args:
moduleMerge name (
moduleClosure modules args
);
errorSource = modules:
"The error may come from the following files:\n" + (
lib.concatStringsSep "\n" (
map (m:
if m ? key then toString m.key else "<unknown location>"
) modules
)
);
eol = "\n";
allNames = modulesNames modules;
getResults = m:
let fetchResult = s: mapAttrs (n: v: v.result) s; in {
options = fetchResult m.options;
config = fetchResult m.config;
};
endRecursion = { options = {}; config = {}; };
in if modules == [] then endRecursion else
getResults (fix (crossResults: moduleZip {
options = lib.zipWithNames allNames (name: values: rec {
config = lib.getAttr name crossResults.config;
declarations = declarationsOf name;
declarationSources =
map (m: {
source = m.key;
}) declarations;
hasOptions = values != [];
isOption = any lib.isOption values;
decls = # add location to sub-module options.
map (m:
mapSubOptions
(unifyOptionModule {inherit (m) key;} name)
m.options
) declarations;
decl =
lib.addErrorContext "${eol
}while enhancing option `${addName name}':${eol
}${errorSource declarations}${eol
}" (
addOptionMakeUp
{ name = addName name; recurseInto = recurseForOption; }
(mergeOptionDecls decls)
);
value = decl // (with config; {
inherit (config) isNotDefined;
isDefined = ! isNotDefined;
declarations = declarationSources;
definitions = definitionSources;
config = strictResult;
});
recurse = (recurseInto name).options;
result =
if isOption then value
else if !hasOptions then {}
else if all isAttrs values then recurse
else
throw "${eol
}Unexpected type where option declarations are expected.${eol
}${errorSource declarations}${eol
}";
});
config = lib.zipWithNames allNames (name: values_: rec {
option = lib.getAttr name crossResults.options;
definitions = definitionsOf name;
definitionSources =
map (m: {
source = m.key;
value = m.config;
}) definitions;
values = values_ ++
optionals (option.isOption && option.decl ? extraConfigs)
option.decl.extraConfigs;
defs = evalDefinitions option.decl values;
isNotDefined = defs == [];
value =
lib.addErrorContext "${eol
}while evaluating the option `${addName name}':${eol
}${errorSource (modulesOf name)}${eol
}" (
let opt = option.decl; in
opt.apply (
if isNotDefined then
opt.default or (throw "Option `${addName name}' not defined and does not have a default value.")
else opt.merge defs
)
);
strictResult = builtins.tryEval (builtins.toXML value);
recurse = (recurseInto name).config;
configIsAnOption = v: isOption (rmProperties v);
errConfigIsAnOption =
let badModules = filter (m: configIsAnOption m.config) definitions; in
"${eol
}Option ${addName name} is defined in the configuration section.${eol
}${errorSource badModules}${eol
}";
errDefinedWithoutDeclaration =
let badModules = definitions; in
"${eol
}Option '${addName name}' defined without option declaration.${eol
}${errorSource badModules}${eol
}";
result =
if option.isOption then value
else if !option.hasOptions then throw errDefinedWithoutDeclaration
else if any configIsAnOption values then throw errConfigIsAnOption
else if all isAttrs values then recurse
# plain value during the traversal
else throw errDefinedWithoutDeclaration;
});
} modules));
fixMergeModules = initModules: {...}@args:
lib.fix (result:
# This trick avoids an infinite loop because names of attribute
# are know and it is not required to evaluate the result of
# moduleMerge to know which attributes are present as arguments.
let module = { inherit (result) options config; }; in
moduleMerge "" (
moduleClosure initModules (module // args)
)
);
# Visit all definitions to raise errors related to undeclared options.
checkModule = path: {config, options, ...}@m:
/* Hack for backward compatibility: convert options of type
optionSet to configOf. FIXME: remove eventually. */
fixupOptionType = loc: opt:
let
eol = "\n";
addName = name:
if path == "" then name else path + "." + name;
in
if lib.isOption options then
if options ? options then
options.type.fold
(cfg: res: res && checkModule (options.type.docPath path) cfg._args)
true config
else
true
else if isAttrs options && lib.attrNames m.options != [] then
all (name:
lib.addErrorContext "${eol
}while checking the attribute `${addName name}':${eol
}" (checkModule (addName name) (selectModule name m))
) (lib.attrNames m.config)
else
builtins.trace "try to evaluate config ${lib.showVal config}."
false;
options' = opt.options or
(throw "Option `${showOption loc'}' has type optionSet but has no option attribute.");
coerce = x:
if builtins.isFunction x then x
else { config, ... }: { options = x; };
options = map coerce (flatten options');
f = tp:
if tp.name == "option set" then types.submodule options
else if tp.name == "attribute set of option sets" then types.attrsOf (types.submodule options)
else if tp.name == "list or attribute set of option sets" then types.loaOf (types.submodule options)
else if tp.name == "list of option sets" then types.listOf (types.submodule options)
else if tp.name == "null or option set" then types.nullOr (types.submodule options)
else tp;
in opt // { type = f (opt.type or types.unspecified); };
/* Properties. */
mkIf = condition: content:
{ _type = "if";
inherit condition content;
};
mkAssert = assertion: message: content:
mkIf
(if assertion then true else throw "\nFailed assertion: ${message}")
content;
mkMerge = contents:
{ _type = "merge";
inherit contents;
};
mkOverride = priority: content:
{ _type = "override";
inherit priority content;
};
mkOptionDefault = mkOverride 1001; # priority of option defaults
mkDefault = mkOverride 1000; # used in config sections of non-user modules to set a default
mkForce = mkOverride 50;
mkVMOverride = mkOverride 10; # used by nixos-rebuild build-vm
mkFixStrictness = id; # obsolete, no-op
# FIXME: Add mkOrder back in. It's not currently used anywhere in
# NixOS, but it should be useful.
/* Compatibility. */
fixMergeModules = modules: args: evalModules { inherit modules args; check = false; };
}

View file

@ -2,28 +2,27 @@
let lib = import ./default.nix; in
with { inherit (builtins) head length; };
with import ./trivial.nix;
with import ./lists.nix;
with import ./misc.nix;
with import ./attrsets.nix;
with import ./properties.nix;
with import ./strings.nix;
rec {
isOption = lib.isType "option";
mkOption = attrs: attrs // {
_type = "option";
# name (this is the name of the attributem it is automatically generated by the traversal)
# default (value used when no definition exists)
# example (documentation)
# description (documentation)
# type (option type, provide a default merge function and ensure type correctness)
# merge (function used to merge definitions into one definition: [ /type/ ] -> /type/)
# apply (convert the option value to ease the manipulation of the option result)
# options (set of sub-options declarations & definitions)
# extraConfigs (list of possible configurations)
};
mkOption =
{ default ? null # Default value used when no definition is given in the configuration.
, defaultText ? null # Textual representation of the default, for in the manual.
, example ? null # Example value used in the manual.
, description ? null # String describing the option.
, type ? null # Option type, providing type-checking and value merging.
, apply ? null # Function that converts the option value to something else.
, internal ? null # Whether the option is for NixOS developers only.
, visible ? null # Whether the option shows up in the manual.
, options ? null # Obsolete, used by types.optionSet.
} @ attrs:
attrs // { _type = "option"; };
mkEnableOption = name: mkOption {
default = false;
@ -32,261 +31,65 @@ rec {
type = lib.types.bool;
};
mapSubOptions = f: opt:
if opt ? options then
opt // {
options = imap f (toList opt.options);
}
else
opt;
# Make the option declaration more user-friendly by adding default
# settings and some verifications based on the declaration content (like
# type correctness).
addOptionMakeUp = {name, recurseInto}: decl:
let
init = {
inherit name;
merge = mergeDefaultOption;
apply = lib.id;
};
functionsFromType = opt:
opt // (builtins.intersectAttrs { merge = 1; check = 1; } (decl.type or {}));
addDeclaration = opt: opt // decl;
ensureMergeInputType = opt:
if opt ? check then
opt // {
merge = list:
if all opt.check list then
opt.merge list
else
throw "A value of the option `${name}' has a bad type.";
}
else opt;
checkDefault = opt:
if opt ? check && opt ? default then
opt // {
default =
if opt.check opt.default then
opt.default
else
throw "The default value of the option `${name}' has a bad type.";
}
else opt;
handleOptionSets = opt:
if opt ? type && opt.type.hasOptions then
let
# Evaluate sub-modules.
subModuleMerge = path: vals:
lib.fix (args:
let
result = recurseInto path (opt.options ++ imap (index: v: args: {
key = rec {
#!!! Would be nice if we had the file the val was from
option = path;
number = index;
outPath = "option ${option} config number ${toString number}";
};
} // (lib.applyIfFunction v args)) (toList vals)) args;
name = lib.removePrefix (opt.name + ".") path;
extraArgs = opt.extraArgs or {};
individualExtraArgs = opt.individualExtraArgs or {};
in {
inherit (result) config options;
inherit name;
} //
(opt.extraArgs or {}) //
(if hasAttr name individualExtraArgs then getAttr name individualExtraArgs else {})
);
# Add _options in sub-modules to make it viewable from other
# modules.
subModuleMergeConfig = path: vals:
let result = subModuleMerge path vals; in
{ _args = result; } // result.config;
in
opt // {
merge = list:
opt.type.iter
subModuleMergeConfig
opt.name
(opt.merge list);
options =
let path = opt.type.docPath opt.name; in
(subModuleMerge path []).options;
}
else
opt;
in
foldl (opt: f: f opt) init [
# default settings
functionsFromType
# user settings
addDeclaration
# override settings
ensureMergeInputType
checkDefault
handleOptionSets
];
# Merge a list of options containning different field. This is useful to
# separate the merge & apply fields from the interface.
mergeOptionDecls = opts:
if opts == [] then {}
else if length opts == 1 then
let opt = head opts; in
if opt ? options then
opt // { options = toList opt.options; }
else
opt
else
fold (opt1: opt2:
lib.addErrorContext "opt1 = ${lib.showVal opt1}\nopt2 = ${lib.showVal opt2}" (
# You cannot merge if two options have the same field.
assert opt1 ? default -> ! opt2 ? default;
assert opt1 ? example -> ! opt2 ? example;
assert opt1 ? description -> ! opt2 ? description;
assert opt1 ? merge -> ! opt2 ? merge;
assert opt1 ? apply -> ! opt2 ? apply;
assert opt1 ? type -> ! opt2 ? type;
opt1 // opt2
// optionalAttrs (opt1 ? options || opt2 ? options) {
options =
(toList (opt1.options or []))
++ (toList (opt2.options or []));
}
// optionalAttrs (opt1 ? extraConfigs || opt2 ? extraConfigs) {
extraConfigs = opt1.extraConfigs or [] ++ opt2.extraConfigs or [];
}
// optionalAttrs (opt1 ? extraArgs || opt2 ? extraArgs) {
extraArgs = opt1.extraArgs or {} // opt2.extraArgs or {};
}
// optionalAttrs (opt1 ? individualExtraArgs || opt2 ? individualExtraArgs) {
individualExtraArgs = zipAttrsWith (name: values:
if length values == 1 then head values else (head values // (head (tail values)))
) [ (opt1.individualExtraArgs or {}) (opt2.individualExtraArgs or {}) ];
}
)) {} opts;
# !!! This function will be removed because this can be done with the
# multiple option declarations.
addDefaultOptionValues = defs: opts: opts //
builtins.listToAttrs (map (defName:
{ name = defName;
value =
let
defValue = builtins.getAttr defName defs;
optValue = builtins.getAttr defName opts;
in
if isOption defValue
then
# `defValue' is an option.
if hasAttr defName opts
then builtins.getAttr defName opts
else defValue.default
else
# `defValue' is an attribute set containing options.
# So recurse.
if hasAttr defName opts && isAttrs optValue
then addDefaultOptionValues defValue optValue
else addDefaultOptionValues defValue {};
}
) (attrNames defs));
mergeDefaultOption = list:
mergeDefaultOption = loc: defs:
let list = getValues defs; in
if length list == 1 then head list
else if all builtins.isFunction list then x: mergeDefaultOption (map (f: f x) list)
else if all builtins.isFunction list then x: mergeDefaultOption loc (map (f: f x) list)
else if all isList list then concatLists 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 builtins.isString list then lib.concatStrings list
else if all builtins.isInt list && all (x: x == head list) list
then head list
else throw "Cannot merge values.";
else if all builtins.isInt list && all (x: x == head list) list then head list
else throw "Cannot merge definitions of `${showOption loc}' given in ${showFiles (getFiles defs)}.";
mergeTypedOption = typeName: predicate: merge: list:
if all predicate list then merge list
else throw "Expect a ${typeName}.";
/* Obsolete, will remove soon. Specify an option type or apply
function instead. */
mergeTypedOption = typeName: predicate: merge: loc: list:
let list' = map (x: x.value) list; in
if all predicate list then merge list'
else throw "Expected a ${typeName}.";
mergeEnableOption = mergeTypedOption "boolean"
(x: true == x || false == x) (fold lib.or false);
mergeListOption = mergeTypedOption "list" isList concatLists;
mergeStringOption = mergeTypedOption "string"
(x: if builtins ? isString then builtins.isString x else x + "")
lib.concatStrings;
mergeStringOption = mergeTypedOption "string" builtins.isString lib.concatStrings;
mergeOneOption = list:
if list == [] then abort "This case should never happen."
else if length list != 1 then throw "Multiple definitions. Only one is allowed for this option."
else head list;
mergeOneOption = loc: defs:
if defs == [] then abort "This case should never happen."
else if length defs != 1 then
throw "The unique option `${showOption loc}' is defined multiple times, in ${showFiles (getFiles defs)}."
else (head defs).value;
fixableMergeFun = merge: f: config:
merge (
# generate the list of option sets.
f config
);
fixableMergeModules = merge: initModules: {...}@args: config:
fixableMergeFun merge (config:
lib.moduleClosure initModules (args // { inherit config; })
) config;
fixableDefinitionsOf = initModules: {...}@args:
fixableMergeModules (modules: (lib.moduleMerge "" modules).config) initModules args;
fixableDeclarationsOf = initModules: {...}@args:
fixableMergeModules (modules: (lib.moduleMerge "" modules).options) initModules args;
definitionsOf = initModules: {...}@args:
(lib.fix (module:
fixableMergeModules (lib.moduleMerge "") initModules args module.config
)).config;
declarationsOf = initModules: {...}@args:
(lib.fix (module:
fixableMergeModules (lib.moduleMerge "") initModules args module.config
)).options;
getValues = map (x: x.value);
getFiles = map (x: x.file);
# Generate documentation template from the list of option declaration like
# the set generated with filterOptionSets.
optionAttrSetToDocList = attrs:
let options = collect isOption attrs; in
fold (opt: rest:
let
docOption = {
inherit (opt) name;
description = opt.description or (throw "Option ${opt.name}: No description.");
declarations = map (x: toString x.source) opt.declarations;
#definitions = map (x: toString x.source) opt.definitions;
internal = opt.internal or false;
visible = opt.visible or true;
}
// optionalAttrs (opt ? example) { example = scrubOptionValue opt.example; }
// optionalAttrs (opt ? default) { default = scrubOptionValue opt.default; }
// optionalAttrs (opt ? defaultText) { default = opt.defaultText; };
optionAttrSetToDocList = optionAttrSetToDocList' [];
subOptions =
if opt ? options then
optionAttrSetToDocList opt.options
else
[];
in
[ docOption ] ++ subOptions ++ rest
) [] options;
optionAttrSetToDocList' = prefix: options:
fold (opt: rest:
let
docOption = rec {
name = showOption opt.loc;
description = opt.description or (throw "Option `${name}' has no description.");
declarations = filter (x: x != unknownModule) opt.declarations;
internal = opt.internal or false;
visible = opt.visible or true;
}
// optionalAttrs (opt ? example) { example = scrubOptionValue opt.example; }
// optionalAttrs (opt ? default) { default = scrubOptionValue opt.default; }
// optionalAttrs (opt ? defaultText) { default = opt.defaultText; };
subOptions =
let ss = opt.type.getSubOptions opt.loc;
in if ss != {} then optionAttrSetToDocList' opt.loc ss else [];
in
# FIXME: expensive, O(n^2)
[ docOption ] ++ subOptions ++ rest) [] (collect isOption options);
/* This function recursively removes all derivation attributes from
@ -295,7 +98,8 @@ rec {
representation of derivations is very large (on the order of
megabytes) and is not actually used by the manual generator. */
scrubOptionValue = x:
if isDerivation x then { type = "derivation"; drvPath = x.name; outPath = x.name; name = x.name; }
if isDerivation x then
{ type = "derivation"; drvPath = x.name; outPath = x.name; name = x.name; }
else if isList x then map scrubOptionValue x
else if isAttrs x then mapAttrs (n: v: scrubOptionValue v) (removeAttrs x ["_args"])
else x;
@ -308,4 +112,9 @@ rec {
literalExample = text: { _type = "literalExample"; inherit text; };
/* Helper functions. */
showOption = concatStringsSep ".";
showFiles = files: concatStringsSep " and " (map (f: "`${f}'") files);
unknownModule = "<unknown-file>";
}

View file

@ -1,464 +0,0 @@
# Nixpkgs/NixOS properties. Generalize the problem of delayable (not yet
# evaluable) properties like mkIf.
let lib = import ./default.nix; in
with { inherit (builtins) head tail; };
with import ./trivial.nix;
with import ./lists.nix;
with import ./misc.nix;
with import ./attrsets.nix;
rec {
inherit (lib) isType;
# Tell that nothing is defined. When properties are evaluated, this type
# is used to remove an entry. Thus if your property evaluation semantic
# implies that you have to mute the content of an attribute, then your
# property should produce this value.
isNotdef = isType "notdef";
mkNotdef = {_type = "notdef";};
# General property type, it has a property attribute and a content
# attribute. The property attribute refers to an attribute set which
# contains a _type attribute and a list of functions which are used to
# evaluate this property. The content attribute is used to stack properties
# on top of each other.
#
# The optional functions which may be contained in the property attribute
# are:
# - onDelay: run on a copied property.
# - onGlobalDelay: run on all copied properties.
# - onEval: run on an evaluated property.
# - onGlobalEval: run on a list of property stack on top of their values.
isProperty = isType "property";
mkProperty = p@{property, content, ...}: p // {
_type = "property";
};
# Go through the stack of properties and apply the function `op' on all
# property and call the function `nul' on the final value which is not a
# property. The stack is traversed in reversed order. The `op' function
# should expect a property with a content which have been modified.
#
# Warning: The `op' function expects only one argument in order to avoid
# calls to mkProperties as the argument is already a valid property which
# contains the result of the folding inside the content attribute.
foldProperty = op: nul: attrs:
if isProperty attrs then
op (attrs // {
content = foldProperty op nul attrs.content;
})
else
nul attrs;
# Simple function which can be used as the `op' argument of the
# foldProperty function. Properties that you don't want to handle can be
# ignored with the `id' function. `isSearched' is a function which should
# check the type of a property and return a boolean value. `thenFun' and
# `elseFun' are functions which behave as the `op' argument of the
# foldProperty function.
foldFilter = isSearched: thenFun: elseFun: attrs:
if isSearched attrs.property then
thenFun attrs
else
elseFun attrs;
# Move properties from the current attribute set to the attribute
# contained in this attribute set. This trigger property handlers called
# `onDelay' and `onGlobalDelay'.
delayPropertiesWithIter = iter: path: attrs:
let cleanAttrs = rmProperties attrs; in
if isProperty attrs then
iter (a: v:
lib.addErrorContext "while moving properties on the attribute `${a}':" (
triggerPropertiesGlobalDelay a (
triggerPropertiesDelay a (
copyProperties attrs v
)))) path cleanAttrs
else
attrs;
delayProperties = # implicit attrs argument.
let
# mapAttrs except that it also recurse into potential mkMerge
# functions. This may cause a strictness issue because looking the
# type of a string implies evaluating it.
iter = fun: path: value:
lib.mapAttrs (attr: val:
if isProperty val && isMerge val.property then
val // { content = map (fun attr) val.content; }
else
fun attr val
) value;
in
delayPropertiesWithIter iter "";
# Call onDelay functions.
triggerPropertiesDelay = name: attrs:
let
callOnDelay = p@{property, ...}:
if property ? onDelay then
property.onDelay name p
else
p;
in
foldProperty callOnDelay id attrs;
# Call onGlobalDelay functions.
triggerPropertiesGlobalDelay = name: attrs:
let
globalDelayFuns = uniqListExt {
getter = property: property._type;
inputList = foldProperty (p@{property, content, ...}:
if property ? onGlobalDelay then
[ property ] ++ content
else
content
) (a: []) attrs;
};
callOnGlobalDelay = property: content:
property.onGlobalDelay name content;
in
fold callOnGlobalDelay attrs globalDelayFuns;
# Expect a list of values which may have properties and return the same
# list of values where all properties have been evaluated and where all
# ignored values are removed. This trigger property handlers called
# `onEval' and `onGlobalEval'.
evalProperties = valList:
if valList != [] then
filter (x: !isNotdef x) (
triggerPropertiesGlobalEval (
evalLocalProperties valList
)
)
else
valList;
evalLocalProperties = valList:
filter (x: !isNotdef x) (
map triggerPropertiesEval valList
);
# Call onEval function
triggerPropertiesEval = val:
foldProperty (p@{property, ...}:
if property ? onEval then
property.onEval p
else
p
) id val;
# Call onGlobalEval function
triggerPropertiesGlobalEval = valList:
let
globalEvalFuns = uniqListExt {
getter = property: property._type;
inputList =
fold (attrs: list:
foldProperty (p@{property, content, ...}:
if property ? onGlobalEval then
[ property ] ++ content
else
content
) (a: list) attrs
) [] valList;
};
callOnGlobalEval = property: valList: property.onGlobalEval valList;
in
fold callOnGlobalEval valList globalEvalFuns;
# Remove all properties on top of a value and return the value.
rmProperties =
foldProperty (p@{content, ...}: content) id;
# Copy properties defined on a value on another value.
copyProperties = attrs: newAttrs:
foldProperty id (x: newAttrs) attrs;
/* Merge. */
# Create "merge" statement which is skipped by the delayProperty function
# and interpreted by the underlying system using properties (modules).
# Create a "Merge" property which only contains a condition.
isMerge = isType "merge";
mkMerge = content: mkProperty {
property = {
_type = "merge";
onDelay = name: val: throw "mkMerge is not the first of the list of properties.";
onEval = val: throw "mkMerge is not allowed on option definitions.";
};
inherit content;
};
/* If. ThenElse. Always. */
# create "if" statement that can be delayed on sets until a "then-else" or
# "always" set is reached. When an always set is reached the condition
# is ignore.
# Create a "If" property which only contains a condition.
isIf = isType "if";
mkIf = condition: content: mkProperty {
property = {
_type = "if";
onGlobalDelay = onIfGlobalDelay;
onEval = onIfEval;
inherit condition;
};
inherit content;
};
mkAssert = assertion: message: content:
mkIf
(if assertion then true else throw "\nFailed assertion: ${message}")
content;
# Evaluate the "If" statements when either "ThenElse" or "Always"
# statement is encountered. Otherwise it removes multiple If statements and
# replaces them by one "If" statement where the condition is the list of all
# conditions joined with a "and" operation.
onIfGlobalDelay = name: content:
let
# extract if statements and non-if statements and repectively put them
# in the attribute list and attrs.
ifProps =
foldProperty
(foldFilter (p: isIf p)
# then, push the condition inside the list list
(p@{property, content, ...}:
{ inherit (content) attrs;
list = [property] ++ content.list;
}
)
# otherwise, add the propertie.
(p@{property, content, ...}:
{ inherit (content) list;
attrs = p // { content = content.attrs; };
}
)
)
(attrs: { list = []; inherit attrs; })
content;
# compute the list of if statements.
evalIf = content: condition: list:
if list == [] then
mkIf condition content
else
let p = head list; in
evalIf content (condition && p.condition) (tail list);
in
evalIf ifProps.attrs true ifProps.list;
# Evaluate the condition of the "If" statement to either get the value or
# to ignore the value.
onIfEval = p@{property, content, ...}:
if property.condition then
content
else
mkNotdef;
/* mkOverride */
# Create an "Override" statement which allow the user to define
# priorities between values. The default priority is 100. The lowest
# priorities are kept. The template argument must reproduce the same
# attribute set hierarchy to override leaves of the hierarchy.
isOverride = isType "override";
mkOverrideTemplate = priority: template: content: mkProperty {
property = {
_type = "override";
onDelay = onOverrideDelay;
onGlobalEval = onOverrideGlobalEval;
inherit priority template;
};
inherit content;
};
# Like mkOverrideTemplate, but without the template argument.
mkOverride = priority: content: mkOverrideTemplate priority {} content;
# Sugar to override the default value of the option by making a new
# default value based on the configuration.
mkDefaultValue = mkOverride 1000;
mkDefault = mkOverride 1000;
mkForce = mkOverride 50;
mkStrict = mkOverride 0;
# Make the template traversal in function of the property traversal. If
# the template define a non-empty attribute set, then the property is
# copied only on all mentionned attributes inside the template.
# Otherwise, the property is kept on all sub-attribute definitions.
onOverrideDelay = name: p@{property, content, ...}:
let inherit (property) template; in
if isAttrs template && template != {} then
if hasAttr name template then
p // {
property = p.property // {
template = builtins.getAttr name template;
};
}
# Do not override the attribute \name\
else
content
# Override values defined inside the attribute \name\.
else
p;
# Keep values having lowest priority numbers only throwing away those having
# a higher priority assigned.
onOverrideGlobalEval = valList:
let
defaultPrio = 100;
inherit (builtins) lessThan;
getPrioVal =
foldProperty
(foldFilter isOverride
(p@{property, content, ...}:
if content ? priority && lessThan content.priority property.priority then
content
else
content // {
inherit (property) priority;
}
)
(p@{property, content, ...}:
content // {
value = p // { content = content.value; };
}
)
) (value: { inherit value; });
addDefaultPrio = x:
if x ? priority then x
else x // { priority = defaultPrio; };
prioValList = map (x: addDefaultPrio (getPrioVal x)) valList;
higherPrio =
if prioValList == [] then
defaultPrio
else
fold (x: min:
if lessThan x.priority min then
x.priority
else
min
) (head prioValList).priority (tail prioValList);
in
map (x:
if x.priority == higherPrio then
x.value
else
mkNotdef
) prioValList;
/* mkOrder */
# Order definitions based on there index value. This property is useful
# when the result of the merge function depends on the order on the
# initial list. (e.g. concatStrings) Definitions are ordered based on
# their rank. The lowest ranked definition would be the first to element
# of the list used by the merge function. And the highest ranked
# definition would be the last. Definitions which does not have any rank
# value have the default rank of 100.
isOrder = isType "order";
mkOrder = rank: content: mkProperty {
property = {
_type = "order";
onGlobalEval = onOrderGlobalEval;
inherit rank;
};
inherit content;
};
mkHeader = mkOrder 10;
mkFooter = mkOrder 1000;
# Fetch the rank of each definition (add the default rank is none) and
# sort them based on their ranking.
onOrderGlobalEval = valList:
let
defaultRank = 100;
inherit (builtins) lessThan;
getRankVal =
foldProperty
(foldFilter isOrder
(p@{property, content, ...}:
if content ? rank then
content
else
content // {
inherit (property) rank;
}
)
(p@{property, content, ...}:
content // {
value = p // { content = content.value; };
}
)
) (value: { inherit value; });
addDefaultRank = x:
if x ? rank then x
else x // { rank = defaultRank; };
rankValList = map (x: addDefaultRank (getRankVal x)) valList;
cmp = x: y:
builtins.lessThan x.rank y.rank;
in
map (x: x.value) (sort cmp rankValList);
/* mkFixStrictness */
# This is a hack used to restore laziness on some option definitions.
# Some option definitions are evaluated when they are not used. This
# error is caused by the strictness of type checking builtins. Builtins
# like 'isAttrs' are too strict because they have to evaluate their
# arguments to check if the type is correct. This evaluation, cause the
# strictness of properties.
#
# Properties can be stacked on top of each other. The stackability of
# properties on top of the option definition is nice for user manipulation
# but require to check if the content of the property is not another
# property. Such testing implies to verify if this is an attribute set
# and if it possess the type 'property'. (see isProperty & typeOf/isType)
#
# To avoid strict evaluation of option definitions, 'mkFixStrictness' is
# introduced. This property protects an option definition by replacing
# the base of the stack of properties by 'mkNotDef', when this property is
# evaluated it returns the original definition.
#
# This property is useful over any elements which depends on options which
# are raising errors when they get evaluated without the proper settings.
#
# Plain list and attribute set are lazy structures, which means that the
# container gets evaluated but not the content. Thus, using this property
# on top of plain list or attribute set is pointless.
#
# This is a Hack, you should avoid it!
# This property has a long name because you should avoid it.
isFixStrictness = attrs: (typeOf attrs) == "fix-strictness";
mkFixStrictness = value:
mkProperty {
property = {
_type = "fix-strictness";
onEval = p: value;
};
content = mkNotdef;
};
}

View file

@ -22,7 +22,7 @@ rec {
};
isCpuType = x: typeOf x == "cpu-type"
isCpuType = x: isType "cpu-type" x
&& elem x.bits [8 16 32 64 128]
&& (builtins.lessThan 8 x.bits -> isSignificantByte x.significantByte);
@ -69,7 +69,7 @@ rec {
};
isSystem = x: typeOf x == "system"
isSystem = x: isType "system" x
&& isCpuType x.cpu
&& isArchitecture x.arch
&& isKernel x.kernel;

View file

@ -1,17 +1,15 @@
# Definitions related to run-time type checking. Used in particular
# to type-check NixOS configurations.
let lib = import ./default.nix; in
with import ./lists.nix;
with import ./attrsets.nix;
with import ./options.nix;
with import ./trivial.nix;
with import ./strings.nix;
rec {
isType = type: x: (x._type or "") == type;
hasType = x: isAttrs x && x ? _type;
typeOf = x: x._type or "";
setType = typeName: value: value // {
@ -19,208 +17,194 @@ rec {
};
# name (name of the type)
# check (check the config value. Before returning false it should trace the bad value eg using traceValIfNot)
# merge (default merge function)
# iter (iterate on all elements contained in this type)
# fold (fold all elements contained in this type)
# hasOptions (boolean: whatever this option contains an option set)
# delayOnGlobalEval (boolean: should properties go through the evaluation of this option)
# docPath (path concatenated to the option name contained in the option set)
isOptionType = isType "option-type";
mkOptionType =
{ name
, check ? (x: true)
, merge ? mergeDefaultOption
# Handle complex structure types.
, iter ? (f: path: v: f path v)
, fold ? (op: nul: v: op v nul)
, docPath ? lib.id
# If the type can contains option sets.
, hasOptions ? false
, delayOnGlobalEval ? false
{ # 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.
# This function is called with two arguments: the location of
# the option in the configuration as a list of strings
# (e.g. ["boot" "loader "grub" "enable"]), and a list of
# definition values and locations (e.g. [ { file = "/foo.nix";
# value = 1; } { file = "/bar.nix"; value = 2 } ]).
merge ? mergeDefaultOption
, # Return a flat list of sub-options. Used to generate
# documentation.
getSubOptions ? prefix: {}
}:
{ _type = "option-type";
inherit name check merge iter fold docPath hasOptions delayOnGlobalEval;
inherit name check merge getSubOptions;
};
types = rec {
unspecified = mkOptionType {
name = "unspecified";
};
bool = mkOptionType {
name = "boolean";
check = lib.traceValIfNot builtins.isBool;
merge = fold lib.or false;
check = builtins.isBool;
merge = loc: fold (x: y: x.value || y) false;
};
int = mkOptionType {
name = "integer";
check = lib.traceValIfNot builtins.isInt;
check = builtins.isInt;
merge = mergeOneOption;
};
string = mkOptionType {
str = mkOptionType {
name = "string";
check = lib.traceValIfNot builtins.isString;
merge = lib.concatStrings;
check = builtins.isString;
merge = mergeOneOption;
};
# Like string, but add newlines between every value. Useful for
# configuration file contents.
lines = mkOptionType {
# Merge multiple definitions by concatenating them (with the given
# separator between the values).
separatedString = sep: mkOptionType {
name = "string";
check = lib.traceValIfNot builtins.isString;
merge = lib.concatStringsSep "\n";
check = builtins.isString;
merge = loc: defs: concatStringsSep sep (getValues defs);
};
envVar = mkOptionType {
name = "environment variable";
inherit (string) check;
merge = lib.concatStringsSep ":";
};
lines = separatedString "\n";
commas = separatedString ",";
envVar = separatedString ":";
# Deprecated; should not be used because it quietly concatenates
# strings, which is usually not what you want.
string = separatedString "";
attrs = mkOptionType {
name = "attribute set";
check = lib.traceValIfNot isAttrs;
merge = fold lib.mergeAttrs {};
check = isAttrs;
merge = loc: fold (def: mergeAttrs def.value) {};
};
# derivation is a reserved keyword.
package = mkOptionType {
name = "derivation";
check = lib.traceValIfNot isDerivation;
check = isDerivation;
merge = mergeOneOption;
};
path = mkOptionType {
name = "path";
# Hacky: there is no isPath primop.
check = lib.traceValIfNot (x: builtins.unsafeDiscardStringContext (builtins.substring 0 1 (toString x)) == "/");
check = x: builtins.unsafeDiscardStringContext (builtins.substring 0 1 (toString x)) == "/";
merge = mergeOneOption;
};
# drop this in the future:
list = builtins.trace "types.list is deprecated, use types.listOf instead" types.listOf;
list = builtins.trace "`types.list' is deprecated; use `types.listOf' instead" types.listOf;
listOf = elemType: mkOptionType {
listOf = elemType: mkOptionType {
name = "list of ${elemType.name}s";
check = value: lib.traceValIfNot isList value && all elemType.check value;
merge = concatLists;
iter = f: path: list: map (elemType.iter f (path + ".*")) list;
fold = op: nul: list: lib.fold (e: l: elemType.fold op l e) nul list;
docPath = path: elemType.docPath (path + ".*");
inherit (elemType) hasOptions;
# You cannot define multiple configurations of one entity, therefore
# no reason justify to delay properties inside list elements.
delayOnGlobalEval = false;
check = value: isList value && all elemType.check value;
merge = loc: defs:
concatLists (imap (n: def: imap (m: def':
elemType.merge (loc ++ ["[${toString n}-${toString m}]"])
[{ inherit (def) file; value = def'; }]) def.value) defs);
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["*"]);
};
attrsOf = elemType: mkOptionType {
name = "attribute set of ${elemType.name}s";
check = x: lib.traceValIfNot isAttrs x
&& all elemType.check (lib.attrValues x);
merge = lib.zipAttrsWith (name: elemType.merge);
iter = f: path: set: lib.mapAttrs (name: elemType.iter f (path + "." + name)) set;
fold = op: nul: set: fold (e: l: elemType.fold op l e) nul (lib.attrValues set);
docPath = path: elemType.docPath (path + ".<name>");
inherit (elemType) hasOptions delayOnGlobalEval;
check = x: isAttrs x && all elemType.check (attrValues x);
merge = loc: defs:
zipAttrsWith (name: elemType.merge (loc ++ [name]))
# Push down position info.
(map (def: listToAttrs (mapAttrsToList (n: def':
{ name = n; value = { inherit (def) file; value = def'; }; }) def.value)) defs);
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name>"]);
};
# List or attribute set of ...
loaOf = elemType:
let
convertIfList = defIdx: def:
if isList def then
listToAttrs (
flip imap def (elemIdx: elem:
nameValuePair "unnamed-${toString defIdx}.${toString elemIdx}" elem))
if isList def.value then
{ inherit (def) file;
value = listToAttrs (
imap (elemIdx: elem:
{ name = "unnamed-${toString defIdx}.${toString elemIdx}";
value = elem;
}) def.value);
}
else
def;
listOnly = listOf elemType;
attrOnly = attrsOf elemType;
in mkOptionType {
name = "list or attribute set of ${elemType.name}s";
check = x:
if isList x then listOnly.check x
else if isAttrs x then attrOnly.check x
else lib.traceValIfNot (x: false) x;
## The merge function returns an attribute set
merge = defs:
attrOnly.merge (imap convertIfList defs);
iter = f: path: def:
if isList def then listOnly.iter f path def
else if isAttrs def then attrOnly.iter f path def
else throw "Unexpected value";
fold = op: nul: def:
if isList def then listOnly.fold op nul def
else if isAttrs def then attrOnly.fold op nul def
else throw "Unexpected value";
docPath = path: elemType.docPath (path + ".<name?>");
inherit (elemType) hasOptions delayOnGlobalEval;
}
;
else false;
merge = loc: defs: attrOnly.merge loc (imap convertIfList defs);
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name?>"]);
};
uniq = elemType: mkOptionType {
inherit (elemType) name check iter fold docPath hasOptions;
merge = list:
if length list == 1 then
head list
else
throw "Multiple definitions of ${elemType.name}. Only one is allowed for this option.";
};
none = elemType: mkOptionType {
inherit (elemType) name check iter fold docPath hasOptions;
merge = list:
throw "No definitions are allowed for this option.";
inherit (elemType) name check;
merge = mergeOneOption;
getSubOptions = elemType.getSubOptions;
};
nullOr = elemType: mkOptionType {
inherit (elemType) name merge docPath hasOptions;
name = "null or ${elemType.name}";
check = x: builtins.isNull x || elemType.check x;
iter = f: path: v: if v == null then v else elemType.iter f path v;
fold = op: nul: v: if v == null then nul else elemType.fold op nul v;
merge = loc: defs:
let nrNulls = count (def: isNull def.value) defs; in
if nrNulls == length defs then null
else if nrNulls != 0 then
throw "The option `${showOption loc}' is defined both null and not null, in ${showFiles (getFiles defs)}."
else elemType.merge loc defs;
getSubOptions = elemType.getSubOptions;
};
functionTo = elemType: mkOptionType {
name = "function that evaluates to a(n) ${elemType.name}";
check = lib.traceValIfNot builtins.isFunction;
merge = fns:
args: elemType.merge (map (fn: fn args) fns);
# These are guesses, I don't fully understand iter, fold, delayOnGlobalEval
iter = f: path: v:
args: elemType.iter f path (v args);
fold = op: nul: v:
args: elemType.fold op nul (v args);
inherit (elemType) delayOnGlobalEval;
hasOptions = false;
check = builtins.isFunction;
merge = loc: defs:
fnArgs: elemType.merge loc (map (fn: { inherit (fn) file; value = fn.value fnArgs; }) defs);
getSubOptions = elemType.getSubOptions;
};
# usually used with listOf, attrsOf, loaOf like this:
# users = mkOption {
# type = loaOf optionSet;
#
# # you can omit the list if there is one element only
# options = [ {
# name = mkOption {
# description = "name of the user"
# ...
# };
# # more options here
# } { more options } ];
# }
# TODO: !!! document passing options as an argument to optionSet,
# deprecate the current approach.
submodule = opts:
let
opts' = toList opts;
inherit (import ./modules.nix) evalModules;
in
mkOptionType rec {
name = "submodule";
check = x: isAttrs x || builtins.isFunction x;
merge = loc: defs:
let
coerce = def: if builtins.isFunction def then def else { config = def; };
modules = opts' ++ map (def: { _file = def.file; imports = [(coerce def.value)]; }) defs;
in (evalModules { inherit modules; args.name = last loc; prefix = loc; }).config;
getSubOptions = prefix: (evalModules
{ modules = opts'; inherit prefix;
# FIXME: hack to get shit to evaluate.
args = { name = ""; }; }).options;
};
# Obsolete alternative to configOf. It takes its option
# declarations from the options attribute of containing option
# declaration.
optionSet = mkOptionType {
name = "option set";
# merge is done in "options.nix > addOptionMakeUp > handleOptionSets"
merge = lib.id;
check = x: isAttrs x || builtins.isFunction x;
hasOptions = true;
delayOnGlobalEval = true;
name = /* builtins.trace "types.optionSet is deprecated; use types.submodule instead" */ "option set";
};
# Augment the given type with an additional type check function.
addCheck = elemType: check: elemType // { check = x: elemType.check x && check x; };
};
}

View file

@ -9,7 +9,7 @@ let
modules = [ configuration ];
};
inherit (eval) config pkgs;
inherit (eval) pkgs;
# This is for `nixos-rebuild build-vm'.
vmConfig = (import ./lib/eval-config.nix {
@ -30,9 +30,9 @@ let
in
{
inherit eval config;
inherit (eval) config options;
system = config.system.build.toplevel;
system = eval.config.system.build.toplevel;
vm = vmConfig.system.build.vm;

View file

@ -7,7 +7,7 @@
<para>This chapter describes how to configure various aspects of a
NixOS machine through the configuration file
<filename>/etc/nixos/configuration.nix</filename>. As described in
<xref linkend="sec-changing-config" />, changes to that file only take
<xref linkend="sec-changing-config" />, changes to this file only take
effect after you run <command>nixos-rebuild</command>.</para>
@ -15,7 +15,703 @@ effect after you run <command>nixos-rebuild</command>.</para>
<section xml:id="sec-configuration-syntax"><title>Configuration syntax</title>
<para>TODO</para>
<section><title>The basics</title>
<para>The NixOS configuration file
<filename>/etc/nixos/configuration.nix</filename> is actually a
<emphasis>Nix expression</emphasis>, which is the Nix package
managers purely functional language for describing how to build
packages and configurations. This means you have all the expressive
power of that language at your disposal, including the ability to
abstract over common patterns, which is very useful when managing
complex systems. The syntax and semantics of the Nix language are
fully described in the <link
xlink:href="http://nixos.org/nix/manual/#chap-writing-nix-expressions">Nix
manual</link>, but here we give a short overview of the most important
constructs useful in NixOS configuration files.</para>
<para>The NixOS configuration file generally looks like this:
<programlisting>
{ config, pkgs, ... }:
{ <replaceable>option definitions</replaceable>
}
</programlisting>
The first line (<literal>{ config, pkgs, ... }:</literal>) denotes
that this is actually a function that takes at least the two arguments
<varname>config</varname> and <varname>pkgs</varname>. (These are
explained later.) The function returns a <emphasis>set</emphasis> of
option definitions (<literal>{ <replaceable>...</replaceable> }</literal>). These definitions have the
form <literal><replaceable>name</replaceable> =
<replaceable>value</replaceable></literal>, where
<replaceable>name</replaceable> is the name of an option and
<replaceable>value</replaceable> is its value. For example,
<programlisting>
{ config, pkgs, ... }:
{ services.httpd.enable = true;
services.httpd.adminAddr = "alice@example.org";
services.httpd.documentRoot = "/webroot";
}
</programlisting>
defines a configuration with three option definitions that together
enable the Apache HTTP Server with <filename>/webroot</filename> as
the document root.</para>
<para>Sets can be nested, and in fact dots in option names are
shorthand for defining a set containing another set. For instance,
<option>services.httpd.enable</option> defines a set named
<varname>services</varname> that contains a set named
<varname>httpd</varname>, which in turn contains an option definition
named <varname>enable</varname> with value <literal>true</literal>.
This means that the example above can also be written as:
<programlisting>
{ config, pkgs, ... }:
{ services = {
httpd = {
enable = true;
adminAddr = "alice@example.org";
documentRoot = "/webroot";
};
};
}
</programlisting>
which may be more convenient if you have lots of option definitions
that share the same prefix (such as
<literal>services.httpd</literal>).</para>
<para>NixOS checks your option definitions for correctness. For
instance, if you try to define an option that doesnt exist (that is,
doesnt have a corresponding <emphasis>option declaration</emphasis>),
<command>nixos-rebuild</command> will give an error like:
<screen>
The option `services.httpd.enabl' defined in `/etc/nixos/configuration.nix' does not exist.
</screen>
Likewise, values in option definitions must have a correct type. For
instance, <option>services.httpd.enable</option> must be a Boolean
(<literal>true</literal> or <literal>false</literal>). Trying to give
it a value of another type, such as a string, will cause an error:
<screen>
The option value `services.httpd.enable' in `/etc/nixos/configuration.nix' is not a boolean.
</screen>
</para>
<para>Options have various types of values. The most important are:
<variablelist>
<varlistentry>
<term>Strings</term>
<listitem>
<para>Strings are enclosed in double quotes, e.g.
<programlisting>
networking.hostName = "dexter";
</programlisting>
Special characters can be escaped by prefixing them with a
backslash (e.g. <literal>\"</literal>).</para>
<para>Multi-line strings can be enclosed in <emphasis>double
single quotes</emphasis>, e.g.
<programlisting>
networking.extraHosts =
''
127.0.0.2 other-localhost
10.0.0.1 server
'';
</programlisting>
The main difference is that preceding whitespace is
automatically stripped from each line, and that characters like
<literal>"</literal> and <literal>\</literal> are not special
(making it more convenient for including things like shell
code).</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Booleans</term>
<listitem>
<para>These can be <literal>true</literal> or
<literal>false</literal>, e.g.
<programlisting>
networking.firewall.enable = true;
networking.firewall.allowPing = false;
</programlisting>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Integers</term>
<listitem>
<para>For example,
<programlisting>
boot.kernel.sysctl."net.ipv4.tcp_keepalive_time" = 60;
</programlisting>
(Note that here the attribute name
<literal>net.ipv4.tcp_keepalive_time</literal> is enclosed in
quotes to prevent it from being interpreted as a set named
<literal>net</literal> containing a set named
<literal>ipv4</literal>, and so on. This is because its not a
NixOS option but the literal name of a Linux kernel
setting.)</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Sets</term>
<listitem>
<para>Sets were introduced above. They are name/value pairs
enclosed in braces, as in the option definition
<programlisting>
fileSystems."/boot" =
{ device = "/dev/sda1";
fsType = "ext4";
options = "rw,data=ordered,relatime";
};
</programlisting>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Lists</term>
<listitem>
<para>The important thing to note about lists is that list
elements are separated by whitespace, like this:
<programlisting>
boot.kernelModules = [ "fuse" "kvm-intel" "coretemp" ];
</programlisting>
List elements can be any other type, e.g. sets:
<programlisting>
swapDevices = [ { device = "/dev/disk/by-label/swap"; } ];
</programlisting>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Packages</term>
<listitem>
<para>Usually, the packages you need are already part of the Nix
Packages collection, which is a set that can be accessed through
the function argument <varname>pkgs</varname>. Typical uses:
<programlisting>
environment.systemPackages =
[ pkgs.thunderbird
pkgs.emacs
];
postgresql.package = pkgs.postgresql90;
</programlisting>
The latter option definition changes the default PostgreSQL
package used by NixOSs PostgreSQL service to 9.0. For more
information on packages, including how to add new ones, see
<xref linkend="sec-custom-packages"/>.</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</section>
<section><title>Abstractions</title>
<para>If you find yourself repeating yourself over and over, its time
to abstract. Take, for instance, this Apache HTTP Server configuration:
<programlisting>
{
services.httpd.virtualHosts =
[ { hostName = "example.org";
documentRoot = "/webroot";
adminAddr = "alice@example.org";
enableUserDir = true;
}
{ hostName = "example.org";
documentRoot = "/webroot";
adminAddr = "alice@example.org";
enableUserDir = true;
enableSSL = true;
sslServerCert = "/root/ssl-example-org.crt";
sslServerKey = "/root/ssl-example-org.key";
}
];
}
</programlisting>
It defines two virtual hosts with nearly identical configuration; the
only difference is that the second one has SSL enabled. To prevent
this duplication, we can use a <literal>let</literal>:
<programlisting>
let
exampleOrgCommon =
{ hostName = "example.org";
documentRoot = "/webroot";
adminAddr = "alice@example.org";
enableUserDir = true;
};
in
{
services.httpd.virtualHosts =
[ exampleOrgCommon
(exampleOrgCommon // {
enableSSL = true;
sslServerCert = "/root/ssl-example-org.crt";
sslServerKey = "/root/ssl-example-org.key";
})
];
}
</programlisting>
The <literal>let exampleOrgCommon =
<replaceable>...</replaceable></literal> defines a variable named
<literal>exampleOrgCommon</literal>. The <literal>//</literal>
operator merges two attribute sets, so the configuration of the second
virtual host is the set <literal>exampleOrgCommon</literal> extended
with the SSL options.</para>
<para>You can write a <literal>let</literal> wherever an expression is
allowed. Thus, you also could have written:
<programlisting>
{
services.httpd.virtualHosts =
let exampleOrgCommon = <replaceable>...</replaceable>; in
[ exampleOrgCommon
(exampleOrgCommon // { <replaceable>...</replaceable> })
];
}
</programlisting>
but not <literal>{ let exampleOrgCommon =
<replaceable>...</replaceable>; in <replaceable>...</replaceable>;
}</literal> since attributes (as opposed to attribute values) are not
expressions.</para>
<para><emphasis>Functions</emphasis> provide another method of
abstraction. For instance, suppose that we want to generate lots of
different virtual hosts, all with identical configuration except for
the host name. This can be done as follows:
<programlisting>
{
services.httpd.virtualHosts =
let
makeVirtualHost = name:
{ hostName = name;
documentRoot = "/webroot";
adminAddr = "alice@example.org";
};
in
[ (makeVirtualHost "example.org")
(makeVirtualHost "example.com")
(makeVirtualHost "example.gov")
(makeVirtualHost "example.nl")
];
}
</programlisting>
Here, <varname>makeVirtualHost</varname> is a function that takes a
single argument <literal>name</literal> and returns the configuration
for a virtual host. That function is then called for several names to
produce the list of virtual host configurations.</para>
<para>We can further improve on this by using the function
<varname>map</varname>, which applies another function to every
element in a list:
<programlisting>
{
services.httpd.virtualHosts =
let
makeVirtualHost = <replaceable>...</replaceable>;
in map makeVirtualHost
[ "example.org" "example.com" "example.gov" "example.nl" ];
}
</programlisting>
(The function <literal>map</literal> is called a
<emphasis>higher-order function</emphasis> because it takes another
function as an argument.)</para>
<para>What if you need more than one argument, for instance, if we
want to use a different <literal>documentRoot</literal> for each
virtual host? Then we can make <varname>makeVirtualHost</varname> a
function that takes a <emphasis>set</emphasis> as its argument, like this:
<programlisting>
{
services.httpd.virtualHosts =
let
makeVirtualHost = { name, root }:
{ hostName = name;
documentRoot = root;
adminAddr = "alice@example.org";
};
in map makeVirtualHost
[ { name = "example.org"; root = "/sites/example.org"; }
{ name = "example.com"; root = "/sites/example.com"; }
{ name = "example.gov"; root = "/sites/example.gov"; }
{ name = "example.nl"; root = "/sites/example.nl"; }
];
}
</programlisting>
But in this case (where every root is a subdirectory of
<filename>/sites</filename> named after the virtual host), it would
have been shorter to define <varname>makeVirtualHost</varname> as
<programlisting>
makeVirtualHost = name:
{ hostName = name;
documentRoot = "/sites/${name}";
adminAddr = "alice@example.org";
};
</programlisting>
Here, the construct
<literal>${<replaceable>...</replaceable>}</literal> allows the result
of an expression to be spliced into a string.</para>
</section>
<section><title>Modularity</title>
<para>The NixOS configuration mechanism is modular. If your
<filename>configuration.nix</filename> becomes too big, you can split
it into multiple files. Likewise, if you have multiple NixOS
configurations (e.g. for different computers) with some commonality,
you can move the common configuration into a shared file.</para>
<para>Modules have exactly the same syntax as
<filename>configuration.nix</filename>. In fact,
<filename>configuration.nix</filename> is itself a module. You can
use other modules by including them from
<filename>configuration.nix</filename>, e.g.:
<programlisting>
{ config, pkgs, ... }:
{ imports = [ ./vpn.nix ./kde.nix ];
services.httpd.enable = true;
environment.systemPackages = [ pkgs.emacs ];
<replaceable>...</replaceable>
}
</programlisting>
Here, we include two modules from the same directory,
<filename>vpn.nix</filename> and <filename>kde.nix</filename>. The
latter might look like this:
<programlisting>
{ config, pkgs, ... }:
{ services.xserver.enable = true;
services.xserver.displayManager.kdm.enable = true;
services.xserver.desktopManager.kde4.enable = true;
environment.systemPackages = [ pkgs.kde4.kscreensaver ];
}
</programlisting>
Note that both <filename>configuration.nix</filename> and
<filename>kde.nix</filename> define the option
<option>environment.systemPackages</option>. When multiple modules
define an option, NixOS will try to <emphasis>merge</emphasis> the
definitions. In the case of
<option>environment.systemPackages</option>, thats easy: the lists of
packages can simply be concatenated. For other types of options, a
merge may not be possible: for instance, if two modules define
<option>services.httpd.adminAddr</option>,
<command>nixos-rebuild</command> will give an error:
<screen>
The unique option `services.httpd.adminAddr' is defined multiple times, in `/etc/nixos/httpd.nix' and `/etc/nixos/configuration.nix'.
</screen>
When that happens, its possible to force one definition take
precedence over the others:
<programlisting>
services.httpd.adminAddr = pkgs.lib.mkForce "bob@example.org";
</programlisting>
</para>
<para>When using multiple modules, you may need to access
configuration values defined in other modules. This is what the
<varname>config</varname> function argument is for: it contains the
complete, merged system configuration. That is,
<varname>config</varname> is the result of combining the
configurations returned by every module<footnote><para>If youre
wondering how its possible that the (indirect)
<emphasis>result</emphasis> of a function is passed as an
<emphasis>input</emphasis> to that same function: thats because Nix
is a “lazy” language — it only computes values when they are needed.
This works as long as no individual configuration value depends on
itself.</para></footnote>. For example, here is a module that adds
some packages to <option>environment.systemPackages</option> only if
<option>services.xserver.enable</option> is set to
<literal>true</literal> somewhere else:
<programlisting>
{ config, pkgs, ... }:
{ environment.systemPackages =
if config.services.xserver.enable then
[ pkgs.firefox
pkgs.thunderbird
]
else
[ ];
}
</programlisting>
</para>
<para>With multiple modules, it may not be obvious what the final
value of a configuration option is. The command
<option>nixos-option</option> allows you to find out:
<screen>
$ nixos-option services.xserver.enable
true
$ nixos-option boot.kernelModules
[ "tun" "ipv6" "loop" <replaceable>...</replaceable> ]
</screen>
Interactive exploration of the configuration is possible using
<command
xlink:href="https://github.com/edolstra/nix-repl">nix-repl</command>,
a read-eval-print loop for Nix expressions. Its not installed by
default; run <literal>nix-env -i nix-repl</literal> to get it. A
typical use:
<screen>
$ nix-repl '&lt;nixos>'
nix-repl> config.networking.hostName
"mandark"
nix-repl> map (x: x.hostName) config.services.httpd.virtualHosts
[ "example.org" "example.gov" ]
</screen>
</para>
</section>
<section><title>Syntax summary</title>
<para>Below is a summary of the most important syntactic constructs in
the Nix expression language. Its not complete. In particular, there
are many other built-in functions. See the <link
xlink:href="http://nixos.org/nix/manual/#chap-writing-nix-expressions">Nix
manual</link> for the rest.</para>
<informaltable frame='none'>
<tgroup cols='2'>
<colspec colname='c1' rowsep='1' colsep='1' />
<colspec colname='c2' rowsep='1' />
<thead>
<row>
<entry>Example</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry namest="c1" nameend="c2"><emphasis>Basic values</emphasis></entry>
</row>
<row>
<entry><literal>"Hello world"</literal></entry>
<entry>A string</entry>
</row>
<row>
<entry><literal>"${pkgs.bash}/bin/sh"</literal></entry>
<entry>A string containing an expression (expands to <literal>"/nix/store/<replaceable>hash</replaceable>-bash-<replaceable>version</replaceable>/bin/sh"</literal>)</entry>
</row>
<row>
<entry><literal>true</literal>, <literal>false</literal></entry>
<entry>Booleans</entry>
</row>
<row>
<entry><literal>123</literal></entry>
<entry>An integer</entry>
</row>
<row>
<entry><literal>./foo.png</literal></entry>
<entry>A path (relative to the containing Nix expression)</entry>
</row>
<row>
<entry namest="c1" nameend="c2"><emphasis>Compound values</emphasis></entry>
</row>
<row>
<entry><literal>{ x = 1; y = 2; }</literal></entry>
<entry>An set with attributes names <literal>x</literal> and <literal>y</literal></entry>
</row>
<row>
<entry><literal>{ foo.bar = 1; }</literal></entry>
<entry>A nested set, equivalent to <literal>{ foo = { bar = 1; }; }</literal></entry>
</row>
<row>
<entry><literal>rec { x = "bla"; y = x + "bar"; }</literal></entry>
<entry>A recursive set, equivalent to <literal>{ x = "foo"; y = "foobar"; }</literal></entry>
</row>
<row>
<entry><literal>[ "foo" "bar" ]</literal></entry>
<entry>A list with two elements</entry>
</row>
<row>
<entry namest="c1" nameend="c2"><emphasis>Operators</emphasis></entry>
</row>
<row>
<entry><literal>"foo" + "bar"</literal></entry>
<entry>String concatenation</entry>
</row>
<row>
<entry><literal>1 + 2</literal></entry>
<entry>Integer addition</entry>
</row>
<row>
<entry><literal>"foo" == "f" + "oo"</literal></entry>
<entry>Equality test (evaluates to <literal>true</literal>)</entry>
</row>
<row>
<entry><literal>"foo" != "bar"</literal></entry>
<entry>Inequality test (evaluates to <literal>true</literal>)</entry>
</row>
<row>
<entry><literal>!true</literal></entry>
<entry>Boolean negation</entry>
</row>
<row>
<entry><literal>{ x = 1; y = 2; }.x</literal></entry>
<entry>Attribute selection (evaluates to <literal>1</literal>)</entry>
</row>
<row>
<entry><literal>{ x = 1; y = 2; }.z or 3</literal></entry>
<entry>Attribute selection with default (evaluates to <literal>3</literal>)</entry>
</row>
<row>
<entry><literal>{ x = 1; y = 2; } // { z = 3; }</literal></entry>
<entry>Merge two sets (attributes in the right-hand set taking precedence)</entry>
</row>
<row>
<entry namest="c1" nameend="c2"><emphasis>Control structures</emphasis></entry>
</row>
<row>
<entry><literal>if 1 + 1 == 2 then "yes!" else "no!"</literal></entry>
<entry>Conditional expression</entry>
</row>
<row>
<entry><literal>assert 1 + 1 == 2; "yes!"</literal></entry>
<entry>Assertion check (evaluates to <literal>"yes!"</literal>)</entry>
</row>
<row>
<entry><literal>let x = "foo"; y = "bar"; in x + y</literal></entry>
<entry>Variable definition</entry>
</row>
<row>
<entry><literal>with pkgs.lib; head [ 1 2 3 ]</literal></entry>
<entry>Add all attributes from the given set to the scope
(evaluates to <literal>1</literal>)</entry>
</row>
<row>
<entry namest="c1" nameend="c2"><emphasis>Functions (lambdas)</emphasis></entry>
</row>
<row>
<entry><literal>x: x + 1</literal></entry>
<entry>A function that expects an integer and returns it increased by 1</entry>
</row>
<row>
<entry><literal>(x: x + 1) 100</literal></entry>
<entry>A function call (evaluates to 101)</entry>
</row>
<row>
<entry><literal>let inc = x: x + 1; in inc (inc (inc 100))</literal></entry>
<entry>A function bound to a variable and subsequently called by name (evaluates to 103)</entry>
</row>
<row>
<entry><literal>{ x, y }: x + y</literal></entry>
<entry>A function that expects a set with required attributes
<literal>x</literal> and <literal>y</literal> and concatenates
them</entry>
</row>
<row>
<entry><literal>{ x, y ? "bar" }: x + y</literal></entry>
<entry>A function that expects a set with required attribute
<literal>x</literal> and optional <literal>y</literal>, using
<literal>"bar"</literal> as default value for
<literal>y</literal></entry>
</row>
<row>
<entry><literal>{ x, y, ... }: x + y</literal></entry>
<entry>A function that expects a set with required attributes
<literal>x</literal> and <literal>y</literal> and ignores any
other attributes</entry>
</row>
<row>
<entry><literal>{ x, y } @ args: x + y</literal></entry>
<entry>A function that expects a set with required attributes
<literal>x</literal> and <literal>y</literal>, and binds the
whole set to <literal>args</literal></entry>
</row>
<row>
<entry namest="c1" nameend="c2"><emphasis>Built-in functions</emphasis></entry>
</row>
<row>
<entry><literal>import ./foo.nix</literal></entry>
<entry>Load and return Nix expression in given file</entry>
</row>
<row>
<entry><literal>map (x: x + x) [ 1 2 3 ]</literal></entry>
<entry>Apply a function to every element of a list (evaluates to <literal>[ 2 4 6 ]</literal>)</entry>
</row>
<!--
<row>
<entry><literal>throw "Urgh"</literal></entry>
<entry>Raise an error condition</entry>
</row>
-->
</tbody>
</tgroup>
</informaltable>
</section>
</section>
@ -170,7 +866,7 @@ recursion.)</para>
</section>
<section><title>Adding custom packages</title>
<section xml:id="sec-custom-packages"><title>Adding custom packages</title>
<para>Its possible that a package you need is not available in NixOS.
In that case, you can do two things. First, you can clone the Nixpkgs
@ -316,7 +1012,7 @@ manpage or the Nix manual.</para>
<!--===============================================================-->
<section><title>User management</title>
<section xml:id="sec-user-management"><title>User management</title>
<para>NixOS supports both declarative and imperative styles of user
management. In the declarative style, users are specified in

File diff suppressed because it is too large Load diff

View file

@ -18,6 +18,33 @@ details, see the <link
xlink:href="https://nixos.org/wiki/Installing_NixOS_from_a_USB_stick">NixOS
Wiki</link>.</para>
<para>As an alternative to installing NixOS yourself, you can get a
running NixOS system through several other means:
<itemizedlist>
<listitem>
<para>Using virtual appliances in Open Virtualization Format (OVF)
that can be imported into VirtualBox. These are available from
the <link xlink:href="http://nixos.org/nixos/download.html">NixOS
homepage</link>.</para>
</listitem>
<listitem>
<para>Using AMIs for Amazons EC2. To find one for your region
and instance type, please refer to the <link
xlink:href="https://github.com/NixOS/nixops/blob/master/nix/ec2-amis.nix">list
of most recent AMIs</link>.</para>
</listitem>
<listitem>
<para>Using NixOps, the NixOS-based cloud deployment tool, which
allows you to provision VirtualBox and EC2 NixOS instances from
declarative specifications. Check out the <link
xlink:href="https://github.com/NixOS/nixops">NixOps
homepage</link> for details.</para>
</listitem>
</itemizedlist>
</para>
</section>
@ -62,9 +89,14 @@ Wiki</link>.</para>
<listitem><para>For initialising Ext4 partitions:
<command>mkfs.ext4</command>. It is recommended that you assign a
unique symbolic label to the file system using the option
<option>-L <replaceable>label</replaceable></option>. This will
make the file system configuration independent from device
changes.</para></listitem>
<option>-L <replaceable>label</replaceable></option>, since this
makes the file system configuration independent from device
changes. For example:
<screen>
$ mkfs.ext4 -L nixos /dev/sda1</screen>
</para></listitem>
<listitem><para>For creating swap partitions:
<command>mkswap</command>. Again its recommended to assign a
@ -97,6 +129,12 @@ $ mount /dev/disk/by-label/nixos /mnt
</para></listitem>
<listitem><para>If your machine has a limited amount of memory, you
may want to activate swap devices now (<command>swapon
<replaceable>device</replaceable></command>). The installer (or
rather, the build actions that it may spawn) may need quite a bit of
RAM, depending on your configuration.</para></listitem>
<listitem>
<para>You now need to create a file
@ -161,28 +199,16 @@ $ nano /mnt/etc/nixos/configuration.nix
</listitem>
<listitem><para>If your machine has a limited amount of memory, you
may want to activate swap devices now (<command>swapon
<replaceable>device</replaceable></command>). The installer (or
rather, the build actions that it may spawn) may need quite a bit of
RAM, depending on your configuration.</para></listitem>
<!--
<listitem><para>Optionally, you can run
<screen>
$ nixos-checkout</screen>
to make the installer use the latest NixOS/Nixpkgs sources from the
Git repository, rather than the sources on CD.</para></listitem>
-->
<listitem><para>Do the installation:
<screen>
$ nixos-install</screen>
Cross fingers.</para></listitem>
Cross fingers. If this fails due to a temporary problem (such as
a network issue while downloading binaries from the NixOS binary
cache), you can just re-run <command>nixos-install</command>.
Otherwise, fix your <filename>configuration.nix</filename> and
then re-run <command>nixos-install</command>.</para></listitem>
<listitem><para>If everything went well:
@ -194,7 +220,7 @@ $ reboot</screen>
<listitem>
<para>You should now be able to boot into the installed NixOS.
The Grub boot menu shows a list of <emphasis>available
The GRUB boot menu shows a list of <emphasis>available
configurations</emphasis> (initially just one). Every time you
change the NixOS configuration (see <xref
linkend="sec-changing-config" />), a new item appears in the menu.
@ -229,26 +255,28 @@ $ nix-env -i w3m</screen>
</orderedlist>
<para><xref linkend="ex-install-sequence" /> shows a typical sequence
of commands for installing NixOS on an empty hard drive (here
<filename>/dev/sda</filename>). <xref linkend="ex-config" /> shows a
corresponding configuration Nix expression.</para>
<para>To summarise, <xref linkend="ex-install-sequence" /> shows a
typical sequence of commands for installing NixOS on an empty hard
drive (here <filename>/dev/sda</filename>). <xref linkend="ex-config"
/> shows a corresponding configuration Nix expression.</para>
<example xml:id='ex-install-sequence'><title>Commands for installing NixOS on <filename>/dev/sda</filename></title>
<screen>
$ fdisk /dev/sda <lineannotation>(or whatever device you want to install on)</lineannotation>
$ mkfs.ext4 -L nixos /dev/sda1 <lineannotation>(idem)</lineannotation>
$ mkswap -L swap /dev/sda2 <lineannotation>(idem)</lineannotation>
$ mount LABEL=nixos /mnt
$ nixos-generate-config
$ fdisk /dev/sda # <lineannotation>(or whatever device you want to install on)</lineannotation>
$ mkfs.ext4 -L nixos /dev/sda1
$ mkswap -L swap /dev/sda2
$ swapon /dev/sda2
$ mount /dev/disk/by-label/nixos /mnt
$ nixos-generate-config --root /mnt
$ nano /mnt/etc/nixos/configuration.nix
<lineannotation>(in particular, set the fileSystems and swapDevices options)</lineannotation>
$ nixos-install
$ reboot</screen>
</example>
<example xml:id='ex-config'><title>NixOS configuration</title>
<screen>
{ config, pkgs, ... }:
{
imports =
[ # Include the results of the hardware scan.
@ -257,14 +285,12 @@ $ reboot</screen>
boot.loader.grub.device = "/dev/sda";
# Note: setting fileSystems and swapDevices is generally not
# necessary, since nixos-generate-config has set them automatically
# in hardware-configuration.nix.
fileSystems."/".device = "/dev/disk/by-label/nixos";
swapDevices =
[ { device = "/dev/disk/by-label/swap"; } ];
# Note: setting fileSystems is generally not
# necessary, since nixos-generate-config figures them out
# automatically in hardware-configuration.nix.
#fileSystems."/".device = "/dev/disk/by-label/nixos";
# Enable the OpenSSH server.
services.sshd.enable = true;
}</screen>
</example>
@ -290,6 +316,10 @@ to build the new configuration, make it the default configuration for
booting, and try to realise the configuration in the running system
(e.g., by restarting system services).</para>
<warning><para>These commands must be executed as root, so you should
either run them from a root shell or by prefixing them with
<literal>sudo -i</literal>.</para></warning>
<para>You can also do
<screen>
@ -309,6 +339,18 @@ to build the configuration and make it the boot default, but not
switch to it now (so it will only take effect after the next
reboot).</para>
<para>You can make your configuration show up in a different submenu
of the GRUB 2 boot screen by giving it a different <emphasis>profile
name</emphasis>, e.g.
<screen>
$ nixos-rebuild switch -p test </screen>
which causes the new configuration (and previous ones created using
<literal>-p test</literal>) to show up in the GRUB submenu “NixOS -
Profile 'test'”. This can be useful to separate test configurations
from “stable” configurations.</para>
<para>Finally, you can do
<screen>
@ -319,7 +361,7 @@ whether everything compiles cleanly.</para>
<para>If you have a machine that supports hardware virtualisation, you
can also test the new configuration in a sandbox by building and
running a <emphasis>virtual machine</emphasis> that contains the
running a QEMU <emphasis>virtual machine</emphasis> that contains the
desired configuration. Just do
<screen>
@ -334,7 +376,6 @@ available.</para>
</section>
<!--===============================================================-->
<section xml:id="sec-upgrading">
@ -342,28 +383,86 @@ available.</para>
<title>Upgrading NixOS</title>
<para>The best way to keep your NixOS installation up to date is to
use the <literal>nixos-unstable</literal> channel. (A channel is a
use one of the NixOS <emphasis>channels</emphasis>. A channel is a
Nix mechanism for distributing Nix expressions and associated
binaries.) The NixOS channel is updated automatically from NixOSs
Git repository after running certain tests and building most
packages.</para>
binaries. The NixOS channels are updated automatically from NixOSs
Git repository after certain tests have passed and all packages have
been built. These channels are:
<para>NixOS automatically subscribes you to the NixOS channel. If for
some reason this is not the case, just do
<itemizedlist>
<listitem>
<para>Stable channels, such as <literal
xlink:href="http://nixos.org/channels/nixos-13.10">nixos-13.10</literal>.
These only get conservative bug fixes and package upgrades. For
instance, a channel update may cause the Linux kernel on your
system to be upgraded from 3.4.66 to 3.4.67 (a minor bug fix), but
not from 3.4.<replaceable>x</replaceable> to
3.11.<replaceable>x</replaceable> (a major change that has the
potential to break things). Stable channels are generally
maintained until the next stable branch is created.</para>
</listitem>
<listitem>
<para>The unstable channel, <literal
xlink:href="http://nixos.org/channels/nixos-unstable">nixos-unstable</literal>.
This corresponds to NixOSs main development branch, and may thus
see radical changes between channel updates. Its not recommended
for production systems.</para>
</listitem>
</itemizedlist>
To see what channels are available, go to <link
xlink:href="http://nixos.org/channels"/>. (Note that the URIs of the
various channels redirect to a directory that contains the channels
latest version and includes ISO images and VirtualBox
appliances.)</para>
<para>When you first install NixOS, youre automatically subscribed to
the NixOS channel that corresponds to your installation source. For
instance, if you installed from a 13.10 ISO, you will be subscribed to
the <literal>nixos-13.10</literal> channel. To see which NixOS
channel youre subscribed to, run the following as root:
<screen>
$ nix-channel --add http://nixos.org/channels/nixos-unstable
$ nix-channel --list | grep nixos
nixos https://nixos.org/channels/nixos-unstable
</screen>
You can then upgrade NixOS to the latest version in the channel by
running
To switch to a different NixOS channel, do
<screen>
$ nix-channel --update nixos
$ nix-channel --add http://nixos.org/channels/<replaceable>channel-name</replaceable> nixos
</screen>
and running the <command>nixos-rebuild</command> command as described
in <xref linkend="sec-changing-config"/>.</para>
(Be sure to include the <literal>nixos</literal> parameter at the
end.) For instance, to use the NixOS 13.10 stable channel:
<screen>
$ nix-channel --add http://nixos.org/channels/nixos-13.10 nixos
</screen>
But it you want to live on the bleeding edge:
<screen>
$ nix-channel --add http://nixos.org/channels/nixos-unstable nixos
</screen>
</para>
<para>You can then upgrade NixOS to the latest version in your chosen
channel by running
<screen>
$ nixos-rebuild switch --upgrade
</screen>
which is equivalent to the more verbose <literal>nix-channel --update
nixos; nixos-rebuild switch</literal>.</para>
<warning><para>It is generally safe to switch back and forth between
channels. The only exception is that a newer NixOS may also have a
newer Nix version, which may involve an upgrade of Nixs database
schema. This cannot be undone easily, so in that case you will not be
able to go back to your original channel.</para></warning>
</section>

View file

@ -36,23 +36,15 @@
select="attr[@name = 'description']/string/@value" />
</para>
<para>
<emphasis>Default:</emphasis>
<xsl:text> </xsl:text>
<xsl:choose>
<xsl:when test="attr[@name = 'default']">
<literal>
<xsl:apply-templates select="attr[@name = 'default']" />
</literal>
</xsl:when>
<xsl:otherwise>
none
</xsl:otherwise>
</xsl:choose>
</para>
<xsl:if test="attr[@name = 'default']">
<para>
<emphasis>Default:</emphasis>
<xsl:text> </xsl:text>
<xsl:apply-templates select="attr[@name = 'default']" mode="top" />
</para>
</xsl:if>
<xsl:if test="attr[@name = 'example']">
<para>
<emphasis>Example:</emphasis>
<xsl:text> </xsl:text>
@ -61,9 +53,7 @@
<programlisting><xsl:value-of select="attr[@name = 'example']/attrs/attr[@name = 'text']/string/@value" /></programlisting>
</xsl:when>
<xsl:otherwise>
<literal>
<xsl:apply-templates select="attr[@name = 'example']" />
</literal>
<xsl:apply-templates select="attr[@name = 'example']" mode="top" />
</xsl:otherwise>
</xsl:choose>
</para>
@ -94,9 +84,34 @@
</xsl:template>
<xsl:template match="*" mode="top">
<xsl:choose>
<xsl:when test="string[contains(@value, '&#010;')]">
<programlisting>
<xsl:text>''
</xsl:text><xsl:value-of select='str:replace(string/@value, "${", "&apos;&apos;${")' /><xsl:text>''</xsl:text></programlisting>
</xsl:when>
<xsl:otherwise>
<literal><xsl:apply-templates /></literal>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="null">
<xsl:text>null</xsl:text>
</xsl:template>
<xsl:template match="string">
<!-- !!! escaping -->
<xsl:text>"</xsl:text><xsl:value-of select="str:replace(str:replace(str:replace(@value, '\', '\\'), '&quot;', '\&quot;'), '&#010;', '\n')" /><xsl:text>"</xsl:text>
<xsl:choose>
<xsl:when test="(contains(@value, '&quot;') or contains(@value, '\')) and not(contains(@value, '&#010;'))">
<xsl:text>''</xsl:text><xsl:value-of select='str:replace(@value, "${", "&apos;&apos;${")' /><xsl:text>''</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>"</xsl:text><xsl:value-of select="str:replace(str:replace(str:replace(str:replace(@value, '\', '\\'), '&quot;', '\&quot;'), '&#010;', '\n'), '$', '\$')" /><xsl:text>"</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
@ -142,14 +157,7 @@
<xsl:template match="derivation">
<xsl:choose>
<xsl:when test="attr[@name = 'url']/string/@value">
<replaceable>(download of <xsl:value-of select="attr[@name = 'url']/string/@value" />)</replaceable>
</xsl:when>
<xsl:otherwise>
<replaceable>(build of <xsl:value-of select="attr[@name = 'name']/string/@value" />)</replaceable>
</xsl:otherwise>
</xsl:choose>
<replaceable>(build of <xsl:value-of select="attr[@name = 'name']/string/@value" />)</replaceable>
</xsl:template>
<xsl:template match="attr[@name = 'declarations' or @name = 'definitions']">

View file

@ -7,23 +7,20 @@
, baseModules ? import ../modules/module-list.nix
, extraArgs ? {}
, modules
, check ? true
}:
let extraArgs_ = extraArgs; pkgs_ = pkgs; system_ = system; in
rec {
# These are the NixOS modules that constitute the system configuration.
configComponents = modules ++ baseModules;
# Merge the option definitions in all modules, forming the full
# system configuration. It's not checked for undeclared options.
systemModule =
pkgs.lib.fixMergeModules configComponents extraArgs;
optionDefinitions = systemModule.config;
optionDeclarations = systemModule.options;
inherit (systemModule) options;
# system configuration.
inherit (pkgs.lib.evalModules {
modules = modules ++ baseModules;
args = extraArgs;
check = check && options.environment.checkConfigurationOptions.value;
}) config options;
# These are the extra arguments passed to every module. In
# particular, Nixpkgs is passed through the "pkgs" argument.
@ -56,16 +53,12 @@ rec {
# define nixpkgs.config, so it's pointless to evaluate them.
baseModules = [ ../modules/misc/nixpkgs.nix ];
pkgs = import ./nixpkgs.nix { system = system_; config = {}; };
}).optionDefinitions.nixpkgs;
check = false;
}).config.nixpkgs;
in
{
inherit system;
inherit (nixpkgsOptions) config;
});
# Optionally check wether all config values have corresponding
# option declarations.
config =
assert optionDefinitions.environment.checkConfigurationOptions -> pkgs.lib.checkModule "" systemModule;
systemModule.config;
}

View file

@ -9,6 +9,7 @@ with pkgs.lib;
fonts = {
enableFontConfig = mkOption { # !!! should be enableFontconfig
type = types.bool;
default = true;
description = ''
If enabled, a Fontconfig configuration file will be built

View file

@ -5,6 +5,7 @@ with pkgs.lib;
{
options = {
gnu = mkOption {
type = types.bool;
default = false;
description =
'' When enabled, GNU software is chosen by default whenever a there is

View file

@ -18,16 +18,18 @@ in
i18n = {
defaultLocale = mkOption {
type = types.str;
default = "en_US.UTF-8";
example = "nl_NL.UTF-8";
description = "
description = ''
The default locale. It determines the language for program
messages, the format for dates and times, sort order, and so on.
It also determines the character set, such as UTF-8.
";
'';
};
supportedLocales = mkOption {
type = types.listOf types.str;
default = ["all"];
example = ["en_US.UTF-8/UTF-8" "nl_NL.UTF-8/UTF-8" "nl_NL/ISO-8859-1"];
description = ''
@ -40,22 +42,23 @@ in
};
consoleFont = mkOption {
type = types.str;
default = "lat9w-16";
example = "LatArCyrHeb-16";
description = "
description = ''
The font used for the virtual consoles. Leave empty to use
whatever the <command>setfont</command> program considers the
default font.
";
'';
};
consoleKeyMap = mkOption {
type = types.str;
default = "us";
example = "fr";
description = "
description = ''
The keyboard mapping table for the virtual consoles.
";
type = types.uniq types.string;
'';
};
};

View file

@ -15,6 +15,7 @@ in
options = {
networking.extraHosts = pkgs.lib.mkOption {
type = types.lines;
default = "";
example = "192.168.0.1 lanlocalhost";
description = ''
@ -23,6 +24,7 @@ in
};
networking.dnsSingleRequest = pkgs.lib.mkOption {
type = types.bool;
default = false;
description = ''
Recent versions of glibc will issue both ipv4 (A) and ipv6 (AAAA)

View file

@ -1,10 +1,12 @@
{ config, pkgs, ... }:
with pkgs.lib;
{
options = {
environment.noXlibs = pkgs.lib.mkOption {
environment.noXlibs = mkOption {
type = types.bool;
default = false;
example = true;
description = ''
Switch off the options in the default configuration that require X libraries.
Currently this includes: ssh X11 forwarding, dbus, fonts.enableCoreFonts,
@ -13,7 +15,7 @@
};
};
config = pkgs.lib.mkIf config.environment.noXlibs {
config = mkIf config.environment.noXlibs {
programs.ssh.setXAuthLocation = false;
fonts = {
enableCoreFonts = false;

View file

@ -16,6 +16,7 @@ in
# NSS modules. Hacky!
system.nssModules = mkOption {
type = types.listOf types.path;
internal = true;
default = [];
description = ''
@ -23,7 +24,6 @@ in
several DNS resolution methods to be specified via
<filename>/etc/nsswitch.conf</filename>.
'';
merge = mergeListOption;
apply = list:
{
inherit list;

View file

@ -17,6 +17,7 @@ in
powerManagement = {
enable = mkOption {
type = types.bool;
default = true;
description =
''
@ -26,11 +27,13 @@ in
};
resumeCommands = mkOption {
type = types.lines;
default = "";
description = "Commands executed after the system resumes from suspend-to-RAM.";
};
powerUpCommands = mkOption {
type = types.lines;
default = "";
example = "${pkgs.hdparm}/sbin/hdparm -B 255 /dev/sda";
description =
@ -42,6 +45,7 @@ in
};
powerDownCommands = mkOption {
type = types.lines;
default = "";
example = "${pkgs.hdparm}/sbin/hdparm -B 255 /dev/sda";
description =

View file

@ -46,6 +46,7 @@ in {
hardware.pulseaudio = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Whether to enable the PulseAudio sound server.
@ -72,12 +73,13 @@ in {
The path to the configuration the PulseAudio server
should use. By default, the "default.pa" configuration
from the PulseAudio distribution is used.
'';
'';
};
package = mkOption {
type = types.path;
default = pulseaudio;
example = "pulseaudio.override { jackaudioSupport = true; }";
example = literalExample "pulseaudio.override { jackaudioSupport = true; }";
description = ''
The PulseAudio derivation to use. This can be used to enable
features (such as JACK support) that are not enabled in the
@ -125,9 +127,9 @@ in {
description = "PulseAudio system service user";
home = pulseRuntimePath;
};
users.extraGroups.pulse.gid = gid;
systemd.services.pulseaudio = {
description = "PulseAudio system-wide server";
wantedBy = [ "sound.target" ];

View file

@ -25,12 +25,17 @@ in
'';
type = types.attrsOf (mkOptionType {
name = "a string or a list of strings";
merge = xs:
let xs' = evalProperties xs; in
if isList (head xs') then concatLists xs'
else if builtins.lessThan 1 (length xs') then abort "variable in environment.variables has multiple values"
else if !builtins.isString (head xs') then abort "variable in environment.variables does not have a string value"
else head xs';
merge = loc: defs:
let
defs' = filterOverrides defs;
res = (head defs').value;
in
if isList res then concatLists (getValues defs')
else if builtins.lessThan 1 (length defs') then
throw "The option `${showOption loc}' is defined multiple times, in ${showFiles (getFiles defs)}."
else if !builtins.isString res then
throw "The option `${showOption loc}' does not have a string value, in ${showFiles (getFiles defs)}."
else res;
});
apply = mapAttrs (n: v: if isList v then concatStringsSep ":" v else v);
};

View file

@ -34,13 +34,13 @@ with utils;
device = mkOption {
example = "/dev/sda3";
type = types.uniq types.string;
type = types.str;
description = "Path of the device.";
};
label = mkOption {
example = "swap";
type = types.uniq types.string;
type = types.str;
description = ''
Label of the device. Can be used instead of <varname>device</varname>.
'';
@ -72,11 +72,8 @@ with utils;
};
config = {
device =
if options.label.isDefined then
"/dev/disk/by-label/${config.label}"
else
mkNotdef;
device = mkIf options.label.isDefined
"/dev/disk/by-label/${config.label}";
};
};

View file

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

View file

@ -14,7 +14,7 @@ let
'';
requiredPackages =
[ config.environment.nix
[ config.nix.package
pkgs.acl
pkgs.attr
pkgs.bashInteractive # bash with ncurses support
@ -60,6 +60,7 @@ in
environment = {
systemPackages = mkOption {
type = types.listOf types.path;
default = [];
example = "[ pkgs.icecat3 pkgs.thunderbird ]";
description = ''
@ -74,6 +75,7 @@ in
};
pathsToLink = mkOption {
type = types.listOf types.str;
# Note: We need `/lib' to be among `pathsToLink' for NSS modules
# to work.
default = [];
@ -122,7 +124,7 @@ in
postBuild =
''
if [ -x $out/bin/update-mime-database -a -w $out/share/mime/packages ]; then
$out/bin/update-mime-database -V $out/share/mime
XDG_DATA_DIRS=$out/share $out/bin/update-mime-database -V $out/share/mime > /dev/null
fi
if [ -x $out/bin/gtk-update-icon-cache -a -f $out/share/icons/hicolor/index.theme ]; then

View file

@ -9,7 +9,7 @@ with pkgs.lib;
timeZone = mkOption {
default = "CET";
type = with types; uniq string;
type = types.str;
example = "America/New_York";
description = "The time zone used when displaying times and dates.";
};

View file

@ -12,14 +12,19 @@ let
options = {
name = mkOption {
type = with types; uniq string;
type = types.str;
description = "The name of the user account. If undefined, the name of the attribute set will be used.";
};
description = mkOption {
type = with types; uniq string;
type = types.str;
default = "";
description = "A short description of the user account.";
example = "Alice Q. User";
description = ''
A short description of the user account, typically the
user's full name. This is actually the GECOS or comment
field in <filename>/etc/passwd</filename>.
'';
};
uid = mkOption {
@ -29,25 +34,25 @@ let
};
group = mkOption {
type = with types; uniq string;
type = types.str;
default = "nogroup";
description = "The user's primary group.";
};
extraGroups = mkOption {
type = types.listOf types.string;
type = types.listOf types.str;
default = [];
description = "The user's auxiliary groups.";
};
home = mkOption {
type = with types; uniq string;
type = types.str;
default = "/var/empty";
description = "The user's home directory.";
};
shell = mkOption {
type = with types; uniq string;
type = types.str;
default = "/run/current-system/sw/sbin/nologin";
description = "The path to the user's shell.";
};
@ -65,9 +70,15 @@ let
};
password = mkOption {
type = with types; uniq (nullOr string);
type = with types; uniq (nullOr str);
default = null;
description = "The user's password. If undefined, no password is set for the user. Warning: do not set confidential information here because this data would be readable by all. This option should only be used for public account such as guest.";
description = ''
The user's password. If undefined, no password is set for
the user. Warning: do not set confidential information here
because it is world-readable in the Nix store. This option
should only be used for public accounts such as
<literal>guest</literal>.
'';
};
isSystemUser = mkOption {
@ -79,11 +90,11 @@ let
createUser = mkOption {
type = types.bool;
default = true;
description = "
description = ''
Indicates if the user should be created automatically as a local user.
Set this to false if the user for instance is an LDAP user. NixOS will
then not modify any of the basic properties for the user account.
";
'';
};
isAlias = mkOption {
@ -107,7 +118,7 @@ let
options = {
name = mkOption {
type = with types; uniq string;
type = types.str;
description = "The name of the group. If undefined, the name of the attribute set will be used.";
};
@ -149,13 +160,12 @@ in
example = {
alice = {
uid = 1234;
description = "Alice";
description = "Alice Q. User";
home = "/home/alice";
createHome = true;
group = "users";
extraGroups = ["wheel"];
shell = "/bin/sh";
password = "foobar";
};
};
description = ''

View file

@ -1,4 +1,6 @@
{pkgs, config, ...}:
{ config, pkgs, ... }:
with pkgs.lib;
{
@ -6,9 +8,9 @@
options = {
hardware.enableAllFirmware = pkgs.lib.mkOption {
hardware.enableAllFirmware = mkOption {
default = false;
type = pkgs.lib.types.bool;
type = types.bool;
description = ''
Turn on this option if you want to enable all the firmware shipped with Debian/Ubuntu.
'';
@ -19,7 +21,7 @@
###### implementation
config = pkgs.lib.mkIf config.hardware.enableAllFirmware {
config = mkIf config.hardware.enableAllFirmware {
hardware.firmware = [ "${pkgs.firmwareLinuxNonfree}/lib/firmware" ];
};

View file

@ -18,16 +18,16 @@ in
hardware.pcmcia = {
enable = mkOption {
type = types.bool;
default = false;
merge = mergeEnableOption;
description = ''
Enable this option to support PCMCIA card.
'';
};
firmware = mkOption {
type = types.listOf types.path;
default = [];
merge = mergeListOption;
description = ''
List of firmware used to handle specific PCMCIA card.
'';
@ -36,7 +36,7 @@ in
config = mkOption {
default = null;
description = ''
Path to the configuration file which map the memory, irq
Path to the configuration file which maps the memory, IRQs
and ports used by the PCMCIA hardware.
'';
};

View file

@ -33,7 +33,7 @@ in
if ! [ -e /var/lib/nixos/did-channel-init ]; then
echo "unpacking the NixOS/Nixpkgs sources..."
mkdir -p /nix/var/nix/profiles/per-user/root
${config.environment.nix}/bin/nix-env -p /nix/var/nix/profiles/per-user/root/channels \
${config.nix.package}/bin/nix-env -p /nix/var/nix/profiles/per-user/root/channels \
-i ${channelSources} --quiet --option use-substitutes false
mkdir -m 0700 -p /root/.nix-defexpr
ln -s /nix/var/nix/profiles/per-user/root/channels /root/.nix-defexpr/channels

View file

@ -298,12 +298,12 @@ in
''
# After booting, register the contents of the Nix store on the
# CD in the Nix database in the tmpfs.
${config.environment.nix}/bin/nix-store --load-db < /nix/store/nix-path-registration
${config.nix.package}/bin/nix-store --load-db < /nix/store/nix-path-registration
# nixos-rebuild also requires a "system" profile and an
# /etc/NIXOS tag.
touch /etc/NIXOS
${config.environment.nix}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system
${config.nix.package}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system
'';
# Add vfat support to the initrd to enable people to copy the

View file

@ -1,78 +0,0 @@
{ config, pkgs, ... }:
{
imports = [ ./installation-cd-base.nix ];
# Build the build-time dependencies of this configuration on the DVD
# to speed up installation.
isoImage.storeContents = [ config.system.build.toplevel.drvPath ];
# Include lots of packages.
environment.systemPackages =
[ pkgs.utillinuxCurses
pkgs.upstartJobControl
pkgs.iproute
pkgs.bc
pkgs.fuse
pkgs.zsh
pkgs.sqlite
pkgs.gnupg
pkgs.manpages
pkgs.pinentry
pkgs.screen
pkgs.patch
pkgs.which
pkgs.diffutils
pkgs.file
pkgs.irssi
pkgs.mcabber
pkgs.mutt
pkgs.emacs
pkgs.vimHugeX
pkgs.bvi
pkgs.ddrescue
pkgs.cdrkit
pkgs.btrfsProgs
pkgs.xfsprogs
pkgs.jfsutils
pkgs.jfsrec
pkgs.ntfs3g
pkgs.subversion16
pkgs.monotone
pkgs.git
pkgs.darcs
pkgs.mercurial
pkgs.bazaar
pkgs.cvs
pkgs.pciutils
pkgs.hddtemp
pkgs.sdparm
pkgs.hdparm
pkgs.usbutils
pkgs.openssh
pkgs.lftp
pkgs.w3m
pkgs.openssl
pkgs.ncat
pkgs.lynx
pkgs.wget
pkgs.elinks
pkgs.socat
pkgs.squid
pkgs.unrar
pkgs.zip
pkgs.unzip
pkgs.lzma
pkgs.cabextract
pkgs.cpio
pkgs.lsof
pkgs.ltrace
pkgs.perl
pkgs.python
pkgs.ruby
pkgs.guile
pkgs.clisp
pkgs.tcl
];
}

View file

@ -152,7 +152,7 @@ in
# default root password is empty.
services.openssh.enable = true;
jobs.openssh.startOn = pkgs.lib.mkOverrideTemplate 50 {} "";
jobs.openssh.startOn = pkgs.lib.mkOverride 50 "";
boot.loader.grub.enable = false;
boot.loader.generationsDir.enable = false;

View file

@ -109,7 +109,7 @@ in
# not be started by default on the installation CD because the
# default root password is empty.
services.openssh.enable = true;
jobs.openssh.startOn = pkgs.lib.mkOverrideTemplate 50 {} "";
jobs.openssh.startOn = pkgs.lib.mkOverride 50 "";
# To be able to use the systemTarball to catch troubles.
boot.crashDump = {

View file

@ -165,7 +165,7 @@ in
# not be started by default on the installation CD because the
# default root password is empty.
services.openssh.enable = true;
jobs.openssh.startOn = pkgs.lib.mkOverrideTemplate 50 {} "";
jobs.openssh.startOn = pkgs.lib.mkOverride 50 "";
# cpufrequtils fails to build on non-pc
powerManagement.enable = false;

View file

@ -77,14 +77,14 @@ in
# After booting, register the contents of the Nix store on the
# CD in the Nix database in the tmpfs.
if [ -f /nix-path-registration ]; then
${config.environment.nix}/bin/nix-store --load-db < /nix-path-registration &&
${config.nix.package}/bin/nix-store --load-db < /nix-path-registration &&
rm /nix-path-registration
fi
# nixos-rebuild also requires a "system" profile and an
# /etc/NIXOS tag.
touch /etc/NIXOS
${config.environment.nix}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system
${config.nix.package}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system
'';
};

View file

@ -1,5 +1,7 @@
#! @shell@ -e
# FIXME: rewrite this in a more suitable language.
usage () {
exec man nixos-option
exit 1
@ -90,24 +92,25 @@ evalNix(){
}
evalAttr(){
local prefix=$1
local suffix=$2
local strict=$3
local prefix="$1"
local strict="$2"
local suffix="$3"
echo "(import <nixos> {}).$prefix${option:+.$option}${suffix:+.$suffix}" |
evalNix ${strict:+--strict}
}
evalOpt(){
evalAttr "eval.options" "$@"
evalAttr "options" "" "$@"
}
evalCfg(){
evalAttr "config" "$@"
local strict="$1"
evalAttr "config" "$strict"
}
findSources(){
local suffix=$1
echo "builtins.map (f: f.source) (import <nixos> {}).eval.options${option:+.$option}.$suffix" |
echo "(import <nixos> {}).options${option:+.$option}.$suffix" |
evalNix --strict
}
@ -143,7 +146,7 @@ let
nixos = import <nixos> {};
nixpkgs = import <nixpkgs> {};
sources = builtins.map (f: f.source);
opt = reach nixos.eval.options;
opt = reach nixos.options;
cfg = reach nixos.config;
in
@ -186,7 +189,7 @@ EOF
fi
if test "$(evalOpt "_type" 2> /dev/null)" = '"option"'; then
$value && evalCfg;
$value && evalCfg 1
if $desc; then
$value && echo;
@ -212,14 +215,14 @@ if test "$(evalOpt "_type" 2> /dev/null)" = '"option"'; then
nixMap printPath "$(findSources "declarations")"
echo ""
echo "Defined by:"
nixMap printPath "$(findSources "definitions")"
nixMap printPath "$(findSources "files")"
echo ""
fi
else
# echo 1>&2 "Warning: This value is not an option."
result=$(evalCfg)
result=$(evalCfg "")
if names=$(attrNames "$result" 2> /dev/null); then
echo 1>&2 "This attribute set contains:"
escapeQuotes () { eval echo "$1"; }

View file

@ -109,7 +109,7 @@ fi
# more conservative.
if [ "$action" != dry-run -a -n "$buildNix" ]; then
echo "building Nix..." >&2
if ! nix-build '<nixpkgs/nixos>' -A config.environment.nix -o $tmpDir/nix "${extraBuildFlags[@]}" > /dev/null; then
if ! nix-build '<nixpkgs/nixos>' -A config.nix.package -o $tmpDir/nix "${extraBuildFlags[@]}" > /dev/null; then
if ! nix-build '<nixpkgs/nixos>' -A nixFallback -o $tmpDir/nix "${extraBuildFlags[@]}" > /dev/null; then
nix-build '<nixpkgs>' -A nixUnstable -o $tmpDir/nix "${extraBuildFlags[@]}" > /dev/null
fi
@ -121,7 +121,7 @@ fi
# Update the version suffix if we're building from Git (so that
# nixos-version shows something useful).
if nixpkgs=$(nix-instantiate --find-file nixpkgs "${extraBuildFlags[@]}"); then
suffix=$(@shell@ $nixpkgs/nixos/modules/installer/tools/get-version-suffix "${extraBuildFlags[@]}")
suffix=$(@shell@ $nixpkgs/nixos/modules/installer/tools/get-version-suffix "${extraBuildFlags[@]}" || true)
if [ -n "$suffix" ]; then
echo -n "$suffix" > "$nixpkgs/.version-suffix" || true
fi

View file

@ -22,10 +22,10 @@ let
src = ./nixos-install.sh;
inherit (pkgs) perl pathsFromGraph;
nix = config.environment.nix;
nix = config.nix.package;
nixClosure = pkgs.runCommand "closure"
{ exportReferencesGraph = ["refs" config.environment.nix]; }
{ exportReferencesGraph = ["refs" config.nix.package]; }
"cp refs $out";
};
@ -52,6 +52,7 @@ let
inherit (config.system) nixosVersion nixosCodeName;
};
/*
nixos-gui = pkgs.xulrunnerWrapper {
launcher = "nixos-gui";
application = pkgs.stdenv.mkDerivation {
@ -71,10 +72,12 @@ let
};
};
};
*/
in
{
/*
options = {
installer.enableGraphicalTools = pkgs.lib.mkOption {
@ -87,6 +90,7 @@ in
};
};
*/
config = {
environment.systemPackages =
@ -96,10 +100,10 @@ in
nixos-generate-config
nixos-option
nixos-version
] ++ pkgs.lib.optional cfg.enableGraphicalTools nixos-gui;
];
system.build = {
inherit nixos-install nixos-generate-config nixos-option;
inherit nixos-install nixos-generate-config nixos-option nixos-rebuild;
};
};
}

View file

@ -15,10 +15,10 @@ in
options = {
assertions = mkOption {
type = types.listOf types.unspecified;
internal = true;
default = [];
example = [ { assertion = false; message = "you can't enable this for that reason"; } ];
merge = pkgs.lib.mergeListOption;
description = ''
This option allows modules to express conditions that must
hold for the evaluation of the system configuration to

View file

@ -1,10 +1,12 @@
{pkgs, ...}:
{ pkgs, ... }:
with pkgs.lib;
{
options = {
environment.checkConfigurationOptions = pkgs.lib.mkOption {
environment.checkConfigurationOptions = mkOption {
type = types.bool;
default = true;
example = false;
description = ''
Whether to check the validity of the entire configuration.
'';

View file

@ -14,8 +14,8 @@ in
boot = {
crashDump = {
enable = mkOption {
type = types.bool;
default = false;
example = true;
description = ''
If enabled, NixOS will set up a kernel that will
boot on crash, and leave the user to a stage1 debug1devices
@ -35,6 +35,7 @@ in
'';
};
kernelParams = mkOption {
type = types.listOf types.str;
default = [ "debug1devices" ];
description = ''
Parameters that will be passed to the kernel kexec-ed on crash.

View file

@ -7,12 +7,14 @@
options = {
ids.uids = pkgs.lib.mkOption {
internal = true;
description = ''
The user IDs used in NixOS.
'';
};
ids.gids = pkgs.lib.mkOption {
internal = true;
description = ''
The group IDs used in NixOS.
'';
@ -102,6 +104,8 @@
tcpcryptd = 93; # tcpcryptd uses a hard-coded uid. We patch it in Nixpkgs to match this choice.
zope2 = 94;
firebird = 95;
redis = 96;
haproxy = 97;
# When adding a uid, make sure it doesn't match an existing gid.
@ -188,6 +192,7 @@
quassel = 89;
amule = 90;
minidlna = 91;
haproxy = 92;
# When adding a gid, make sure it doesn't match an existing uid.

View file

@ -17,8 +17,8 @@ in
services.locate = {
enable = mkOption {
type = types.bool;
default = false;
example = true;
description = ''
If enabled, NixOS will periodically update the database of
files used by the <command>locate</command> command.
@ -26,11 +26,12 @@ in
};
period = mkOption {
type = types.str;
default = "15 02 * * *";
description = ''
This option defines (in the format used by cron) when the
locate database is updated.
The default is to update at 02:15 (at night) every day.
The default is to update at 02:15 at night every day.
'';
};

View file

@ -26,7 +26,7 @@ let
configType = mkOptionType {
name = "nixpkgs config";
check = traceValIfNot isConfig;
merge = fold mergeConfig {};
merge = args: fold (def: mergeConfig def.value) {};
};
in
@ -59,7 +59,7 @@ in
};
nixpkgs.system = mkOption {
default = pkgs.stdenv.system;
type = types.str;
description = ''
Specifies the Nix platform type for which NixOS should be built.
If unset, it defaults to the platform type of your host system
@ -70,4 +70,8 @@ in
};
};
config = {
nixpkgs.system = mkDefault pkgs.stdenv.system;
};
}

View file

@ -6,6 +6,7 @@
{
options = {
passthru = pkgs.lib.mkOption {
visible = false;
description = ''
This attribute set will be exported as a system attribute.
You can put whatever you want here.

View file

@ -8,31 +8,31 @@ with pkgs.lib;
system.nixosVersion = mkOption {
internal = true;
type = types.uniq types.string;
type = types.str;
description = "NixOS version.";
};
system.nixosVersionSuffix = mkOption {
internal = true;
type = types.uniq types.string;
type = types.str;
description = "NixOS version suffix.";
};
system.nixosRevision = mkOption {
internal = true;
type = types.uniq types.string;
type = types.str;
description = "NixOS Git revision hash.";
};
system.nixosCodeName = mkOption {
internal = true;
type = types.uniq types.string;
type = types.str;
description = "NixOS release code name.";
};
system.defaultChannel = mkOption {
internal = true;
type = types.uniq types.string;
type = types.str;
default = https://nixos.org/channels/nixos-unstable;
description = "Default NixOS channel to which the root user is subscribed.";
};
@ -58,18 +58,15 @@ with pkgs.lib;
# Generate /etc/os-release. See
# http://0pointer.de/public/systemd-man/os-release.html for the
# format.
environment.etc = singleton
{ source = pkgs.writeText "os-release"
''
NAME=NixOS
ID=nixos
VERSION="${config.system.nixosVersion} (${config.system.nixosCodeName})"
VERSION_ID="${config.system.nixosVersion}"
PRETTY_NAME="NixOS ${config.system.nixosVersion} (${config.system.nixosCodeName})"
HOME_URL="http://nixos.org/"
'';
target = "os-release";
};
environment.etc."os-release".text =
''
NAME=NixOS
ID=nixos
VERSION="${config.system.nixosVersion} (${config.system.nixosCodeName})"
VERSION_ID="${config.system.nixosVersion}"
PRETTY_NAME="NixOS ${config.system.nixosVersion} (${config.system.nixosCodeName})"
HOME_URL="http://nixos.org/"
'';
};

View file

@ -150,12 +150,12 @@
./services/networking/cntlm.nix
./services/networking/chrony.nix
./services/networking/ddclient.nix
#./services/networking/dhclient.nix
./services/networking/dhcpcd.nix
./services/networking/dhcpd.nix
./services/networking/dnsmasq.nix
./services/networking/ejabberd.nix
./services/networking/firewall.nix
./services/networking/haproxy.nix
./services/networking/tcpcrypt.nix
./services/networking/flashpolicyd.nix
./services/networking/freenet.nix
@ -276,7 +276,7 @@
./tasks/scsi-link-power-management.nix
./tasks/swraid.nix
./virtualisation/libvirtd.nix
./virtualisation/nova.nix
#./virtualisation/nova.nix
./virtualisation/virtualbox-guest.nix
./virtualisation/xen-dom0.nix
]

View file

@ -16,7 +16,8 @@ let
# cannot serialized attribute set given in the list of modules (that's why
# you should use files).
moduleFiles =
filter isPath modules;
# FIXME: use typeOf (Nix 1.6.1).
filter (x: !isAttrs x && !builtins.isFunction x) modules;
# Partition module files because between NixOS and non-NixOS files. NixOS
# files may change if the repository is updated.

View file

@ -48,7 +48,7 @@ in
Rather, it should be the path of a symlink that points to the
actual shell in the Nix store.
'';
type = types.uniq types.path;
type = types.path;
};
};

View file

@ -16,6 +16,7 @@ in
programs.ssh = {
forwardX11 = mkOption {
type = types.bool;
default = false;
description = ''
Whether to request X11 forwarding on outgoing connections by default.
@ -29,18 +30,21 @@ in
};
setXAuthLocation = mkOption {
type = types.bool;
default = true;
description = ''
Whether to set the path to <command>xauth</command> for X11-forwarded connections.
Pulls in X11 dependency.
This causes a dependency on X11 packages.
'';
};
extraConfig = mkOption {
type = types.lines;
default = "";
description = ''
Extra configuration text appended to <filename>ssh_config</filename>.
See the ssh_config(5) man page for help.
See <citerefentry><refentrytitle>ssh_config</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for help.
'';
};
};

View file

@ -32,7 +32,6 @@ let
zipAttrsWith (n: v:
if tail v != [] then
if n == "_type" then (head v)
else if n == "extraConfigs" then concatLists v
else if n == "warnings" then concatLists v
else if n == "description" || n == "apply" then
abort "Cannot rename an option to multiple options."
@ -55,12 +54,7 @@ let
inherit visible;
});
}
{ options = setTo (mkOption {
extraConfigs =
let externalDefs = (fromOf options).definitions; in
if externalDefs == [] then []
else map (def: def.value) (define externalDefs);
});
{ config = setTo (mkIf (fromOf options).isDefined (define (mkMerge (fromOf options).definitions)));
}
];
@ -75,10 +69,9 @@ let
in zipModules ([]
# usage example:
# ++ alias [ "services" "xserver" "slim" "theme" ] [ "services" "xserver" "displayManager" "slim" "theme" ]
++ obsolete [ "environment" "extraPackages" ] [ "environment" "systemPackages" ]
++ obsolete [ "environment" "x11Packages" ] [ "environment" "systemPackages" ]
++ obsolete [ "environment" "enableBashCompletion" ] [ "programs" "bash" "enableCompletion" ]
++ obsolete [ "environment" "nix" ] [ "nix" "package" ]
++ obsolete [ "security" "extraSetuidPrograms" ] [ "security" "setuidPrograms" ]
++ obsolete [ "networking" "enableWLAN" ] [ "networking" "wireless" "enable" ]
@ -98,6 +91,7 @@ in zipModules ([]
++ obsolete [ "boot" "grubSplashImage" ] [ "boot" "loader" "grub" "splashImage" ]
++ obsolete [ "boot" "initrd" "extraKernelModules" ] [ "boot" "initrd" "kernelModules" ]
++ obsolete [ "boot" "extraKernelParams" ] [ "boot" "kernelParams" ]
# OpenSSH
++ obsolete [ "services" "sshd" "ports" ] [ "services" "openssh" "ports" ]

View file

@ -15,6 +15,7 @@ with pkgs.lib;
security.apparmor = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Enable AppArmor application security system. Enable only if
@ -23,8 +24,8 @@ with pkgs.lib;
};
profiles = mkOption {
type = types.listOf types.path;
default = [];
merge = mergeListOption;
description = ''
List of file names of AppArmor profiles.
'';

View file

@ -13,7 +13,7 @@ let
name = mkOption {
example = "sshd";
type = types.uniq types.string;
type = types.str;
description = "Name of the PAM service.";
};
@ -133,7 +133,7 @@ let
};
text = mkOption {
type = types.nullOr types.string;
type = types.nullOr types.lines;
description = "Contents of the PAM service file.";
};

View file

@ -17,6 +17,7 @@ in
security.pam.usb = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Enable USB login for all login systems that support it. For

View file

@ -13,11 +13,13 @@ in
options = {
security.polkit.enable = mkOption {
type = types.bool;
default = true;
description = "Whether to enable PolKit.";
};
security.polkit.permissions = mkOption {
type = types.lines;
default = "";
example =
''
@ -49,6 +51,7 @@ in
};
security.polkit.adminIdentities = mkOption {
type = types.str;
default = "unix-user:0;unix-group:wheel";
example = "";
description =

View file

@ -5,6 +5,7 @@ with pkgs.lib;
{
options = {
security.rngd.enable = mkOption {
type = types.bool;
default = true;
description = ''
Whether to enable the rng daemon, which adds entropy from

View file

@ -10,6 +10,7 @@ with pkgs.lib;
options = {
security.rtkit.enable = mkOption {
type = types.bool;
default = false;
description = ''
Whether to enable the RealtimeKit system service, which hands

View file

@ -25,7 +25,9 @@ in
options = {
security.setuidPrograms = mkOption {
type = types.listOf types.str;
default = [];
example = ["passwd"];
description = ''
The Nix store cannot contain setuid/setgid programs directly.
For this reason, NixOS can automatically generate wrapper
@ -36,6 +38,7 @@ in
};
security.setuidOwners = mkOption {
type = types.listOf types.attrs;
default = [];
example =
[ { program = "sendmail";
@ -53,6 +56,8 @@ in
};
security.wrapperDir = mkOption {
internal = true;
type = types.path;
default = "/var/setuid-wrappers";
description = ''
This option defines the path to the setuid wrappers. It

View file

@ -17,6 +17,7 @@ in
options = {
security.sudo.enable = mkOption {
type = types.bool;
default = true;
description =
''
@ -26,6 +27,7 @@ in
};
security.sudo.wheelNeedsPassword = mkOption {
type = types.bool;
default = true;
description =
''
@ -35,6 +37,7 @@ in
};
security.sudo.configFile = mkOption {
type = types.lines;
# Note: if syntax errors are detected in this file, the NixOS
# configuration will fail to build.
description =

View file

@ -20,14 +20,15 @@ in
sound = {
enable = mkOption {
type = types.bool;
default = true;
description = ''
Whether to enable ALSA sound.
'';
merge = mergeEnableOption;
};
enableOSSEmulation = mkOption {
type = types.bool;
default = true;
description = ''
Whether to enable ALSA OSS emulation (with certain cards sound mixing may not work!).

View file

@ -21,7 +21,7 @@ with pkgs.lib;
name = mkOption {
example = "Media Center";
type = with types; uniq string;
type = types.str;
description = ''
Enables Fuppes (UPnP A/V Media Server). Can be used to watch
photos, video and listen to music from a phone/tv connected to the
@ -41,7 +41,7 @@ with pkgs.lib;
file = mkOption {
default = "/var/log/fuppes.log";
type = with types; uniq string;
type = types.str;
description = ''
File which will contains the log produced by the daemon.
'';
@ -50,7 +50,7 @@ with pkgs.lib;
config = mkOption {
example = "/etc/fuppes/fuppes.cfg";
type = with types; uniq string;
type = types.str;
description = ''
Mutable configuration file which can be edited with the web
interface. Due to possible modification, double quote the full
@ -69,7 +69,7 @@ with pkgs.lib;
database = mkOption {
default = "/var/lib/fuppes/fuppes.db";
type = with types; uniq string;
type = types.str;
description = ''
Database file which index all shared files.
'';
@ -88,7 +88,7 @@ with pkgs.lib;
user = mkOption {
default = "root"; # The default is not secure.
example = "fuppes";
type = with types; uniq string;
type = types.str;
description = ''
Name of the user which own the configuration files and under which
the fuppes daemon will be executed.

View file

@ -24,12 +24,12 @@ with pkgs.lib;
};
listenAddress = mkOption {
default = null;
default = null;
description = "IP address to listen on.";
};
port = mkOption {
default = 8080;
default = 8080;
description = "port to listen on.";
};
@ -45,9 +45,12 @@ with pkgs.lib;
###### implementation
config = mkIf cfg.enable (
mkAssert (cfg.enable -> cfg.database != "")
"Must specify database name" {
config = mkIf cfg.enable {
assertions = singleton
{ assertion = cfg.enable -> cfg.database != "";
message = "Must specify 4Store database name";
};
users.extraUsers = singleton
{ name = endpointUser;
@ -63,10 +66,10 @@ with pkgs.lib;
startOn = "filesystem";
exec = ''
${run} '${pkgs.rdf4store}/bin/4s-httpd -D ${cfg.options} ${if cfg.listenAddress!=null then "-H ${cfg.listenAddress}" else "" } -p ${toString cfg.port} ${cfg.database}'
${run} '${pkgs.rdf4store}/bin/4s-httpd -D ${cfg.options} ${if cfg.listenAddress!=null then "-H ${cfg.listenAddress}" else "" } -p ${toString cfg.port} ${cfg.database}'
'';
};
});
};
}

View file

@ -36,9 +36,12 @@ with pkgs.lib;
###### implementation
config = mkIf cfg.enable (
mkAssert (cfg.enable -> cfg.database != "")
"Must specify database name" {
config = mkIf cfg.enable {
assertions = singleton
{ assertion = cfg.enable -> cfg.database != "";
message = "Must specify 4Store database name.";
};
users.extraUsers = singleton
{ name = fourStoreUser;
@ -56,16 +59,16 @@ with pkgs.lib;
preStart = ''
mkdir -p ${stateDir}/
chown ${fourStoreUser} ${stateDir}
if ! test -e "${stateDir}/${cfg.database}"; then
${run} -c '${pkgs.rdf4store}/bin/4s-backend-setup ${cfg.database}'
if ! test -e "${stateDir}/${cfg.database}"; then
${run} -c '${pkgs.rdf4store}/bin/4s-backend-setup ${cfg.database}'
fi
'';
exec = ''
${run} -c '${pkgs.rdf4store}/bin/4s-backend -D ${cfg.options} ${cfg.database}'
${run} -c '${pkgs.rdf4store}/bin/4s-backend -D ${cfg.options} ${cfg.database}'
'';
};
});
};
}

View file

@ -46,6 +46,7 @@ in
services.postgresql = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Whether to run PostgreSQL.
@ -53,6 +54,7 @@ in
};
package = mkOption {
type = types.path;
example = literalExample "pkgs.postgresql92";
description = ''
PostgreSQL package to use.
@ -60,6 +62,7 @@ in
};
port = mkOption {
type = types.int;
default = "5432";
description = ''
Port for PostgreSQL.
@ -67,6 +70,7 @@ in
};
dataDir = mkOption {
type = types.path;
default = "/var/db/postgresql";
description = ''
Data directory for PostgreSQL.
@ -74,6 +78,7 @@ in
};
authentication = mkOption {
type = types.lines;
default = "";
description = ''
Defines how users authenticate themselves to the server.
@ -81,6 +86,7 @@ in
};
identMap = mkOption {
type = types.lines;
default = "";
description = ''
Defines the mapping from system users to database users.
@ -88,14 +94,15 @@ in
};
initialScript = mkOption {
default = null;
type = types.nullOr types.path;
default = null;
description = ''
A file containing SQL statements to execute on first startup.
'';
};
enableTCPIP = mkOption {
type = types.bool;
default = false;
description = ''
Whether to run PostgreSQL with -i flag to enable TCP/IP connections.
@ -103,8 +110,9 @@ in
};
extraPlugins = mkOption {
type = types.listOf types.path;
default = [];
example = "pkgs.postgis"; # of course don't use a string here!
example = literalExample "pkgs.postgis";
description = ''
When this list contains elements a new store path is created.
PostgreSQL and the elments are symlinked into it. Then pg_config,
@ -118,15 +126,16 @@ in
};
extraConfig = mkOption {
type = types.lines;
default = "";
description = "Additional text to be appended to <filename>postgresql.conf</filename>.";
};
recoveryConfig = mkOption {
type = types.nullOr types.lines;
default = null;
type = types.nullOr types.string;
description = ''
Values to put into recovery.conf file.
Contents of the <filename>recovery.conf</filename> file.
'';
};
};

View file

@ -14,6 +14,7 @@ let
${condOption "unixsocket" cfg.unixSocket}
loglevel ${cfg.logLevel}
logfile ${cfg.logfile}
syslog-enabled ${redisBool cfg.syslog}
databases ${toString cfg.databases}
${concatMapStrings (d: "save ${toString (builtins.elemAt d 0)} ${toString (builtins.elemAt d 1)}\n") cfg.save}
dbfilename ${cfg.dbFilename}
@ -82,12 +83,18 @@ in
};
logfile = mkOption {
default = "stdout";
default = "/dev/null";
description = "Specify the log file name. Also 'stdout' can be used to force Redis to log on the standard output.";
example = "/var/log/redis.log";
type = with types; string;
};
syslog = mkOption {
default = true;
description = "Enable logging to the system logger.";
type = with types; bool;
};
databases = mkOption {
default = 16;
description = "Set the number of databases.";
@ -177,8 +184,9 @@ in
config = mkIf config.services.redis.enable {
users.extraUsers = singleton
users.extraUsers.redis =
{ name = cfg.user;
uid = config.ids.uids.redis;
description = "Redis database user";
};

View file

@ -21,7 +21,8 @@ in
language = mkOption {
default = "English";
check = lang: elem lang [ "English" "Spanish" "Russian" "Serbian" "Turkish" ];
type = types.addCheck types.str
(lang: elem lang [ "English" "Spanish" "Russian" "Serbian" "Turkish" ]);
description = "The language of bot messages: English, Spanish, Russian, Serbian or Turkish.";
};

View file

@ -66,21 +66,25 @@ in
services.acpid = {
enable = mkOption {
type = types.bool;
default = false;
description = "Whether to enable the ACPI daemon.";
};
powerEventCommands = mkOption {
type = types.lines;
default = "";
description = "Shell commands to execute on a button/power.* event.";
};
lidEventCommands = mkOption {
type = types.lines;
default = "";
description = "Shell commands to execute on a button/lid.* event.";
};
acEventCommands = mkOption {
type = types.lines;
default = "";
description = "Shell commands to execute on an ac_adapter.* event.";
};

View file

@ -9,6 +9,7 @@ with pkgs.lib;
options = {
hardware.bluetooth.enable = mkOption {
type = types.bool;
default = false;
description = "Whether to enable support for Bluetooth.";
};

View file

@ -2,6 +2,12 @@
with pkgs.lib;
let
pkg = if config.hardware.sane.snapshot then pkgs.saneBackendsGit else pkgs.saneBackends;
in
{
###### interface
@ -9,11 +15,13 @@ with pkgs.lib;
options = {
hardware.sane.enable = mkOption {
type = types.bool;
default = false;
description = "Enable support for SANE scanners.";
};
hardware.sane.snapshot = mkOption {
type = types.bool;
default = false;
description = "Use a development snapshot of SANE scanner drivers.";
};
@ -23,18 +31,13 @@ with pkgs.lib;
###### implementation
config = let pkg = if config.hardware.sane.snapshot
then pkgs.saneBackendsGit
else pkgs.saneBackends;
in mkIf config.hardware.sane.enable {
environment.systemPackages = [ pkg ];
services.udev.packages = [ pkg ];
users.extraGroups = singleton {
name = "scanner";
gid = config.ids.gids.scanner;
};
config = mkIf config.hardware.sane.enable {
};
environment.systemPackages = [ pkg ];
services.udev.packages = [ pkg ];
users.extraGroups."scanner".gid = config.ids.gids.scanner;
};
}

View file

@ -114,6 +114,7 @@ in
options = {
boot.hardwareScan = mkOption {
type = types.bool;
default = true;
description = ''
Whether to try to load kernel modules for all detected hardware.
@ -126,8 +127,8 @@ in
services.udev = {
packages = mkOption {
type = types.listOf types.path;
default = [];
merge = mergeListOption;
description = ''
List of packages containing <command>udev</command> rules.
All files found in
@ -138,8 +139,8 @@ in
};
path = mkOption {
type = types.listOf types.path;
default = [];
merge = mergeListOption;
description = ''
Packages added to the <envar>PATH</envar> environment variable when
executing programs from Udev rules.
@ -162,9 +163,9 @@ in
};
hardware.firmware = mkOption {
type = types.listOf types.path;
default = [];
example = [ "/root/my-firmware" ];
merge = mergeListOption;
description = ''
List of directories containing firmware files. Such files
will be loaded automatically if the kernel asks for them

View file

@ -13,6 +13,7 @@ with pkgs.lib;
services.udisks = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Whether to enable Udisks, a DBus service that allows

View file

@ -13,6 +13,7 @@ with pkgs.lib;
services.udisks2 = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Whether to enable Udisks, a DBus service that allows

View file

@ -13,6 +13,7 @@ with pkgs.lib;
services.upower = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Whether to enable Upower, a DBus service that provides power

View file

@ -52,7 +52,7 @@ let
levelOption = mkOption {
default = "server";
type = types.uniq types.string;
type = types.str;
description = ''
Set the logcheck level. Either "workstation", "server", or "paranoid".
'';
@ -63,7 +63,7 @@ let
regex = mkOption {
default = "";
type = types.uniq types.string;
type = types.str;
description = ''
Regex specifying which log lines to ignore.
'';
@ -73,7 +73,7 @@ let
ignoreCronOptions = {
user = mkOption {
default = "root";
type = types.uniq types.string;
type = types.str;
description = ''
User that runs the cronjob.
'';
@ -81,7 +81,7 @@ let
cmdline = mkOption {
default = "";
type = types.uniq types.string;
type = types.str;
description = ''
Command line for the cron job. Will be turned into a regex for the logcheck ignore rule.
'';
@ -89,7 +89,7 @@ let
timeArgs = mkOption {
default = null;
type = types.nullOr (types.uniq types.string);
type = types.nullOr (types.str);
example = "02 06 * * *";
description = ''
"min hr dom mon dow" crontab time args, to auto-create a cronjob too.
@ -112,7 +112,7 @@ in
user = mkOption {
default = "logcheck";
type = types.uniq types.string;
type = types.str;
description = ''
Username for the logcheck user.
'';
@ -121,7 +121,7 @@ in
timeOfDay = mkOption {
default = "*";
example = "6";
type = types.uniq types.string;
type = types.str;
description = ''
Time of day to run logcheck. A logcheck will be scheduled at xx:02 each day.
Leave default (*) to run every hour. Of course when nothing special was logged,
@ -132,7 +132,7 @@ in
mailTo = mkOption {
default = "root";
example = "you@domain.com";
type = types.uniq types.string;
type = types.str;
description = ''
Email address to send reports to.
'';
@ -140,7 +140,7 @@ in
level = mkOption {
default = "server";
type = types.uniq types.string;
type = types.str;
description = ''
Set the logcheck level. Either "workstation", "server", or "paranoid".
'';

View file

@ -99,7 +99,7 @@ in
mkHash functions, which take a string representation of a float and an
attrset, respectively.
'';
merge = mergeConfigs;
apply = mergeConfigs;
};
filterConfig = mkOption {
@ -109,7 +109,7 @@ in
representing a logstash configuration's filter section.
See inputConfig description for details.
'';
merge = mergeConfigs;
apply = mergeConfigs;
};
outputConfig = mkOption {
@ -119,7 +119,7 @@ in
representing a logstash configuration's output section.
See inputConfig description for details.
'';
merge = mergeConfigs;
apply = mergeConfigs;
};
};
};

View file

@ -46,7 +46,7 @@ in
};
tty = mkOption {
type = types.uniq types.string;
type = types.str;
default = "tty10";
description = ''
The tty device on which syslogd will print important log
@ -55,7 +55,7 @@ in
};
defaultConfig = mkOption {
type = types.string;
type = types.lines;
default = defaultConf;
description = ''
The default <filename>syslog.conf</filename> file configures a
@ -73,7 +73,7 @@ in
};
extraConfig = mkOption {
type = types.string;
type = types.lines;
default = "";
example = "news.* -/var/log/news";
description = ''

View file

@ -35,7 +35,7 @@ in
bind = mkOption {
default = "0.0.0.0";
type = with types; uniq string;
type = types.str;
description = ''
Bind over an IPv4 address instead of any.
'';
@ -44,7 +44,7 @@ in
logFile = mkOption {
default = "/var/log/freepopsd";
example = "syslog";
type = with types; uniq string;
type = types.str;
description = ''
Filename of the log file or syslog to rely on the logging daemon.
'';
@ -53,7 +53,7 @@ in
suid = {
user = mkOption {
default = "nobody";
type = with types; uniq string;
type = types.str;
description = ''
User name under which freepopsd will be after binding the port.
'';
@ -61,7 +61,7 @@ in
group = mkOption {
default = "nogroup";
type = with types; uniq string;
type = types.str;
description = ''
Group under which freepopsd will be after binding the port.
'';

View file

@ -6,7 +6,7 @@ let
cfg = config.nix;
inherit (config.environment) nix;
nix = cfg.package;
makeNixBuildUser = nr:
{ name = "nixbld${toString nr}";
@ -55,19 +55,20 @@ in
options = {
environment.nix = mkOption {
default = pkgs.nix;
merge = mergeOneOption;
description = ''
This option specifies the Nix package instance to use throughout the system.
'';
};
nix = {
package = mkOption {
type = types.path;
default = pkgs.nix;
description = ''
This option specifies the Nix package instance to use throughout the system.
'';
};
maxJobs = mkOption {
type = types.int;
default = 1;
example = 2;
example = 64;
description = "
This option defines the maximum number of jobs that Nix will try
to build in parallel. The default is 1. You should generally
@ -77,8 +78,8 @@ in
};
useChroot = mkOption {
type = types.bool;
default = false;
example = true;
description = "
If set, Nix will perform builds in a chroot-environment that it
will set up automatically for each build. This prevents
@ -88,6 +89,7 @@ in
};
chrootDirs = mkOption {
type = types.listOf types.str;
default = [];
example = [ "/dev" "/proc" ];
description =
@ -98,15 +100,17 @@ in
};
extraOptions = mkOption {
type = types.lines;
default = "";
example = "
example = ''
gc-keep-outputs = true
gc-keep-derivations = true
";
'';
description = "Additional text appended to <filename>nix.conf</filename>.";
};
distributedBuilds = mkOption {
type = types.bool;
default = false;
description = ''
Whether to distribute builds to the machines listed in
@ -115,22 +119,25 @@ in
};
daemonNiceLevel = mkOption {
type = types.int;
default = 0;
description = "
description = ''
Nix daemon process priority. This priority propagates to build processes.
0 is the default Unix process priority, 20 is the lowest.
";
'';
};
daemonIONiceLevel = mkOption {
type = types.int;
default = 0;
description = "
description = ''
Nix daemon process I/O priority. This priority propagates to build processes.
0 is the default Unix process I/O priority, 7 is the lowest.
";
'';
};
buildMachines = mkOption {
type = types.listOf types.attrs;
default = [];
example = [
{ hostName = "voila.labs.cs.uu.nl";
@ -160,7 +167,7 @@ in
user name to be used for the SSH connection
(<varname>sshUser</varname>), the Nix system type
(<varname>system</varname>, e.g.,
<literal>\"i686-linux\"</literal>), the maximum number of
<literal>"i686-linux"</literal>), the maximum number of
jobs to be run in parallel on that machine
(<varname>maxJobs</varname>), the path to the SSH private
key to be used to connect (<varname>sshKey</varname>), a
@ -176,24 +183,26 @@ in
};
proxy = mkOption {
type = types.str;
default = "";
description = "
description = ''
This option specifies the proxy to use for fetchurl. The real effect
is just exporting http_proxy, https_proxy and ftp_proxy with that
value.
";
'';
example = "http://127.0.0.1:3128";
};
# Environment variables for running Nix.
envVars = mkOption {
type = types.attrs;
internal = true;
default = {};
type = types.attrs;
description = "Environment variables used by Nix.";
};
nrBuildUsers = mkOption {
type = types.int;
default = 10;
description = ''
Number of <literal>nixbld</literal> user accounts created to
@ -204,6 +213,7 @@ in
};
readOnlyStore = mkOption {
type = types.bool;
default = true;
description = ''
If set, NixOS will enforce the immutability of the Nix store
@ -214,8 +224,8 @@ in
};
binaryCaches = mkOption {
type = types.listOf types.str;
default = [ http://cache.nixos.org/ ];
type = types.listOf types.string;
description = ''
List of binary cache URLs used to obtain pre-built binaries
of Nix packages.
@ -223,9 +233,9 @@ in
};
trustedBinaryCaches = mkOption {
type = types.listOf types.str;
default = [ ];
example = [ http://hydra.nixos.org/ ];
type = types.listOf types.string;
description = ''
List of binary cache URLs that non-root users can use (in
addition to those specified using
@ -302,7 +312,7 @@ in
}
// optionalAttrs cfg.distributedBuilds {
NIX_BUILD_HOOK = "${config.environment.nix}/libexec/nix/build-remote.pl";
NIX_BUILD_HOOK = "${nix}/libexec/nix/build-remote.pl";
NIX_REMOTE_SYSTEMS = "/etc/nix/machines";
NIX_CURRENT_LOAD = "/run/nix/current-load";
}

View file

@ -22,7 +22,7 @@ in
dates = mkOption {
default = "03:15";
type = types.uniq types.string;
type = types.str;
description = ''
Specification (in the format described by
<citerefentry><refentrytitle>systemd.time</refentrytitle>
@ -34,7 +34,7 @@ in
options = mkOption {
default = "";
example = "--max-freed $((64 * 1024**3))";
type = types.uniq types.string;
type = types.str;
description = ''
Options given to <filename>nix-collect-garbage</filename> when the
garbage collector is run automatically.
@ -52,7 +52,7 @@ in
systemd.services.nix-gc =
{ description = "Nix Garbage Collector";
script = "exec ${config.environment.nix}/bin/nix-collect-garbage ${cfg.options}";
script = "exec ${config.nix.package}/bin/nix-collect-garbage ${cfg.options}";
startAt = optionalString cfg.automatic cfg.dates;
};

View file

@ -16,13 +16,15 @@ let
system.nixosRevision = config.system.nixosRevision;
};
eval = evalModules {
modules = [ versionModule ] ++ baseModules;
args = (removeAttrs extraArgs ["config" "options"]) // { modules = [ ]; };
};
manual = import ../../../doc/manual {
inherit pkgs;
revision = config.system.nixosRevision;
options = (fixMergeModules ([ versionModule ] ++ baseModules)
(removeAttrs extraArgs ["config" "options"]) // {
modules = [ ];
}).options;
options = eval.options;
};
entry = "${manual.manual}/share/doc/nixos/manual.html";
@ -51,14 +53,15 @@ in
options = {
services.nixosManual.enable = mkOption {
default = true;
type = types.bool;
default = true;
description = ''
Whether to build the NixOS manual pages.
'';
};
services.nixosManual.showManual = mkOption {
type = types.bool;
default = false;
description = ''
Whether to show the NixOS manual on one of the virtual
@ -74,6 +77,7 @@ in
};
services.nixosManual.browser = mkOption {
type = types.path;
default = "${pkgs.w3m}/bin/w3m";
description = ''
Browser used to show the manual.

View file

@ -17,6 +17,7 @@ in
options = {
services.rogue.enable = mkOption {
type = types.bool;
default = false;
description = ''
Whether to enable the Rogue game on one of the virtual
@ -25,6 +26,7 @@ in
};
services.rogue.tty = mkOption {
type = types.str;
default = "tty9";
description = ''
Virtual console on which to run Rogue.

View file

@ -22,58 +22,56 @@ in
enable = mkOption {
default = false;
description = "
Whether to enable the synergy client (receive keyboard and mouse events from a synergy server)
Whether to enable the Synergy client (receive keyboard and mouse events from a Synergy server).
";
};
screenName = mkOption {
default = "";
description = "
use screen-name instead the hostname to identify
description = ''
Use the given name instead of the hostname to identify
ourselves to the server.
";
'';
};
serverAddress = mkOption {
description = "
description = ''
The server address is of the form: [hostname][:port]. The
hostname must be the address or hostname of the server. The
port overrides the default port, 24800.
";
'';
};
autoStart = mkOption {
default = true;
type = types.bool;
description = "Whether synergy-client should be started automatically.";
description = "Whether the Synergy client should be started automatically.";
};
};
server = {
enable = mkOption {
default = false;
description = "
Whether to enable the synergy server (send keyboard and mouse events)
";
description = ''
Whether to enable the Synergy server (send keyboard and mouse events).
'';
};
configFile = mkOption {
default = "/etc/synergy-server.conf";
description = "
The synergy server configuration file. open upstart-jobs/synergy.nix to see an example
";
description = "The Synergy server configuration file.";
};
screenName = mkOption {
default = "";
description = "
use screen-name instead the hostname to identify
description = ''
Use the given name instead of the hostname to identify
this screen in the configuration.
";
'';
};
address = mkOption {
default = "";
description = "listen for clients on the given address";
description = "Address on which to listen for clients.";
};
autoStart = mkOption {
default = true;
type = types.bool;
description = "Whether synergy-server should be started automatically.";
description = "Whether the Synergy server should be started automatically.";
};
};
};

View file

@ -26,7 +26,7 @@ in {
example = "ae0aa6a8f08efa988ba0a17578f009ab";
type = types.uniq types.string;
type = types.str;
};
hostname = mkOption {

View file

@ -8,7 +8,7 @@ let
dataDir = "/var/db/graphite";
carbonOpts = name: with config.ids; ''
--nodaemon --syslog --prefix=${name} \
--nodaemon --syslog --prefix=${name} --pidfile /var/run/${name}.pid \
--uid ${toString uids.graphite} --gid ${toString uids.graphite} ${name}
'';
carbonEnv = {
@ -32,13 +32,13 @@ in {
host = mkOption {
description = "Graphite web frontend listen address";
default = "127.0.0.1";
types = type.uniq types.string;
type = types.str;
};
port = mkOption {
description = "Graphite web frontend port";
default = "8080";
types = type.uniq types.string;
type = types.str;
};
};
@ -52,8 +52,11 @@ in {
PICKLE_RECEIVER_INTERFACE = 127.0.0.1
LINE_RECEIVER_INTERFACE = 127.0.0.1
CACHE_QUERY_INTERFACE = 127.0.0.1
# Do not log every update
LOG_UPDATES = False
LOG_CACHE_HITS = False
'';
type = types.uniq types.string;
type = types.str;
};
enableCache = mkOption {

View file

@ -12,16 +12,15 @@ let
device = mkOption {
example = "/dev/sda";
type = types.string;
type = types.str;
description = "Location of the device.";
};
options = mkOption {
default = "";
example = "-d sat";
type = types.string;
merge = pkgs.lib.concatStringsSep " ";
description = "Options that determine how smartd monitors the device";
type = types.separatedString " ";
description = "Options that determine how smartd monitors the device.";
};
};

View file

@ -36,7 +36,7 @@ in
host = mkOption {
description = "Address that statsd listens on over UDP";
default = "127.0.0.1";
type = types.uniq types.string;
type = types.str;
};
port = mkOption {
@ -48,7 +48,7 @@ in
mgmt_address = mkOption {
description = "Address to run managment TCP interface on";
default = "127.0.0.1";
type = types.uniq types.string;
type = types.str;
};
mgmt_port = mkOption {
@ -65,7 +65,7 @@ in
graphiteHost = mkOption {
description = "Hostname or IP of Graphite server";
default = "127.0.0.1";
type = types.uniq types.string;
type = types.str;
};
graphitePort = mkOption {
@ -77,7 +77,7 @@ in
extraConfig = mkOption {
default = "";
description = "Extra configuration options for statsd";
type = types.uniq types.string;
type = types.str;
};
};

View file

@ -15,7 +15,7 @@ let
# This can be infered from the UPS model by looking at
# /nix/store/nut/share/driver.list
driver = mkOption {
type = types.uniq types.string;
type = types.str;
description = ''
Specify the program to run to talk to this UPS. apcsmart,
bestups, and sec are some examples.
@ -23,7 +23,7 @@ let
};
port = mkOption {
type = types.uniq types.string;
type = types.str;
description = ''
The serial port to which your UPS is connected. /dev/ttyS0 is
usually the first port on Linux boxes, for example.
@ -115,7 +115,7 @@ in
# This option is not used yet.
mode = mkOption {
default = "standalone";
type = types.uniq types.string;
type = types.str;
description = ''
The MODE determines which part of the NUT is to be started, and
which configuration files must be modified.
@ -142,7 +142,7 @@ in
schedulerRules = mkOption {
example = "/etc/nixos/upssched.conf";
type = types.uniq types.string;
type = types.str;
description = ''
File which contains the rules to handle UPS events.
'';

View file

@ -50,7 +50,7 @@ in
};
hostName = mkOption {
type = types.uniq types.string;
type = types.str;
description = ''Host name advertised on the LAN.'';
};

View file

@ -64,7 +64,7 @@ in
authMode = mkOption {
default = "Open";
check = authModeCheck;
type = types.addCheck types.str authModeCheck;
description = ''
The following authentication modes are available:
Open -- Accept connections from anyone, use NickServ for user authentication.

View file

@ -39,7 +39,7 @@ in
};
netbios_hostname = mkOption {
type = types.uniq types.string;
type = types.str;
description = ''
The hostname of your machine.
'';

View file

@ -1,111 +0,0 @@
{ config, pkgs, ... }:
with pkgs.lib;
let
inherit (pkgs) nettools dhcp lib;
# Don't start dhclient on explicitly configured interfaces or on
# interfaces that are part of a bridge.
ignoredInterfaces =
map (i: i.name) (lib.filter (i: i ? ipAddress && i.ipAddress != "" ) config.networking.interfaces)
++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bridges));
stateDir = "/var/lib/dhcp"; # Don't use /var/state/dhcp; not FHS-compliant.
dhclientExitHooks = pkgs.writeText "dhclient-exit-hooks"
''
#echo "$reason" >> /tmp/dhcp-exit
#echo "$exit_status" >> /tmp/dhcp-exit
if test "$reason" = BOUND -o "$reason" = REBOOT; then
# Restart ntpd. (The "ip-up" event below will trigger the
# restart.) We need to restart it to make sure that it will
# actually do something: if ntpd cannot resolve the server
# hostnames in its config file, then it will never do
# anything ever again ("couldn't resolve ..., giving up on
# it"), so we silently lose time synchronisation.
${config.system.build.upstart}/sbin/initctl stop ntpd
${config.system.build.upstart}/sbin/initctl emit -n ip-up
fi
if test "$reason" = EXPIRE -o "$reason" = RELEASE; then
${config.system.build.upstart}/sbin/initctl emit -n ip-down
fi
'';
in
{
###### implementation
config = mkIf config.networking.useDHCP {
# dhclient barfs if /proc/net/if_inet6 doesn't exist.
boot.kernelModules = [ "ipv6" ];
jobs.dhclient =
{ startOn = "started network-interfaces";
stopOn = "stopping network-interfaces";
path = [ dhcp ];
script =
''
# Determine the interface on which to start dhclient.
interfaces=
for i in $(cd /sys/class/net && ls -d *); do
# Only run dhclient on interfaces of type ARPHRD_ETHER
# (1), i.e. Ethernet. Ignore peth* devices; on Xen,
# they're renamed physical Ethernet cards used for
# bridging. Likewise for vif* and tap* (Xen) and
# virbr* and vnet* (libvirt).
if [ "$(cat /sys/class/net/$i/type)" = 1 ]; then
if ! for j in ${toString ignoredInterfaces}; do echo $j; done | grep -F -x -q "$i" &&
! echo "$i" | grep -x -q "peth.*\|vif.*\|tap.*\|virbr.*\|vnet.*";
then
echo "Running dhclient on $i"
interfaces="$interfaces $i"
fi
fi
done
if test -z "$interfaces"; then
echo 'No interfaces on which to start dhclient!'
exit 1
fi
mkdir -m 755 -p ${stateDir}
exec dhclient -d $interfaces -e "PATH=$PATH" -lf ${stateDir}/dhclient.leases -sf ${dhcp}/sbin/dhclient-script
'';
};
environment.systemPackages = [dhcp];
environment.etc =
[ # Dhclient hooks for emitting ip-up/ip-down events.
{ source = dhclientExitHooks;
target = "dhclient-exit-hooks";
}
];
powerManagement.resumeCommands =
''
${config.system.build.upstart}/sbin/restart dhclient
'';
networking.interfaceMonitor.commands =
''
if [ "$status" = up ]; then
${config.system.build.upstart}/sbin/restart dhclient
fi
'';
};
}

View file

@ -6,7 +6,7 @@ let
inherit (pkgs) dhcpcd;
# Don't start dhclient on explicitly configured interfaces or on
# Don't start dhcpcd on explicitly configured interfaces or on
# interfaces that are part of a bridge.
ignoredInterfaces =
map (i: i.name) (filter (i: i.ipAddress != null) (attrValues config.networking.interfaces))

View file

@ -15,7 +15,7 @@ let
authoritative;
ddns-update-style ad-hoc;
log-facility local1; # see dhcpd.nix
${cfg.extraConfig}
${pkgs.lib.concatMapStrings
@ -30,13 +30,13 @@ let
'';
in
{
###### interface
options = {
services.dhcpd = {
enable = mkOption {
@ -48,16 +48,16 @@ in
extraConfig = mkOption {
default = "";
example = "
example = ''
option subnet-mask 255.255.255.0;
option broadcast-address 192.168.1.255;
option routers 192.168.1.5;
option domain-name-servers 130.161.158.4, 130.161.33.17, 130.161.180.1;
option domain-name \"example.org\";
option domain-name "example.org";
subnet 192.168.1.0 netmask 255.255.255.0 {
range 192.168.1.100 192.168.1.200;
}
";
'';
description = "
Extra text to be appended to the DHCP server configuration
file. Currently, you almost certainly need to specify
@ -100,9 +100,9 @@ in
};
};
};
###### implementation
@ -127,5 +127,5 @@ in
};
};
}

View file

@ -53,6 +53,7 @@ in
options = {
networking.firewall.enable = mkOption {
type = types.bool;
default = false;
description =
''
@ -64,6 +65,7 @@ in
};
networking.firewall.logRefusedConnections = mkOption {
type = types.bool;
default = true;
description =
''
@ -72,6 +74,7 @@ in
};
networking.firewall.logRefusedPackets = mkOption {
type = types.bool;
default = false;
description =
''
@ -82,6 +85,7 @@ in
};
networking.firewall.logRefusedUnicastsOnly = mkOption {
type = types.bool;
default = true;
description =
''
@ -93,6 +97,7 @@ in
};
networking.firewall.rejectPackets = mkOption {
type = types.bool;
default = false;
description =
''
@ -193,6 +198,7 @@ in
};
networking.firewall.extraCommands = mkOption {
type = types.lines;
default = "";
example = "iptables -A INPUT -p icmp -j ACCEPT";
description =
@ -209,11 +215,8 @@ in
###### implementation
# !!! Maybe if `enable' is false, the firewall should still be built
# but not started by default. However, currently nixos-rebuild
# doesn't deal with such Upstart jobs properly (it starts them if
# they are changed, regardless of whether the start condition
# holds).
# FIXME: Maybe if `enable' is false, the firewall should still be
# built but not started by default?
config = mkIf cfg.enable {
networking.firewall.trustedInterfaces = [ "lo" ];

View file

@ -15,38 +15,35 @@ in
default = false;
type = types.bool;
description = ''
Enable the gogoclient ipv6 tunnel.
Enable the gogoCLIENT IPv6 tunnel.
'';
};
autorun = mkOption {
default = true;
description = "
Switch to false to create upstart-job and configuration,
but not run it automatically
";
description = ''
Whether to automatically start the tunnel.
'';
};
username = mkOption {
default = "";
description = "
description = ''
Your Gateway6 login name, if any.
";
'';
};
password = mkOption {
default = "";
type = types.string;
description = "
Path to a file (as a string), containing your gogonet password, if any.
";
description = ''
Path to a file (as a string), containing your gogoNET password, if any.
'';
};
server = mkOption {
default = "anonymous.freenet6.net";
example = "broker.freenet6.net";
description = "
Used Gateway6 server.
";
description = "The Gateway6 server to be used.";
};
};
};

View file

@ -0,0 +1,87 @@
{ config, pkgs, ...}:
let
cfg = config.services.haproxy;
haproxyCfg = pkgs.writeText "haproxy.conf" cfg.config;
in
with pkgs.lib;
{
options = {
services.haproxy = {
enable = mkOption {
default = false;
description = "
Enable the HAProxy.
";
};
config = mkOption {
default =
''
global
log 127.0.0.1 local6
maxconn 24000
daemon
nbproc 1
defaults
mode http
option httpclose
# Remove requests from the queue if people press stop button
option abortonclose
# Try to connect this many times on failure
retries 3
# If a client is bound to a particular backend but it goes down,
# send them to a different one
option redispatch
monitor-uri /haproxy-ping
timeout connect 7s
timeout queue 300s
timeout client 300s
timeout server 300s
# Enable status page at this URL, on the port HAProxy is bound to
stats enable
stats uri /haproxy-status
stats refresh 5s
stats realm Haproxy statistics
'';
description = "
Default configuration.
";
};
};
};
config = mkIf cfg.enable {
systemd.services.haproxy = {
description = "HAProxy";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "forking";
PIDFile = "/var/run/haproxy.pid";
ExecStartPre = "${pkgs.haproxy}/sbin/haproxy -c -q -f ${haproxyCfg}";
ExecStart = "${pkgs.haproxy}/sbin/haproxy -D -f ${haproxyCfg} -p /var/run/haproxy.pid";
ExecReload = "-${pkgs.bash}/bin/bash -c \"exec ${pkgs.haproxy}/sbin/haproxy -D -f ${haproxyCfg} -p /var/run/haproxy.pid -sf $MAINPID\"";
};
};
environment.systemPackages = [ pkgs.haproxy ];
users.extraUsers.haproxy = {
group = "haproxy";
uid = config.ids.uids.haproxy;
};
users.extraGroups.haproxy.gid = config.ids.uids.haproxy;
};
}

View file

@ -9,10 +9,7 @@ let
cfg = config.networking.interfaceMonitor;
# The ifplugd action script, which is called whenever the link
# status changes (i.e., a cable is plugged in or unplugged). We do
# nothing when a cable is unplugged. When a cable is plugged in, we
# restart dhclient, which will hopefully give us a new IP address
# if appropriate.
# status changes (i.e., a cable is plugged in or unplugged).
plugScript = pkgs.writeScript "ifplugd.action"
''
#! ${pkgs.stdenv.shell}
@ -30,17 +27,19 @@ in
options = {
networking.interfaceMonitor.enable = mkOption {
type = types.bool;
default = false;
description = ''
If <literal>true</literal>, monitor Ethernet interfaces for
cables being plugged in or unplugged. When this occurs, the
<command>dhclient</command> service is restarted to
automatically obtain a new IP address. This is useful for
roaming users (laptops).
commands specified in
<option>networking.interfaceMonitor.commands</option> are
executed.
'';
};
networking.interfaceMonitor.beep = mkOption {
type = types.bool;
default = false;
description = ''
If <literal>true</literal>, beep when an Ethernet cable is
@ -49,6 +48,7 @@ in
};
networking.interfaceMonitor.commands = mkOption {
type = types.lines;
default = "";
description = ''
Shell commands to be executed when the link status of an

View file

@ -32,21 +32,21 @@ in
};
ip = mkOption {
type = types.uniq types.string;
type = types.str;
default = "";
description = "Assigned ip address or ip range";
example = "172.16.10.1/24";
};
domain = mkOption {
type = types.uniq types.string;
type = types.str;
default = "";
description = "Domain or subdomain of which nameservers point to us";
example = "tunnel.mydomain.com";
};
extraConfig = mkOption {
type = types.uniq types.string;
type = types.str;
default = "";
description = "Additional command line parameters";
example = "-P mysecurepassword -l 192.168.1.10 -p 23";

Some files were not shown because too many files have changed in this diff Show more