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;' */ ["x" "y"] applied with some value v returns `x.y = v;' */
setAttrByPath = attrPath: value: setAttrByPath = attrPath: value:
if attrPath == [] then value if attrPath == [] then value
else listToAttrs [( else listToAttrs
nameValuePair (head attrPath) (setAttrByPath (tail attrPath) value) [ { name = head attrPath; value = setAttrByPath (tail attrPath) value; } ];
)];
getAttrFromPath = attrPath: set: getAttrFromPath = attrPath: set:
@ -133,7 +132,7 @@ rec {
=> { x = "x-foo"; y = "y-bar"; } => { x = "x-foo"; y = "y-bar"; }
*/ */
mapAttrs = f: set: 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 /* 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 # names, hopefully this does not affect the system because the maximal
# laziness avoid computing twice the same expression and listToAttrs does # laziness avoid computing twice the same expression and listToAttrs does
# not care about duplicated attribute names. # 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); zipAttrs = zipAttrsWith (name: values: values);

View File

@ -8,7 +8,6 @@ let
sources = import ./sources.nix; sources = import ./sources.nix;
modules = import ./modules.nix; modules = import ./modules.nix;
options = import ./options.nix; options = import ./options.nix;
properties = import ./properties.nix;
types = import ./types.nix; types = import ./types.nix;
meta = import ./meta.nix; meta = import ./meta.nix;
debug = import ./debug.nix; debug = import ./debug.nix;
@ -21,13 +20,13 @@ let
in in
{ inherit trivial lists strings stringsWithDeps attrsets sources options { 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. # Pull in some builtins not included elsewhere.
inherit (builtins) pathExists readFile; inherit (builtins) pathExists readFile;
} }
# !!! don't include everything at top-level; perhaps only the most # !!! don't include everything at top-level; perhaps only the most
# commonly used functions. # commonly used functions.
// trivial // lists // strings // stringsWithDeps // attrsets // sources // trivial // lists // strings // stringsWithDeps // attrsets // sources
// properties // options // types // meta // debug // misc // modules // options // types // meta // debug // misc // modules
// systems // systems
// customisation // customisation

View File

@ -118,6 +118,11 @@ in rec {
all = pred: fold (x: y: if pred x then y else false) true; 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 # Return a singleton list or an empty list, depending on a boolean
# value. Useful when building lists with optional elements # value. Useful when building lists with optional elements
# (e.g. `++ optional (system == "i686-linux") flashplayer'). # (e.g. `++ optional (system == "i686-linux") flashplayer').
@ -165,10 +170,11 @@ in rec {
zipLists = zipListsWith (fst: snd: { inherit fst snd; }); 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 ]) []; reverseList = fold (e: acc: acc ++ [ e ]) [];
# Sort a list based on a comparator function which compares two # Sort a list based on a comparator function which compares two
# elements and returns true if the first argument is strictly below # elements and returns true if the first argument is strictly below
# the second argument. The returned list is sorted in an increasing # 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 ./lists.nix;
with import ./misc.nix; with import ./trivial.nix;
with import ./attrsets.nix; with import ./attrsets.nix;
with import ./options.nix; with import ./options.nix;
with import ./properties.nix; with import ./debug.nix;
with import ./types.nix;
rec { rec {
# Unfortunately this can also be a string. /* Evaluate a set of modules. The result is a set of two
isPath = x: !( attributes: options: the nested set of all option declarations,
builtins.isFunction x and config: the nested set of all option values. */
|| builtins.isAttrs x evalModules = { modules, prefix ? [], args ? {}, check ? true }:
|| 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:
let let
delayedModule = delayProperties m; args' = args // result;
closed = closeModules modules args';
getImports = # Note: the list of modules is reversed to maintain backward
toList (rmProperties (delayedModule.require or [])); # compatibility with the old module system. Not sure if this is
getImportedPaths = filter isPath getImports; # the most sensible policy.
getImportedSets = filter (x: !isPath x) getImports; options = mergeModules prefix (reverseList closed);
# Traverse options and extract the option values into the final
getConfig = # config set. At the same time, check whether all option
removeAttrs delayedModule ["require" "key" "imports"]; # 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 in
if isModule m then builtins.genericClosure {
{ key = "<unknown location>"; } // m 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 else
{ key = "<unknown location>"; { file = m._file or file;
imports = (m.imports or []) ++ getImportedPaths; key = toString m.key or key;
config = getConfig; imports = m.imports or [];
} // ( options = m.options or {};
if getImportedSets != [] then config = m.config or {};
assert length getImportedSets == 1; }
{ options = head getImportedSets; } 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 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 let
module = lib.applyIfFunction m args; # Process mkOverride properties, adding in the default
key_ = rec { # value specified in the option declaration (if any).
file = key; defsFinal = filterOverrides
option = name; ((if opt ? default then [{ file = head opt.declarations; value = mkOptionDefault opt.default; }] else []) ++ defs);
number = index; files = map (def: def.file) defsFinal;
outPath = key; # Type-check the remaining definitions, and merge them if
}; # possible.
in if lib.isModule module then merged =
{ key = key_; } // module if defsFinal == [] then
else throw "The option `${showOption loc}' is used but not defined."
{ key = key_; options = module; } 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}.")
moduleClosure = initModules: args: (opt.type.merge loc defsFinal) defsFinal;
let # Finally, apply the apply function to the merged
moduleImport = origin: index: m: # value. This allows options to yield a value computed
let m' = applyIfFunction (importIfPath m) args; # from the definitions.
in (unifyModuleSyntax m') // { value = (opt.apply or id) merged;
# used by generic closure to avoid duplicated imports. in opt //
key = { value = addErrorContext "while evaluating the option `${showOption loc}':" value;
if isPath m then m definitions = map (def: def.value) defsFinal;
else m'.key or (newModuleName origin index); isDefined = defsFinal != [];
}; inherit files;
getImports = m: m.imports or [];
newModuleName = origin: index:
"${origin.key}:<import-${toString index}>";
topLevel = {
key = "<top-level>";
}; };
in /* Given a config set, expand mkMerge properties, and push down the
(lazyGenericClosure { mkIf properties into the children. The result is a list of
startSet = imap (moduleImport topLevel) initModules; config sets that do not have properties at top-level. For
operator = m: imap (moduleImport m) (getImports m); example,
});
mkMerge [ { boot = set1; } (mkIf cond { boot = set2; services = set3; }) ]
moduleApply = funs: module: is transformed into
lib.mapAttrs (name: value:
if builtins.hasAttr name funs then [ { boot = set1; } { boot = mkIf cond set2; services mkIf cond set3; } ].
let fun = lib.getAttr name funs; in
fun value 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 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 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 [ { file = "/1"; value = mkOverride 10 "a"; }
# properties and convert them into a list of modules. Delay properties { file = "/2"; value = mkOverride 20 "b"; }
# inside the config attribute of a module and create a second module if a { file = "/3"; value = "z"; }
# mkMerge attribute was left behind. { file = "/4"; value = mkOverride 10 "d"; }
# ]
# Module -> [ Module ]
delayModule = module:
map (moduleApply { config = delayProperties; }) (moduleFlattenMerge module);
yields
evalDefinitions = opt: values: [ { file = "/1"; value = "a"; }
if opt.type.delayOnGlobalEval or false then { file = "/4"; value = "d"; }
map (delayPropertiesWithIter opt.type.iter opt.name) ]
(evalLocalProperties values)
else
evalProperties values;
Note that "z" has the default priority 100.
selectModule = name: m: */
{ inherit (m) key; filterOverrides = defs:
} // (
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_:
let let
addName = name: defaultPrio = 100;
if path == "" then name else path + "." + name; 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_); /* Hack for backward compatibility: convert options of type
optionSet to configOf. FIXME: remove eventually. */
modulesOf = name: filterModules name modules; fixupOptionType = loc: opt:
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:
let let
eol = "\n"; options' = opt.options or
addName = name: (throw "Option `${showOption loc'}' has type optionSet but has no option attribute.");
if path == "" then name else path + "." + name; coerce = x:
in if builtins.isFunction x then x
if lib.isOption options then else { config, ... }: { options = x; };
if options ? options then options = map coerce (flatten options');
options.type.fold f = tp:
(cfg: res: res && checkModule (options.type.docPath path) cfg._args) if tp.name == "option set" then types.submodule options
true config else if tp.name == "attribute set of option sets" then types.attrsOf (types.submodule options)
else else if tp.name == "list or attribute set of option sets" then types.loaOf (types.submodule options)
true else if tp.name == "list of option sets" then types.listOf (types.submodule options)
else if isAttrs options && lib.attrNames m.options != [] then else if tp.name == "null or option set" then types.nullOr (types.submodule options)
all (name: else tp;
lib.addErrorContext "${eol in opt // { type = f (opt.type or types.unspecified); };
}while checking the attribute `${addName name}':${eol
}" (checkModule (addName name) (selectModule name m))
) (lib.attrNames m.config) /* Properties. */
else
builtins.trace "try to evaluate config ${lib.showVal config}." mkIf = condition: content:
false; { _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 let lib = import ./default.nix; in
with { inherit (builtins) head length; };
with import ./trivial.nix; with import ./trivial.nix;
with import ./lists.nix; with import ./lists.nix;
with import ./misc.nix; with import ./misc.nix;
with import ./attrsets.nix; with import ./attrsets.nix;
with import ./properties.nix; with import ./strings.nix;
rec { rec {
isOption = lib.isType "option"; isOption = lib.isType "option";
mkOption = attrs: attrs // { mkOption =
_type = "option"; { default ? null # Default value used when no definition is given in the configuration.
# name (this is the name of the attributem it is automatically generated by the traversal) , defaultText ? null # Textual representation of the default, for in the manual.
# default (value used when no definition exists) , example ? null # Example value used in the manual.
# example (documentation) , description ? null # String describing the option.
# description (documentation) , type ? null # Option type, providing type-checking and value merging.
# type (option type, provide a default merge function and ensure type correctness) , apply ? null # Function that converts the option value to something else.
# merge (function used to merge definitions into one definition: [ /type/ ] -> /type/) , internal ? null # Whether the option is for NixOS developers only.
# apply (convert the option value to ease the manipulation of the option result) , visible ? null # Whether the option shows up in the manual.
# options (set of sub-options declarations & definitions) , options ? null # Obsolete, used by types.optionSet.
# extraConfigs (list of possible configurations) } @ attrs:
}; attrs // { _type = "option"; };
mkEnableOption = name: mkOption { mkEnableOption = name: mkOption {
default = false; default = false;
@ -32,261 +31,65 @@ rec {
type = lib.types.bool; type = lib.types.bool;
}; };
mapSubOptions = f: opt: mergeDefaultOption = loc: defs:
if opt ? options then let list = getValues defs; in
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:
if length list == 1 then head list 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 isList list then concatLists list
else if all isAttrs list then fold lib.mergeAttrs {} list else if all isAttrs list then fold lib.mergeAttrs {} list
else if all builtins.isBool list then fold lib.or false list else if all builtins.isBool list then fold lib.or false list
else if all builtins.isString list then lib.concatStrings list else if all builtins.isString list then lib.concatStrings list
else if all builtins.isInt list && all (x: x == head list) list else if all builtins.isInt list && all (x: x == head list) list then head list
then head list else throw "Cannot merge definitions of `${showOption loc}' given in ${showFiles (getFiles defs)}.";
else throw "Cannot merge values.";
mergeTypedOption = typeName: predicate: merge: list: /* Obsolete, will remove soon. Specify an option type or apply
if all predicate list then merge list function instead. */
else throw "Expect a ${typeName}."; 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" mergeEnableOption = mergeTypedOption "boolean"
(x: true == x || false == x) (fold lib.or false); (x: true == x || false == x) (fold lib.or false);
mergeListOption = mergeTypedOption "list" isList concatLists; mergeListOption = mergeTypedOption "list" isList concatLists;
mergeStringOption = mergeTypedOption "string" mergeStringOption = mergeTypedOption "string" builtins.isString lib.concatStrings;
(x: if builtins ? isString then builtins.isString x else x + "")
lib.concatStrings;
mergeOneOption = list: mergeOneOption = loc: defs:
if list == [] then abort "This case should never happen." if defs == [] then abort "This case should never happen."
else if length list != 1 then throw "Multiple definitions. Only one is allowed for this option." else if length defs != 1 then
else head list; throw "The unique option `${showOption loc}' is defined multiple times, in ${showFiles (getFiles defs)}."
else (head defs).value;
getValues = map (x: x.value);
fixableMergeFun = merge: f: config: getFiles = map (x: x.file);
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;
# Generate documentation template from the list of option declaration like # Generate documentation template from the list of option declaration like
# the set generated with filterOptionSets. # the set generated with filterOptionSets.
optionAttrSetToDocList = attrs: optionAttrSetToDocList = optionAttrSetToDocList' [];
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; };
subOptions = optionAttrSetToDocList' = prefix: options:
if opt ? options then fold (opt: rest:
optionAttrSetToDocList opt.options let
else docOption = rec {
[]; name = showOption opt.loc;
in description = opt.description or (throw "Option `${name}' has no description.");
[ docOption ] ++ subOptions ++ rest declarations = filter (x: x != unknownModule) opt.declarations;
) [] options; 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 /* This function recursively removes all derivation attributes from
@ -295,7 +98,8 @@ rec {
representation of derivations is very large (on the order of representation of derivations is very large (on the order of
megabytes) and is not actually used by the manual generator. */ megabytes) and is not actually used by the manual generator. */
scrubOptionValue = x: 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 isList x then map scrubOptionValue x
else if isAttrs x then mapAttrs (n: v: scrubOptionValue v) (removeAttrs x ["_args"]) else if isAttrs x then mapAttrs (n: v: scrubOptionValue v) (removeAttrs x ["_args"])
else x; else x;
@ -308,4 +112,9 @@ rec {
literalExample = text: { _type = "literalExample"; inherit text; }; 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] && elem x.bits [8 16 32 64 128]
&& (builtins.lessThan 8 x.bits -> isSignificantByte x.significantByte); && (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 && isCpuType x.cpu
&& isArchitecture x.arch && isArchitecture x.arch
&& isKernel x.kernel; && isKernel x.kernel;

View File

@ -1,17 +1,15 @@
# Definitions related to run-time type checking. Used in particular # Definitions related to run-time type checking. Used in particular
# to type-check NixOS configurations. # to type-check NixOS configurations.
let lib = import ./default.nix; in
with import ./lists.nix; with import ./lists.nix;
with import ./attrsets.nix; with import ./attrsets.nix;
with import ./options.nix; with import ./options.nix;
with import ./trivial.nix; with import ./trivial.nix;
with import ./strings.nix;
rec { rec {
isType = type: x: (x._type or "") == type; isType = type: x: (x._type or "") == type;
hasType = x: isAttrs x && x ? _type;
typeOf = x: x._type or ""; typeOf = x: x._type or "";
setType = typeName: value: value // { 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"; isOptionType = isType "option-type";
mkOptionType = mkOptionType =
{ name { # Human-readable representation of the type.
, check ? (x: true) name
, merge ? mergeDefaultOption , # Function applied to each definition that should return true if
# Handle complex structure types. # its type-correct, false otherwise.
, iter ? (f: path: v: f path v) check ? (x: true)
, fold ? (op: nul: v: op v nul) , # Merge a list of definitions together into a single value.
, docPath ? lib.id # This function is called with two arguments: the location of
# If the type can contains option sets. # the option in the configuration as a list of strings
, hasOptions ? false # (e.g. ["boot" "loader "grub" "enable"]), and a list of
, delayOnGlobalEval ? false # 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"; { _type = "option-type";
inherit name check merge iter fold docPath hasOptions delayOnGlobalEval; inherit name check merge getSubOptions;
}; };
types = rec { types = rec {
unspecified = mkOptionType {
name = "unspecified";
};
bool = mkOptionType { bool = mkOptionType {
name = "boolean"; name = "boolean";
check = lib.traceValIfNot builtins.isBool; check = builtins.isBool;
merge = fold lib.or false; merge = loc: fold (x: y: x.value || y) false;
}; };
int = mkOptionType { int = mkOptionType {
name = "integer"; name = "integer";
check = lib.traceValIfNot builtins.isInt; check = builtins.isInt;
merge = mergeOneOption;
}; };
string = mkOptionType { str = mkOptionType {
name = "string"; name = "string";
check = lib.traceValIfNot builtins.isString; check = builtins.isString;
merge = lib.concatStrings; merge = mergeOneOption;
}; };
# Like string, but add newlines between every value. Useful for # Merge multiple definitions by concatenating them (with the given
# configuration file contents. # separator between the values).
lines = mkOptionType { separatedString = sep: mkOptionType {
name = "string"; name = "string";
check = lib.traceValIfNot builtins.isString; check = builtins.isString;
merge = lib.concatStringsSep "\n"; merge = loc: defs: concatStringsSep sep (getValues defs);
}; };
envVar = mkOptionType { lines = separatedString "\n";
name = "environment variable"; commas = separatedString ",";
inherit (string) check; envVar = separatedString ":";
merge = lib.concatStringsSep ":";
}; # Deprecated; should not be used because it quietly concatenates
# strings, which is usually not what you want.
string = separatedString "";
attrs = mkOptionType { attrs = mkOptionType {
name = "attribute set"; name = "attribute set";
check = lib.traceValIfNot isAttrs; check = isAttrs;
merge = fold lib.mergeAttrs {}; merge = loc: fold (def: mergeAttrs def.value) {};
}; };
# derivation is a reserved keyword. # derivation is a reserved keyword.
package = mkOptionType { package = mkOptionType {
name = "derivation"; name = "derivation";
check = lib.traceValIfNot isDerivation; check = isDerivation;
merge = mergeOneOption;
}; };
path = mkOptionType { path = mkOptionType {
name = "path"; name = "path";
# Hacky: there is no isPath primop. # 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: # 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"; name = "list of ${elemType.name}s";
check = value: lib.traceValIfNot isList value && all elemType.check value; check = value: isList value && all elemType.check value;
merge = concatLists; merge = loc: defs:
iter = f: path: list: map (elemType.iter f (path + ".*")) list; concatLists (imap (n: def: imap (m: def':
fold = op: nul: list: lib.fold (e: l: elemType.fold op l e) nul list; elemType.merge (loc ++ ["[${toString n}-${toString m}]"])
docPath = path: elemType.docPath (path + ".*"); [{ inherit (def) file; value = def'; }]) def.value) defs);
inherit (elemType) hasOptions; getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["*"]);
# You cannot define multiple configurations of one entity, therefore
# no reason justify to delay properties inside list elements.
delayOnGlobalEval = false;
}; };
attrsOf = elemType: mkOptionType { attrsOf = elemType: mkOptionType {
name = "attribute set of ${elemType.name}s"; name = "attribute set of ${elemType.name}s";
check = x: lib.traceValIfNot isAttrs x check = x: isAttrs x && all elemType.check (attrValues x);
&& all elemType.check (lib.attrValues x); merge = loc: defs:
merge = lib.zipAttrsWith (name: elemType.merge); zipAttrsWith (name: elemType.merge (loc ++ [name]))
iter = f: path: set: lib.mapAttrs (name: elemType.iter f (path + "." + name)) set; # Push down position info.
fold = op: nul: set: fold (e: l: elemType.fold op l e) nul (lib.attrValues set); (map (def: listToAttrs (mapAttrsToList (n: def':
docPath = path: elemType.docPath (path + ".<name>"); { name = n; value = { inherit (def) file; value = def'; }; }) def.value)) defs);
inherit (elemType) hasOptions delayOnGlobalEval; getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name>"]);
}; };
# List or attribute set of ... # List or attribute set of ...
loaOf = elemType: loaOf = elemType:
let let
convertIfList = defIdx: def: convertIfList = defIdx: def:
if isList def then if isList def.value then
listToAttrs ( { inherit (def) file;
flip imap def (elemIdx: elem: value = listToAttrs (
nameValuePair "unnamed-${toString defIdx}.${toString elemIdx}" elem)) imap (elemIdx: elem:
{ name = "unnamed-${toString defIdx}.${toString elemIdx}";
value = elem;
}) def.value);
}
else else
def; def;
listOnly = listOf elemType; listOnly = listOf elemType;
attrOnly = attrsOf elemType; attrOnly = attrsOf elemType;
in mkOptionType { in mkOptionType {
name = "list or attribute set of ${elemType.name}s"; name = "list or attribute set of ${elemType.name}s";
check = x: check = x:
if isList x then listOnly.check x if isList x then listOnly.check x
else if isAttrs x then attrOnly.check x else if isAttrs x then attrOnly.check x
else lib.traceValIfNot (x: false) x; else false;
## The merge function returns an attribute set merge = loc: defs: attrOnly.merge loc (imap convertIfList defs);
merge = defs: getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name?>"]);
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;
}
;
uniq = elemType: mkOptionType { uniq = elemType: mkOptionType {
inherit (elemType) name check iter fold docPath hasOptions; inherit (elemType) name check;
merge = list: merge = mergeOneOption;
if length list == 1 then getSubOptions = elemType.getSubOptions;
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.";
}; };
nullOr = elemType: mkOptionType { nullOr = elemType: mkOptionType {
inherit (elemType) name merge docPath hasOptions; name = "null or ${elemType.name}";
check = x: builtins.isNull x || elemType.check x; check = x: builtins.isNull x || elemType.check x;
iter = f: path: v: if v == null then v else elemType.iter f path v; merge = loc: defs:
fold = op: nul: v: if v == null then nul else elemType.fold op nul v; 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 { functionTo = elemType: mkOptionType {
name = "function that evaluates to a(n) ${elemType.name}"; name = "function that evaluates to a(n) ${elemType.name}";
check = lib.traceValIfNot builtins.isFunction; check = builtins.isFunction;
merge = fns: merge = loc: defs:
args: elemType.merge (map (fn: fn args) fns); fnArgs: elemType.merge loc (map (fn: { inherit (fn) file; value = fn.value fnArgs; }) defs);
# These are guesses, I don't fully understand iter, fold, delayOnGlobalEval getSubOptions = elemType.getSubOptions;
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;
}; };
# usually used with listOf, attrsOf, loaOf like this: submodule = opts:
# users = mkOption { let
# type = loaOf optionSet; opts' = toList opts;
# inherit (import ./modules.nix) evalModules;
# # you can omit the list if there is one element only in
# options = [ { mkOptionType rec {
# name = mkOption { name = "submodule";
# description = "name of the user" check = x: isAttrs x || builtins.isFunction x;
# ... merge = loc: defs:
# }; let
# # more options here coerce = def: if builtins.isFunction def then def else { config = def; };
# } { more options } ]; modules = opts' ++ map (def: { _file = def.file; imports = [(coerce def.value)]; }) defs;
# } in (evalModules { inherit modules; args.name = last loc; prefix = loc; }).config;
# TODO: !!! document passing options as an argument to optionSet, getSubOptions = prefix: (evalModules
# deprecate the current approach. { 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 { optionSet = mkOptionType {
name = "option set"; name = /* builtins.trace "types.optionSet is deprecated; use types.submodule instead" */ "option set";
# merge is done in "options.nix > addOptionMakeUp > handleOptionSets"
merge = lib.id;
check = x: isAttrs x || builtins.isFunction x;
hasOptions = true;
delayOnGlobalEval = true;
}; };
# 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 ]; modules = [ configuration ];
}; };
inherit (eval) config pkgs; inherit (eval) pkgs;
# This is for `nixos-rebuild build-vm'. # This is for `nixos-rebuild build-vm'.
vmConfig = (import ./lib/eval-config.nix { vmConfig = (import ./lib/eval-config.nix {
@ -30,9 +30,9 @@ let
in in
{ {
inherit eval config; inherit (eval) config options;
system = config.system.build.toplevel; system = eval.config.system.build.toplevel;
vm = vmConfig.system.build.vm; vm = vmConfig.system.build.vm;

View File

@ -7,7 +7,7 @@
<para>This chapter describes how to configure various aspects of a <para>This chapter describes how to configure various aspects of a
NixOS machine through the configuration file NixOS machine through the configuration file
<filename>/etc/nixos/configuration.nix</filename>. As described in <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> 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> <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> </section>
@ -170,7 +866,7 @@ recursion.)</para>
</section> </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. <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 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 <para>NixOS supports both declarative and imperative styles of user
management. In the declarative style, users are specified in 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 xlink:href="https://nixos.org/wiki/Installing_NixOS_from_a_USB_stick">NixOS
Wiki</link>.</para> 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> </section>
@ -62,9 +89,14 @@ Wiki</link>.</para>
<listitem><para>For initialising Ext4 partitions: <listitem><para>For initialising Ext4 partitions:
<command>mkfs.ext4</command>. It is recommended that you assign a <command>mkfs.ext4</command>. It is recommended that you assign a
unique symbolic label to the file system using the option unique symbolic label to the file system using the option
<option>-L <replaceable>label</replaceable></option>. This will <option>-L <replaceable>label</replaceable></option>, since this
make the file system configuration independent from device makes the file system configuration independent from device
changes.</para></listitem> changes. For example:
<screen>
$ mkfs.ext4 -L nixos /dev/sda1</screen>
</para></listitem>
<listitem><para>For creating swap partitions: <listitem><para>For creating swap partitions:
<command>mkswap</command>. Again its recommended to assign a <command>mkswap</command>. Again its recommended to assign a
@ -97,6 +129,12 @@ $ mount /dev/disk/by-label/nixos /mnt
</para></listitem> </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> <listitem>
<para>You now need to create a file <para>You now need to create a file
@ -161,28 +199,16 @@ $ nano /mnt/etc/nixos/configuration.nix
</listitem> </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: <listitem><para>Do the installation:
<screen> <screen>
$ nixos-install</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: <listitem><para>If everything went well:
@ -194,7 +220,7 @@ $ reboot</screen>
<listitem> <listitem>
<para>You should now be able to boot into the installed NixOS. <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 configurations</emphasis> (initially just one). Every time you
change the NixOS configuration (see <xref change the NixOS configuration (see <xref
linkend="sec-changing-config" />), a new item appears in the menu. linkend="sec-changing-config" />), a new item appears in the menu.
@ -229,26 +255,28 @@ $ nix-env -i w3m</screen>
</orderedlist> </orderedlist>
<para><xref linkend="ex-install-sequence" /> shows a typical sequence <para>To summarise, <xref linkend="ex-install-sequence" /> shows a
of commands for installing NixOS on an empty hard drive (here typical sequence of commands for installing NixOS on an empty hard
<filename>/dev/sda</filename>). <xref linkend="ex-config" /> shows a drive (here <filename>/dev/sda</filename>). <xref linkend="ex-config"
corresponding configuration Nix expression.</para> /> shows a corresponding configuration Nix expression.</para>
<example xml:id='ex-install-sequence'><title>Commands for installing NixOS on <filename>/dev/sda</filename></title> <example xml:id='ex-install-sequence'><title>Commands for installing NixOS on <filename>/dev/sda</filename></title>
<screen> <screen>
$ fdisk /dev/sda <lineannotation>(or whatever device you want to install on)</lineannotation> $ fdisk /dev/sda # <lineannotation>(or whatever device you want to install on)</lineannotation>
$ mkfs.ext4 -L nixos /dev/sda1 <lineannotation>(idem)</lineannotation> $ mkfs.ext4 -L nixos /dev/sda1
$ mkswap -L swap /dev/sda2 <lineannotation>(idem)</lineannotation> $ mkswap -L swap /dev/sda2
$ mount LABEL=nixos /mnt $ swapon /dev/sda2
$ nixos-generate-config $ mount /dev/disk/by-label/nixos /mnt
$ nixos-generate-config --root /mnt
$ nano /mnt/etc/nixos/configuration.nix $ nano /mnt/etc/nixos/configuration.nix
<lineannotation>(in particular, set the fileSystems and swapDevices options)</lineannotation>
$ nixos-install $ nixos-install
$ reboot</screen> $ reboot</screen>
</example> </example>
<example xml:id='ex-config'><title>NixOS configuration</title> <example xml:id='ex-config'><title>NixOS configuration</title>
<screen> <screen>
{ config, pkgs, ... }:
{ {
imports = imports =
[ # Include the results of the hardware scan. [ # Include the results of the hardware scan.
@ -257,14 +285,12 @@ $ reboot</screen>
boot.loader.grub.device = "/dev/sda"; boot.loader.grub.device = "/dev/sda";
# Note: setting fileSystems and swapDevices is generally not # Note: setting fileSystems is generally not
# necessary, since nixos-generate-config has set them automatically # necessary, since nixos-generate-config figures them out
# in hardware-configuration.nix. # automatically in hardware-configuration.nix.
fileSystems."/".device = "/dev/disk/by-label/nixos"; #fileSystems."/".device = "/dev/disk/by-label/nixos";
swapDevices =
[ { device = "/dev/disk/by-label/swap"; } ];
# Enable the OpenSSH server.
services.sshd.enable = true; services.sshd.enable = true;
}</screen> }</screen>
</example> </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 booting, and try to realise the configuration in the running system
(e.g., by restarting system services).</para> (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 <para>You can also do
<screen> <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 switch to it now (so it will only take effect after the next
reboot).</para> 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 <para>Finally, you can do
<screen> <screen>
@ -319,7 +361,7 @@ whether everything compiles cleanly.</para>
<para>If you have a machine that supports hardware virtualisation, you <para>If you have a machine that supports hardware virtualisation, you
can also test the new configuration in a sandbox by building and 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 desired configuration. Just do
<screen> <screen>
@ -334,7 +376,6 @@ available.</para>
</section> </section>
<!--===============================================================--> <!--===============================================================-->
<section xml:id="sec-upgrading"> <section xml:id="sec-upgrading">
@ -342,28 +383,86 @@ available.</para>
<title>Upgrading NixOS</title> <title>Upgrading NixOS</title>
<para>The best way to keep your NixOS installation up to date is to <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 Nix mechanism for distributing Nix expressions and associated
binaries.) The NixOS channel is updated automatically from NixOSs binaries. The NixOS channels are updated automatically from NixOSs
Git repository after running certain tests and building most Git repository after certain tests have passed and all packages have
packages.</para> been built. These channels are:
<para>NixOS automatically subscribes you to the NixOS channel. If for <itemizedlist>
some reason this is not the case, just do <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> <screen>
$ nix-channel --add http://nixos.org/channels/nixos-unstable $ nix-channel --list | grep nixos
nixos https://nixos.org/channels/nixos-unstable
</screen> </screen>
You can then upgrade NixOS to the latest version in the channel by To switch to a different NixOS channel, do
running
<screen> <screen>
$ nix-channel --update nixos $ nix-channel --add http://nixos.org/channels/<replaceable>channel-name</replaceable> nixos
</screen> </screen>
and running the <command>nixos-rebuild</command> command as described (Be sure to include the <literal>nixos</literal> parameter at the
in <xref linkend="sec-changing-config"/>.</para> 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> </section>

View File

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

View File

@ -7,23 +7,20 @@
, baseModules ? import ../modules/module-list.nix , baseModules ? import ../modules/module-list.nix
, extraArgs ? {} , extraArgs ? {}
, modules , modules
, check ? true
}: }:
let extraArgs_ = extraArgs; pkgs_ = pkgs; system_ = system; in let extraArgs_ = extraArgs; pkgs_ = pkgs; system_ = system; in
rec { rec {
# These are the NixOS modules that constitute the system configuration.
configComponents = modules ++ baseModules;
# Merge the option definitions in all modules, forming the full # Merge the option definitions in all modules, forming the full
# system configuration. It's not checked for undeclared options. # system configuration.
systemModule = inherit (pkgs.lib.evalModules {
pkgs.lib.fixMergeModules configComponents extraArgs; modules = modules ++ baseModules;
args = extraArgs;
optionDefinitions = systemModule.config; check = check && options.environment.checkConfigurationOptions.value;
optionDeclarations = systemModule.options; }) config options;
inherit (systemModule) options;
# These are the extra arguments passed to every module. In # These are the extra arguments passed to every module. In
# particular, Nixpkgs is passed through the "pkgs" argument. # particular, Nixpkgs is passed through the "pkgs" argument.
@ -56,16 +53,12 @@ rec {
# define nixpkgs.config, so it's pointless to evaluate them. # define nixpkgs.config, so it's pointless to evaluate them.
baseModules = [ ../modules/misc/nixpkgs.nix ]; baseModules = [ ../modules/misc/nixpkgs.nix ];
pkgs = import ./nixpkgs.nix { system = system_; config = {}; }; pkgs = import ./nixpkgs.nix { system = system_; config = {}; };
}).optionDefinitions.nixpkgs; check = false;
}).config.nixpkgs;
in in
{ {
inherit system; inherit system;
inherit (nixpkgsOptions) config; 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 = { fonts = {
enableFontConfig = mkOption { # !!! should be enableFontconfig enableFontConfig = mkOption { # !!! should be enableFontconfig
type = types.bool;
default = true; default = true;
description = '' description = ''
If enabled, a Fontconfig configuration file will be built If enabled, a Fontconfig configuration file will be built

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -25,12 +25,17 @@ in
''; '';
type = types.attrsOf (mkOptionType { type = types.attrsOf (mkOptionType {
name = "a string or a list of strings"; name = "a string or a list of strings";
merge = xs: merge = loc: defs:
let xs' = evalProperties xs; in let
if isList (head xs') then concatLists xs' defs' = filterOverrides defs;
else if builtins.lessThan 1 (length xs') then abort "variable in environment.variables has multiple values" res = (head defs').value;
else if !builtins.isString (head xs') then abort "variable in environment.variables does not have a string value" in
else head xs'; 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); apply = mapAttrs (n: v: if isList v then concatStringsSep ":" v else v);
}; };

View File

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

View File

@ -7,7 +7,7 @@ let
sysctlOption = mkOptionType { sysctlOption = mkOptionType {
name = "sysctl option value"; name = "sysctl option value";
check = x: builtins.isBool x || builtins.isString x || builtins.isInt x; check = x: 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 in

View File

@ -14,7 +14,7 @@ let
''; '';
requiredPackages = requiredPackages =
[ config.environment.nix [ config.nix.package
pkgs.acl pkgs.acl
pkgs.attr pkgs.attr
pkgs.bashInteractive # bash with ncurses support pkgs.bashInteractive # bash with ncurses support
@ -60,6 +60,7 @@ in
environment = { environment = {
systemPackages = mkOption { systemPackages = mkOption {
type = types.listOf types.path;
default = []; default = [];
example = "[ pkgs.icecat3 pkgs.thunderbird ]"; example = "[ pkgs.icecat3 pkgs.thunderbird ]";
description = '' description = ''
@ -74,6 +75,7 @@ in
}; };
pathsToLink = mkOption { pathsToLink = mkOption {
type = types.listOf types.str;
# Note: We need `/lib' to be among `pathsToLink' for NSS modules # Note: We need `/lib' to be among `pathsToLink' for NSS modules
# to work. # to work.
default = []; default = [];
@ -122,7 +124,7 @@ in
postBuild = postBuild =
'' ''
if [ -x $out/bin/update-mime-database -a -w $out/share/mime/packages ]; then 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 fi
if [ -x $out/bin/gtk-update-icon-cache -a -f $out/share/icons/hicolor/index.theme ]; then 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 { timeZone = mkOption {
default = "CET"; default = "CET";
type = with types; uniq string; type = types.str;
example = "America/New_York"; example = "America/New_York";
description = "The time zone used when displaying times and dates."; description = "The time zone used when displaying times and dates.";
}; };

View File

@ -12,14 +12,19 @@ let
options = { options = {
name = mkOption { 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 = "The name of the user account. If undefined, the name of the attribute set will be used.";
}; };
description = mkOption { description = mkOption {
type = with types; uniq string; type = types.str;
default = ""; 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 { uid = mkOption {
@ -29,25 +34,25 @@ let
}; };
group = mkOption { group = mkOption {
type = with types; uniq string; type = types.str;
default = "nogroup"; default = "nogroup";
description = "The user's primary group."; description = "The user's primary group.";
}; };
extraGroups = mkOption { extraGroups = mkOption {
type = types.listOf types.string; type = types.listOf types.str;
default = []; default = [];
description = "The user's auxiliary groups."; description = "The user's auxiliary groups.";
}; };
home = mkOption { home = mkOption {
type = with types; uniq string; type = types.str;
default = "/var/empty"; default = "/var/empty";
description = "The user's home directory."; description = "The user's home directory.";
}; };
shell = mkOption { shell = mkOption {
type = with types; uniq string; type = types.str;
default = "/run/current-system/sw/sbin/nologin"; default = "/run/current-system/sw/sbin/nologin";
description = "The path to the user's shell."; description = "The path to the user's shell.";
}; };
@ -65,9 +70,15 @@ let
}; };
password = mkOption { password = mkOption {
type = with types; uniq (nullOr string); type = with types; uniq (nullOr str);
default = null; 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 { isSystemUser = mkOption {
@ -79,11 +90,11 @@ let
createUser = mkOption { createUser = mkOption {
type = types.bool; type = types.bool;
default = true; default = true;
description = " description = ''
Indicates if the user should be created automatically as a local user. 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 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. then not modify any of the basic properties for the user account.
"; '';
}; };
isAlias = mkOption { isAlias = mkOption {
@ -107,7 +118,7 @@ let
options = { options = {
name = mkOption { 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."; description = "The name of the group. If undefined, the name of the attribute set will be used.";
}; };
@ -149,13 +160,12 @@ in
example = { example = {
alice = { alice = {
uid = 1234; uid = 1234;
description = "Alice"; description = "Alice Q. User";
home = "/home/alice"; home = "/home/alice";
createHome = true; createHome = true;
group = "users"; group = "users";
extraGroups = ["wheel"]; extraGroups = ["wheel"];
shell = "/bin/sh"; shell = "/bin/sh";
password = "foobar";
}; };
}; };
description = '' description = ''

View File

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

View File

@ -18,16 +18,16 @@ in
hardware.pcmcia = { hardware.pcmcia = {
enable = mkOption { enable = mkOption {
type = types.bool;
default = false; default = false;
merge = mergeEnableOption;
description = '' description = ''
Enable this option to support PCMCIA card. Enable this option to support PCMCIA card.
''; '';
}; };
firmware = mkOption { firmware = mkOption {
type = types.listOf types.path;
default = []; default = [];
merge = mergeListOption;
description = '' description = ''
List of firmware used to handle specific PCMCIA card. List of firmware used to handle specific PCMCIA card.
''; '';
@ -36,7 +36,7 @@ in
config = mkOption { config = mkOption {
default = null; default = null;
description = '' 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. and ports used by the PCMCIA hardware.
''; '';
}; };

View File

@ -33,7 +33,7 @@ in
if ! [ -e /var/lib/nixos/did-channel-init ]; then if ! [ -e /var/lib/nixos/did-channel-init ]; then
echo "unpacking the NixOS/Nixpkgs sources..." echo "unpacking the NixOS/Nixpkgs sources..."
mkdir -p /nix/var/nix/profiles/per-user/root 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 -i ${channelSources} --quiet --option use-substitutes false
mkdir -m 0700 -p /root/.nix-defexpr mkdir -m 0700 -p /root/.nix-defexpr
ln -s /nix/var/nix/profiles/per-user/root/channels /root/.nix-defexpr/channels 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 # After booting, register the contents of the Nix store on the
# CD in the Nix database in the tmpfs. # 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 # nixos-rebuild also requires a "system" profile and an
# /etc/NIXOS tag. # /etc/NIXOS tag.
touch /etc/NIXOS 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 # 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. # default root password is empty.
services.openssh.enable = true; 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.grub.enable = false;
boot.loader.generationsDir.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 # not be started by default on the installation CD because the
# default root password is empty. # default root password is empty.
services.openssh.enable = true; 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. # To be able to use the systemTarball to catch troubles.
boot.crashDump = { boot.crashDump = {

View File

@ -165,7 +165,7 @@ in
# not be started by default on the installation CD because the # not be started by default on the installation CD because the
# default root password is empty. # default root password is empty.
services.openssh.enable = true; 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 # cpufrequtils fails to build on non-pc
powerManagement.enable = false; powerManagement.enable = false;

View File

@ -77,14 +77,14 @@ in
# After booting, register the contents of the Nix store on the # After booting, register the contents of the Nix store on the
# CD in the Nix database in the tmpfs. # CD in the Nix database in the tmpfs.
if [ -f /nix-path-registration ]; then 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 rm /nix-path-registration
fi fi
# nixos-rebuild also requires a "system" profile and an # nixos-rebuild also requires a "system" profile and an
# /etc/NIXOS tag. # /etc/NIXOS tag.
touch /etc/NIXOS 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 #! @shell@ -e
# FIXME: rewrite this in a more suitable language.
usage () { usage () {
exec man nixos-option exec man nixos-option
exit 1 exit 1
@ -90,24 +92,25 @@ evalNix(){
} }
evalAttr(){ evalAttr(){
local prefix=$1 local prefix="$1"
local suffix=$2 local strict="$2"
local strict=$3 local suffix="$3"
echo "(import <nixos> {}).$prefix${option:+.$option}${suffix:+.$suffix}" | echo "(import <nixos> {}).$prefix${option:+.$option}${suffix:+.$suffix}" |
evalNix ${strict:+--strict} evalNix ${strict:+--strict}
} }
evalOpt(){ evalOpt(){
evalAttr "eval.options" "$@" evalAttr "options" "" "$@"
} }
evalCfg(){ evalCfg(){
evalAttr "config" "$@" local strict="$1"
evalAttr "config" "$strict"
} }
findSources(){ findSources(){
local suffix=$1 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 evalNix --strict
} }
@ -143,7 +146,7 @@ let
nixos = import <nixos> {}; nixos = import <nixos> {};
nixpkgs = import <nixpkgs> {}; nixpkgs = import <nixpkgs> {};
sources = builtins.map (f: f.source); sources = builtins.map (f: f.source);
opt = reach nixos.eval.options; opt = reach nixos.options;
cfg = reach nixos.config; cfg = reach nixos.config;
in in
@ -186,7 +189,7 @@ EOF
fi fi
if test "$(evalOpt "_type" 2> /dev/null)" = '"option"'; then if test "$(evalOpt "_type" 2> /dev/null)" = '"option"'; then
$value && evalCfg; $value && evalCfg 1
if $desc; then if $desc; then
$value && echo; $value && echo;
@ -212,14 +215,14 @@ if test "$(evalOpt "_type" 2> /dev/null)" = '"option"'; then
nixMap printPath "$(findSources "declarations")" nixMap printPath "$(findSources "declarations")"
echo "" echo ""
echo "Defined by:" echo "Defined by:"
nixMap printPath "$(findSources "definitions")" nixMap printPath "$(findSources "files")"
echo "" echo ""
fi fi
else else
# echo 1>&2 "Warning: This value is not an option." # echo 1>&2 "Warning: This value is not an option."
result=$(evalCfg) result=$(evalCfg "")
if names=$(attrNames "$result" 2> /dev/null); then if names=$(attrNames "$result" 2> /dev/null); then
echo 1>&2 "This attribute set contains:" echo 1>&2 "This attribute set contains:"
escapeQuotes () { eval echo "$1"; } escapeQuotes () { eval echo "$1"; }

View File

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

View File

@ -22,10 +22,10 @@ let
src = ./nixos-install.sh; src = ./nixos-install.sh;
inherit (pkgs) perl pathsFromGraph; inherit (pkgs) perl pathsFromGraph;
nix = config.environment.nix; nix = config.nix.package;
nixClosure = pkgs.runCommand "closure" nixClosure = pkgs.runCommand "closure"
{ exportReferencesGraph = ["refs" config.environment.nix]; } { exportReferencesGraph = ["refs" config.nix.package]; }
"cp refs $out"; "cp refs $out";
}; };
@ -52,6 +52,7 @@ let
inherit (config.system) nixosVersion nixosCodeName; inherit (config.system) nixosVersion nixosCodeName;
}; };
/*
nixos-gui = pkgs.xulrunnerWrapper { nixos-gui = pkgs.xulrunnerWrapper {
launcher = "nixos-gui"; launcher = "nixos-gui";
application = pkgs.stdenv.mkDerivation { application = pkgs.stdenv.mkDerivation {
@ -71,10 +72,12 @@ let
}; };
}; };
}; };
*/
in in
{ {
/*
options = { options = {
installer.enableGraphicalTools = pkgs.lib.mkOption { installer.enableGraphicalTools = pkgs.lib.mkOption {
@ -87,6 +90,7 @@ in
}; };
}; };
*/
config = { config = {
environment.systemPackages = environment.systemPackages =
@ -96,10 +100,10 @@ in
nixos-generate-config nixos-generate-config
nixos-option nixos-option
nixos-version nixos-version
] ++ pkgs.lib.optional cfg.enableGraphicalTools nixos-gui; ];
system.build = { 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 = { options = {
assertions = mkOption { assertions = mkOption {
type = types.listOf types.unspecified;
internal = true; internal = true;
default = []; default = [];
example = [ { assertion = false; message = "you can't enable this for that reason"; } ]; example = [ { assertion = false; message = "you can't enable this for that reason"; } ];
merge = pkgs.lib.mergeListOption;
description = '' description = ''
This option allows modules to express conditions that must This option allows modules to express conditions that must
hold for the evaluation of the system configuration to hold for the evaluation of the system configuration to

View File

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

View File

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

View File

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

View File

@ -17,8 +17,8 @@ in
services.locate = { services.locate = {
enable = mkOption { enable = mkOption {
type = types.bool;
default = false; default = false;
example = true;
description = '' description = ''
If enabled, NixOS will periodically update the database of If enabled, NixOS will periodically update the database of
files used by the <command>locate</command> command. files used by the <command>locate</command> command.
@ -26,11 +26,12 @@ in
}; };
period = mkOption { period = mkOption {
type = types.str;
default = "15 02 * * *"; default = "15 02 * * *";
description = '' description = ''
This option defines (in the format used by cron) when the This option defines (in the format used by cron) when the
locate database is updated. 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 { configType = mkOptionType {
name = "nixpkgs config"; name = "nixpkgs config";
check = traceValIfNot isConfig; check = traceValIfNot isConfig;
merge = fold mergeConfig {}; merge = args: fold (def: mergeConfig def.value) {};
}; };
in in
@ -59,7 +59,7 @@ in
}; };
nixpkgs.system = mkOption { nixpkgs.system = mkOption {
default = pkgs.stdenv.system; type = types.str;
description = '' description = ''
Specifies the Nix platform type for which NixOS should be built. Specifies the Nix platform type for which NixOS should be built.
If unset, it defaults to the platform type of your host system 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 = { options = {
passthru = pkgs.lib.mkOption { passthru = pkgs.lib.mkOption {
visible = false;
description = '' description = ''
This attribute set will be exported as a system attribute. This attribute set will be exported as a system attribute.
You can put whatever you want here. You can put whatever you want here.

View File

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

View File

@ -150,12 +150,12 @@
./services/networking/cntlm.nix ./services/networking/cntlm.nix
./services/networking/chrony.nix ./services/networking/chrony.nix
./services/networking/ddclient.nix ./services/networking/ddclient.nix
#./services/networking/dhclient.nix
./services/networking/dhcpcd.nix ./services/networking/dhcpcd.nix
./services/networking/dhcpd.nix ./services/networking/dhcpd.nix
./services/networking/dnsmasq.nix ./services/networking/dnsmasq.nix
./services/networking/ejabberd.nix ./services/networking/ejabberd.nix
./services/networking/firewall.nix ./services/networking/firewall.nix
./services/networking/haproxy.nix
./services/networking/tcpcrypt.nix ./services/networking/tcpcrypt.nix
./services/networking/flashpolicyd.nix ./services/networking/flashpolicyd.nix
./services/networking/freenet.nix ./services/networking/freenet.nix
@ -276,7 +276,7 @@
./tasks/scsi-link-power-management.nix ./tasks/scsi-link-power-management.nix
./tasks/swraid.nix ./tasks/swraid.nix
./virtualisation/libvirtd.nix ./virtualisation/libvirtd.nix
./virtualisation/nova.nix #./virtualisation/nova.nix
./virtualisation/virtualbox-guest.nix ./virtualisation/virtualbox-guest.nix
./virtualisation/xen-dom0.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 # cannot serialized attribute set given in the list of modules (that's why
# you should use files). # you should use files).
moduleFiles = 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 # Partition module files because between NixOS and non-NixOS files. NixOS
# files may change if the repository is updated. # files may change if the repository is updated.

View File

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

View File

@ -16,6 +16,7 @@ in
programs.ssh = { programs.ssh = {
forwardX11 = mkOption { forwardX11 = mkOption {
type = types.bool;
default = false; default = false;
description = '' description = ''
Whether to request X11 forwarding on outgoing connections by default. Whether to request X11 forwarding on outgoing connections by default.
@ -29,18 +30,21 @@ in
}; };
setXAuthLocation = mkOption { setXAuthLocation = mkOption {
type = types.bool;
default = true; default = true;
description = '' description = ''
Whether to set the path to <command>xauth</command> for X11-forwarded connections. 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 { extraConfig = mkOption {
type = types.lines;
default = ""; default = "";
description = '' description = ''
Extra configuration text appended to <filename>ssh_config</filename>. 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: zipAttrsWith (n: v:
if tail v != [] then if tail v != [] then
if n == "_type" then (head v) if n == "_type" then (head v)
else if n == "extraConfigs" then concatLists v
else if n == "warnings" then concatLists v else if n == "warnings" then concatLists v
else if n == "description" || n == "apply" then else if n == "description" || n == "apply" then
abort "Cannot rename an option to multiple options." abort "Cannot rename an option to multiple options."
@ -55,12 +54,7 @@ let
inherit visible; inherit visible;
}); });
} }
{ options = setTo (mkOption { { config = setTo (mkIf (fromOf options).isDefined (define (mkMerge (fromOf options).definitions)));
extraConfigs =
let externalDefs = (fromOf options).definitions; in
if externalDefs == [] then []
else map (def: def.value) (define externalDefs);
});
} }
]; ];
@ -75,10 +69,9 @@ let
in zipModules ([] in zipModules ([]
# usage example: ++ obsolete [ "environment" "x11Packages" ] [ "environment" "systemPackages" ]
# ++ alias [ "services" "xserver" "slim" "theme" ] [ "services" "xserver" "displayManager" "slim" "theme" ]
++ obsolete [ "environment" "extraPackages" ] [ "environment" "systemPackages" ]
++ obsolete [ "environment" "enableBashCompletion" ] [ "programs" "bash" "enableCompletion" ] ++ obsolete [ "environment" "enableBashCompletion" ] [ "programs" "bash" "enableCompletion" ]
++ obsolete [ "environment" "nix" ] [ "nix" "package" ]
++ obsolete [ "security" "extraSetuidPrograms" ] [ "security" "setuidPrograms" ] ++ obsolete [ "security" "extraSetuidPrograms" ] [ "security" "setuidPrograms" ]
++ obsolete [ "networking" "enableWLAN" ] [ "networking" "wireless" "enable" ] ++ obsolete [ "networking" "enableWLAN" ] [ "networking" "wireless" "enable" ]
@ -98,6 +91,7 @@ in zipModules ([]
++ obsolete [ "boot" "grubSplashImage" ] [ "boot" "loader" "grub" "splashImage" ] ++ obsolete [ "boot" "grubSplashImage" ] [ "boot" "loader" "grub" "splashImage" ]
++ obsolete [ "boot" "initrd" "extraKernelModules" ] [ "boot" "initrd" "kernelModules" ] ++ obsolete [ "boot" "initrd" "extraKernelModules" ] [ "boot" "initrd" "kernelModules" ]
++ obsolete [ "boot" "extraKernelParams" ] [ "boot" "kernelParams" ]
# OpenSSH # OpenSSH
++ obsolete [ "services" "sshd" "ports" ] [ "services" "openssh" "ports" ] ++ obsolete [ "services" "sshd" "ports" ] [ "services" "openssh" "ports" ]

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -20,14 +20,15 @@ in
sound = { sound = {
enable = mkOption { enable = mkOption {
type = types.bool;
default = true; default = true;
description = '' description = ''
Whether to enable ALSA sound. Whether to enable ALSA sound.
''; '';
merge = mergeEnableOption;
}; };
enableOSSEmulation = mkOption { enableOSSEmulation = mkOption {
type = types.bool;
default = true; default = true;
description = '' description = ''
Whether to enable ALSA OSS emulation (with certain cards sound mixing may not work!). 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 { name = mkOption {
example = "Media Center"; example = "Media Center";
type = with types; uniq string; type = types.str;
description = '' description = ''
Enables Fuppes (UPnP A/V Media Server). Can be used to watch 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 photos, video and listen to music from a phone/tv connected to the
@ -41,7 +41,7 @@ with pkgs.lib;
file = mkOption { file = mkOption {
default = "/var/log/fuppes.log"; default = "/var/log/fuppes.log";
type = with types; uniq string; type = types.str;
description = '' description = ''
File which will contains the log produced by the daemon. File which will contains the log produced by the daemon.
''; '';
@ -50,7 +50,7 @@ with pkgs.lib;
config = mkOption { config = mkOption {
example = "/etc/fuppes/fuppes.cfg"; example = "/etc/fuppes/fuppes.cfg";
type = with types; uniq string; type = types.str;
description = '' description = ''
Mutable configuration file which can be edited with the web Mutable configuration file which can be edited with the web
interface. Due to possible modification, double quote the full interface. Due to possible modification, double quote the full
@ -69,7 +69,7 @@ with pkgs.lib;
database = mkOption { database = mkOption {
default = "/var/lib/fuppes/fuppes.db"; default = "/var/lib/fuppes/fuppes.db";
type = with types; uniq string; type = types.str;
description = '' description = ''
Database file which index all shared files. Database file which index all shared files.
''; '';
@ -88,7 +88,7 @@ with pkgs.lib;
user = mkOption { user = mkOption {
default = "root"; # The default is not secure. default = "root"; # The default is not secure.
example = "fuppes"; example = "fuppes";
type = with types; uniq string; type = types.str;
description = '' description = ''
Name of the user which own the configuration files and under which Name of the user which own the configuration files and under which
the fuppes daemon will be executed. the fuppes daemon will be executed.

View File

@ -24,12 +24,12 @@ with pkgs.lib;
}; };
listenAddress = mkOption { listenAddress = mkOption {
default = null; default = null;
description = "IP address to listen on."; description = "IP address to listen on.";
}; };
port = mkOption { port = mkOption {
default = 8080; default = 8080;
description = "port to listen on."; description = "port to listen on.";
}; };
@ -45,9 +45,12 @@ with pkgs.lib;
###### implementation ###### implementation
config = mkIf cfg.enable ( config = mkIf cfg.enable {
mkAssert (cfg.enable -> cfg.database != "")
"Must specify database name" { assertions = singleton
{ assertion = cfg.enable -> cfg.database != "";
message = "Must specify 4Store database name";
};
users.extraUsers = singleton users.extraUsers = singleton
{ name = endpointUser; { name = endpointUser;
@ -63,10 +66,10 @@ with pkgs.lib;
startOn = "filesystem"; startOn = "filesystem";
exec = '' 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 ###### implementation
config = mkIf cfg.enable ( config = mkIf cfg.enable {
mkAssert (cfg.enable -> cfg.database != "")
"Must specify database name" { assertions = singleton
{ assertion = cfg.enable -> cfg.database != "";
message = "Must specify 4Store database name.";
};
users.extraUsers = singleton users.extraUsers = singleton
{ name = fourStoreUser; { name = fourStoreUser;
@ -56,16 +59,16 @@ with pkgs.lib;
preStart = '' preStart = ''
mkdir -p ${stateDir}/ mkdir -p ${stateDir}/
chown ${fourStoreUser} ${stateDir} chown ${fourStoreUser} ${stateDir}
if ! test -e "${stateDir}/${cfg.database}"; then if ! test -e "${stateDir}/${cfg.database}"; then
${run} -c '${pkgs.rdf4store}/bin/4s-backend-setup ${cfg.database}' ${run} -c '${pkgs.rdf4store}/bin/4s-backend-setup ${cfg.database}'
fi fi
''; '';
exec = '' 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 = { services.postgresql = {
enable = mkOption { enable = mkOption {
type = types.bool;
default = false; default = false;
description = '' description = ''
Whether to run PostgreSQL. Whether to run PostgreSQL.
@ -53,6 +54,7 @@ in
}; };
package = mkOption { package = mkOption {
type = types.path;
example = literalExample "pkgs.postgresql92"; example = literalExample "pkgs.postgresql92";
description = '' description = ''
PostgreSQL package to use. PostgreSQL package to use.
@ -60,6 +62,7 @@ in
}; };
port = mkOption { port = mkOption {
type = types.int;
default = "5432"; default = "5432";
description = '' description = ''
Port for PostgreSQL. Port for PostgreSQL.
@ -67,6 +70,7 @@ in
}; };
dataDir = mkOption { dataDir = mkOption {
type = types.path;
default = "/var/db/postgresql"; default = "/var/db/postgresql";
description = '' description = ''
Data directory for PostgreSQL. Data directory for PostgreSQL.
@ -74,6 +78,7 @@ in
}; };
authentication = mkOption { authentication = mkOption {
type = types.lines;
default = ""; default = "";
description = '' description = ''
Defines how users authenticate themselves to the server. Defines how users authenticate themselves to the server.
@ -81,6 +86,7 @@ in
}; };
identMap = mkOption { identMap = mkOption {
type = types.lines;
default = ""; default = "";
description = '' description = ''
Defines the mapping from system users to database users. Defines the mapping from system users to database users.
@ -88,14 +94,15 @@ in
}; };
initialScript = mkOption { initialScript = mkOption {
default = null;
type = types.nullOr types.path; type = types.nullOr types.path;
default = null;
description = '' description = ''
A file containing SQL statements to execute on first startup. A file containing SQL statements to execute on first startup.
''; '';
}; };
enableTCPIP = mkOption { enableTCPIP = mkOption {
type = types.bool;
default = false; default = false;
description = '' description = ''
Whether to run PostgreSQL with -i flag to enable TCP/IP connections. Whether to run PostgreSQL with -i flag to enable TCP/IP connections.
@ -103,8 +110,9 @@ in
}; };
extraPlugins = mkOption { extraPlugins = mkOption {
type = types.listOf types.path;
default = []; default = [];
example = "pkgs.postgis"; # of course don't use a string here! example = literalExample "pkgs.postgis";
description = '' description = ''
When this list contains elements a new store path is created. When this list contains elements a new store path is created.
PostgreSQL and the elments are symlinked into it. Then pg_config, PostgreSQL and the elments are symlinked into it. Then pg_config,
@ -118,15 +126,16 @@ in
}; };
extraConfig = mkOption { extraConfig = mkOption {
type = types.lines;
default = ""; default = "";
description = "Additional text to be appended to <filename>postgresql.conf</filename>."; description = "Additional text to be appended to <filename>postgresql.conf</filename>.";
}; };
recoveryConfig = mkOption { recoveryConfig = mkOption {
type = types.nullOr types.lines;
default = null; default = null;
type = types.nullOr types.string;
description = '' 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} ${condOption "unixsocket" cfg.unixSocket}
loglevel ${cfg.logLevel} loglevel ${cfg.logLevel}
logfile ${cfg.logfile} logfile ${cfg.logfile}
syslog-enabled ${redisBool cfg.syslog}
databases ${toString cfg.databases} databases ${toString cfg.databases}
${concatMapStrings (d: "save ${toString (builtins.elemAt d 0)} ${toString (builtins.elemAt d 1)}\n") cfg.save} ${concatMapStrings (d: "save ${toString (builtins.elemAt d 0)} ${toString (builtins.elemAt d 1)}\n") cfg.save}
dbfilename ${cfg.dbFilename} dbfilename ${cfg.dbFilename}
@ -82,12 +83,18 @@ in
}; };
logfile = mkOption { 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."; 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"; example = "/var/log/redis.log";
type = with types; string; type = with types; string;
}; };
syslog = mkOption {
default = true;
description = "Enable logging to the system logger.";
type = with types; bool;
};
databases = mkOption { databases = mkOption {
default = 16; default = 16;
description = "Set the number of databases."; description = "Set the number of databases.";
@ -177,8 +184,9 @@ in
config = mkIf config.services.redis.enable { config = mkIf config.services.redis.enable {
users.extraUsers = singleton users.extraUsers.redis =
{ name = cfg.user; { name = cfg.user;
uid = config.ids.uids.redis;
description = "Redis database user"; description = "Redis database user";
}; };

View File

@ -21,7 +21,8 @@ in
language = mkOption { language = mkOption {
default = "English"; 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."; description = "The language of bot messages: English, Spanish, Russian, Serbian or Turkish.";
}; };

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -52,7 +52,7 @@ let
levelOption = mkOption { levelOption = mkOption {
default = "server"; default = "server";
type = types.uniq types.string; type = types.str;
description = '' description = ''
Set the logcheck level. Either "workstation", "server", or "paranoid". Set the logcheck level. Either "workstation", "server", or "paranoid".
''; '';
@ -63,7 +63,7 @@ let
regex = mkOption { regex = mkOption {
default = ""; default = "";
type = types.uniq types.string; type = types.str;
description = '' description = ''
Regex specifying which log lines to ignore. Regex specifying which log lines to ignore.
''; '';
@ -73,7 +73,7 @@ let
ignoreCronOptions = { ignoreCronOptions = {
user = mkOption { user = mkOption {
default = "root"; default = "root";
type = types.uniq types.string; type = types.str;
description = '' description = ''
User that runs the cronjob. User that runs the cronjob.
''; '';
@ -81,7 +81,7 @@ let
cmdline = mkOption { cmdline = mkOption {
default = ""; default = "";
type = types.uniq types.string; type = types.str;
description = '' description = ''
Command line for the cron job. Will be turned into a regex for the logcheck ignore rule. Command line for the cron job. Will be turned into a regex for the logcheck ignore rule.
''; '';
@ -89,7 +89,7 @@ let
timeArgs = mkOption { timeArgs = mkOption {
default = null; default = null;
type = types.nullOr (types.uniq types.string); type = types.nullOr (types.str);
example = "02 06 * * *"; example = "02 06 * * *";
description = '' description = ''
"min hr dom mon dow" crontab time args, to auto-create a cronjob too. "min hr dom mon dow" crontab time args, to auto-create a cronjob too.
@ -112,7 +112,7 @@ in
user = mkOption { user = mkOption {
default = "logcheck"; default = "logcheck";
type = types.uniq types.string; type = types.str;
description = '' description = ''
Username for the logcheck user. Username for the logcheck user.
''; '';
@ -121,7 +121,7 @@ in
timeOfDay = mkOption { timeOfDay = mkOption {
default = "*"; default = "*";
example = "6"; example = "6";
type = types.uniq types.string; type = types.str;
description = '' description = ''
Time of day to run logcheck. A logcheck will be scheduled at xx:02 each day. 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, Leave default (*) to run every hour. Of course when nothing special was logged,
@ -132,7 +132,7 @@ in
mailTo = mkOption { mailTo = mkOption {
default = "root"; default = "root";
example = "you@domain.com"; example = "you@domain.com";
type = types.uniq types.string; type = types.str;
description = '' description = ''
Email address to send reports to. Email address to send reports to.
''; '';
@ -140,7 +140,7 @@ in
level = mkOption { level = mkOption {
default = "server"; default = "server";
type = types.uniq types.string; type = types.str;
description = '' description = ''
Set the logcheck level. Either "workstation", "server", or "paranoid". 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 mkHash functions, which take a string representation of a float and an
attrset, respectively. attrset, respectively.
''; '';
merge = mergeConfigs; apply = mergeConfigs;
}; };
filterConfig = mkOption { filterConfig = mkOption {
@ -109,7 +109,7 @@ in
representing a logstash configuration's filter section. representing a logstash configuration's filter section.
See inputConfig description for details. See inputConfig description for details.
''; '';
merge = mergeConfigs; apply = mergeConfigs;
}; };
outputConfig = mkOption { outputConfig = mkOption {
@ -119,7 +119,7 @@ in
representing a logstash configuration's output section. representing a logstash configuration's output section.
See inputConfig description for details. See inputConfig description for details.
''; '';
merge = mergeConfigs; apply = mergeConfigs;
}; };
}; };
}; };

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,7 @@ let
dataDir = "/var/db/graphite"; dataDir = "/var/db/graphite";
carbonOpts = name: with config.ids; '' 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} --uid ${toString uids.graphite} --gid ${toString uids.graphite} ${name}
''; '';
carbonEnv = { carbonEnv = {
@ -32,13 +32,13 @@ in {
host = mkOption { host = mkOption {
description = "Graphite web frontend listen address"; description = "Graphite web frontend listen address";
default = "127.0.0.1"; default = "127.0.0.1";
types = type.uniq types.string; type = types.str;
}; };
port = mkOption { port = mkOption {
description = "Graphite web frontend port"; description = "Graphite web frontend port";
default = "8080"; default = "8080";
types = type.uniq types.string; type = types.str;
}; };
}; };
@ -52,8 +52,11 @@ in {
PICKLE_RECEIVER_INTERFACE = 127.0.0.1 PICKLE_RECEIVER_INTERFACE = 127.0.0.1
LINE_RECEIVER_INTERFACE = 127.0.0.1 LINE_RECEIVER_INTERFACE = 127.0.0.1
CACHE_QUERY_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 { enableCache = mkOption {

View File

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

View File

@ -36,7 +36,7 @@ in
host = mkOption { host = mkOption {
description = "Address that statsd listens on over UDP"; description = "Address that statsd listens on over UDP";
default = "127.0.0.1"; default = "127.0.0.1";
type = types.uniq types.string; type = types.str;
}; };
port = mkOption { port = mkOption {
@ -48,7 +48,7 @@ in
mgmt_address = mkOption { mgmt_address = mkOption {
description = "Address to run managment TCP interface on"; description = "Address to run managment TCP interface on";
default = "127.0.0.1"; default = "127.0.0.1";
type = types.uniq types.string; type = types.str;
}; };
mgmt_port = mkOption { mgmt_port = mkOption {
@ -65,7 +65,7 @@ in
graphiteHost = mkOption { graphiteHost = mkOption {
description = "Hostname or IP of Graphite server"; description = "Hostname or IP of Graphite server";
default = "127.0.0.1"; default = "127.0.0.1";
type = types.uniq types.string; type = types.str;
}; };
graphitePort = mkOption { graphitePort = mkOption {
@ -77,7 +77,7 @@ in
extraConfig = mkOption { extraConfig = mkOption {
default = ""; default = "";
description = "Extra configuration options for statsd"; 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 # This can be infered from the UPS model by looking at
# /nix/store/nut/share/driver.list # /nix/store/nut/share/driver.list
driver = mkOption { driver = mkOption {
type = types.uniq types.string; type = types.str;
description = '' description = ''
Specify the program to run to talk to this UPS. apcsmart, Specify the program to run to talk to this UPS. apcsmart,
bestups, and sec are some examples. bestups, and sec are some examples.
@ -23,7 +23,7 @@ let
}; };
port = mkOption { port = mkOption {
type = types.uniq types.string; type = types.str;
description = '' description = ''
The serial port to which your UPS is connected. /dev/ttyS0 is The serial port to which your UPS is connected. /dev/ttyS0 is
usually the first port on Linux boxes, for example. usually the first port on Linux boxes, for example.
@ -115,7 +115,7 @@ in
# This option is not used yet. # This option is not used yet.
mode = mkOption { mode = mkOption {
default = "standalone"; default = "standalone";
type = types.uniq types.string; type = types.str;
description = '' description = ''
The MODE determines which part of the NUT is to be started, and The MODE determines which part of the NUT is to be started, and
which configuration files must be modified. which configuration files must be modified.
@ -142,7 +142,7 @@ in
schedulerRules = mkOption { schedulerRules = mkOption {
example = "/etc/nixos/upssched.conf"; example = "/etc/nixos/upssched.conf";
type = types.uniq types.string; type = types.str;
description = '' description = ''
File which contains the rules to handle UPS events. File which contains the rules to handle UPS events.
''; '';

View File

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

View File

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

View File

@ -39,7 +39,7 @@ in
}; };
netbios_hostname = mkOption { netbios_hostname = mkOption {
type = types.uniq types.string; type = types.str;
description = '' description = ''
The hostname of your machine. 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; 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. # interfaces that are part of a bridge.
ignoredInterfaces = ignoredInterfaces =
map (i: i.name) (filter (i: i.ipAddress != null) (attrValues config.networking.interfaces)) map (i: i.name) (filter (i: i.ipAddress != null) (attrValues config.networking.interfaces))

View File

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

View File

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

View File

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

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

View File

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