forked from mirrors/nixpkgs
Merge branch 'master' into stdenv-updates
Conflicts: pkgs/top-level/all-packages.nix
This commit is contained in:
commit
609f8dc04b
|
@ -29,9 +29,8 @@ rec {
|
|||
["x" "y"] applied with some value v returns `x.y = v;' */
|
||||
setAttrByPath = attrPath: value:
|
||||
if attrPath == [] then value
|
||||
else listToAttrs [(
|
||||
nameValuePair (head attrPath) (setAttrByPath (tail attrPath) value)
|
||||
)];
|
||||
else listToAttrs
|
||||
[ { name = head attrPath; value = setAttrByPath (tail attrPath) value; } ];
|
||||
|
||||
|
||||
getAttrFromPath = attrPath: set:
|
||||
|
@ -133,7 +132,7 @@ rec {
|
|||
=> { x = "x-foo"; y = "y-bar"; }
|
||||
*/
|
||||
mapAttrs = f: set:
|
||||
listToAttrs (map (attr: nameValuePair attr (f attr (getAttr attr set))) (attrNames set));
|
||||
listToAttrs (map (attr: { name = attr; value = f attr (getAttr attr set); }) (attrNames set));
|
||||
|
||||
|
||||
/* Like `mapAttrs', but allows the name of each attribute to be
|
||||
|
@ -240,7 +239,7 @@ rec {
|
|||
# names, hopefully this does not affect the system because the maximal
|
||||
# laziness avoid computing twice the same expression and listToAttrs does
|
||||
# not care about duplicated attribute names.
|
||||
zipAttrsWith = f: sets: zipWithNames (concatMap attrNames sets) f sets;
|
||||
zipAttrsWith = f: sets: zipAttrsWithNames (concatMap attrNames sets) f sets;
|
||||
|
||||
zipAttrs = zipAttrsWith (name: values: values);
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ let
|
|||
sources = import ./sources.nix;
|
||||
modules = import ./modules.nix;
|
||||
options = import ./options.nix;
|
||||
properties = import ./properties.nix;
|
||||
types = import ./types.nix;
|
||||
meta = import ./meta.nix;
|
||||
debug = import ./debug.nix;
|
||||
|
@ -21,13 +20,13 @@ let
|
|||
|
||||
in
|
||||
{ inherit trivial lists strings stringsWithDeps attrsets sources options
|
||||
properties modules types meta debug maintainers licenses platforms systems;
|
||||
modules types meta debug maintainers licenses platforms systems;
|
||||
# Pull in some builtins not included elsewhere.
|
||||
inherit (builtins) pathExists readFile;
|
||||
}
|
||||
# !!! don't include everything at top-level; perhaps only the most
|
||||
# commonly used functions.
|
||||
// trivial // lists // strings // stringsWithDeps // attrsets // sources
|
||||
// properties // options // types // meta // debug // misc // modules
|
||||
// options // types // meta // debug // misc // modules
|
||||
// systems
|
||||
// customisation
|
||||
|
|
|
@ -118,6 +118,11 @@ in rec {
|
|||
all = pred: fold (x: y: if pred x then y else false) true;
|
||||
|
||||
|
||||
# Count how many times function `pred' returns true for the elements
|
||||
# of `list'.
|
||||
count = pred: fold (x: c: if pred x then inc c else c) 0;
|
||||
|
||||
|
||||
# Return a singleton list or an empty list, depending on a boolean
|
||||
# value. Useful when building lists with optional elements
|
||||
# (e.g. `++ optional (system == "i686-linux") flashplayer').
|
||||
|
@ -165,10 +170,11 @@ in rec {
|
|||
|
||||
zipLists = zipListsWith (fst: snd: { inherit fst snd; });
|
||||
|
||||
|
||||
# Reverse the order of the elements of a list.
|
||||
|
||||
# Reverse the order of the elements of a list. FIXME: O(n^2)!
|
||||
reverseList = fold (e: acc: acc ++ [ e ]) [];
|
||||
|
||||
|
||||
# Sort a list based on a comparator function which compares two
|
||||
# elements and returns true if the first argument is strictly below
|
||||
# the second argument. The returned list is sorted in an increasing
|
||||
|
|
631
lib/modules.nix
631
lib/modules.nix
|
@ -1,379 +1,312 @@
|
|||
# NixOS module handling.
|
||||
|
||||
let lib = import ./default.nix; in
|
||||
|
||||
with { inherit (builtins) head; };
|
||||
with import ./trivial.nix;
|
||||
with import ./lists.nix;
|
||||
with import ./misc.nix;
|
||||
with import ./trivial.nix;
|
||||
with import ./attrsets.nix;
|
||||
with import ./options.nix;
|
||||
with import ./properties.nix;
|
||||
with import ./debug.nix;
|
||||
with import ./types.nix;
|
||||
|
||||
rec {
|
||||
|
||||
# Unfortunately this can also be a string.
|
||||
isPath = x: !(
|
||||
builtins.isFunction x
|
||||
|| builtins.isAttrs x
|
||||
|| builtins.isInt x
|
||||
|| builtins.isBool x
|
||||
|| builtins.isList x
|
||||
);
|
||||
|
||||
|
||||
importIfPath = path:
|
||||
if isPath path then
|
||||
import path
|
||||
else
|
||||
path;
|
||||
|
||||
|
||||
applyIfFunction = f: arg:
|
||||
if builtins.isFunction f then
|
||||
f arg
|
||||
else
|
||||
f;
|
||||
|
||||
|
||||
isModule = m:
|
||||
(m ? config && isAttrs m.config && ! isOption m.config)
|
||||
|| (m ? options && isAttrs m.options && ! isOption m.options);
|
||||
|
||||
|
||||
# Convert module to a set which has imports / options and config
|
||||
# attributes.
|
||||
unifyModuleSyntax = m:
|
||||
/* Evaluate a set of modules. The result is a set of two
|
||||
attributes: ‘options’: the nested set of all option declarations,
|
||||
and ‘config’: the nested set of all option values. */
|
||||
evalModules = { modules, prefix ? [], args ? {}, check ? true }:
|
||||
let
|
||||
delayedModule = delayProperties m;
|
||||
|
||||
getImports =
|
||||
toList (rmProperties (delayedModule.require or []));
|
||||
getImportedPaths = filter isPath getImports;
|
||||
getImportedSets = filter (x: !isPath x) getImports;
|
||||
|
||||
getConfig =
|
||||
removeAttrs delayedModule ["require" "key" "imports"];
|
||||
args' = args // result;
|
||||
closed = closeModules modules args';
|
||||
# Note: the list of modules is reversed to maintain backward
|
||||
# compatibility with the old module system. Not sure if this is
|
||||
# the most sensible policy.
|
||||
options = mergeModules prefix (reverseList closed);
|
||||
# Traverse options and extract the option values into the final
|
||||
# config set. At the same time, check whether all option
|
||||
# definitions have matching declarations.
|
||||
config = yieldConfig prefix options;
|
||||
yieldConfig = prefix: set:
|
||||
let res = removeAttrs (mapAttrs (n: v:
|
||||
if isOption v then v.value
|
||||
else yieldConfig (prefix ++ [n]) v) set) ["_definedNames"];
|
||||
in
|
||||
if check && set ? _definedNames then
|
||||
fold (m: res:
|
||||
fold (name: res:
|
||||
if hasAttr name set then res else throw "The option `${showOption (prefix ++ [name])}' defined in `${m.file}' does not exist.")
|
||||
res m.names)
|
||||
res set._definedNames
|
||||
else
|
||||
res;
|
||||
result = { inherit options config; };
|
||||
in result;
|
||||
|
||||
/* Close a set of modules under the ‘imports’ relation. */
|
||||
closeModules = modules: args:
|
||||
let
|
||||
toClosureList = file: parentKey: imap (n: x:
|
||||
if isAttrs x || builtins.isFunction x then
|
||||
unifyModuleSyntax file "${parentKey}:anon-${toString n}" (applyIfFunction x args)
|
||||
else
|
||||
unifyModuleSyntax (toString x) (toString x) (applyIfFunction (import x) args));
|
||||
in
|
||||
if isModule m then
|
||||
{ key = "<unknown location>"; } // m
|
||||
builtins.genericClosure {
|
||||
startSet = toClosureList unknownModule "" modules;
|
||||
operator = m: toClosureList m.file m.key m.imports;
|
||||
};
|
||||
|
||||
/* Massage a module into canonical form, that is, a set consisting
|
||||
of ‘options’, ‘config’ and ‘imports’ attributes. */
|
||||
unifyModuleSyntax = file: key: m:
|
||||
if m ? config || m ? options then
|
||||
let badAttrs = removeAttrs m ["imports" "options" "config" "key" "_file"]; in
|
||||
if badAttrs != {} then
|
||||
throw "Module `${key}' has an unsupported attribute `${head (attrNames badAttrs)}'."
|
||||
else
|
||||
{ key = "<unknown location>";
|
||||
imports = (m.imports or []) ++ getImportedPaths;
|
||||
config = getConfig;
|
||||
} // (
|
||||
if getImportedSets != [] then
|
||||
assert length getImportedSets == 1;
|
||||
{ options = head getImportedSets; }
|
||||
{ file = m._file or file;
|
||||
key = toString m.key or key;
|
||||
imports = m.imports or [];
|
||||
options = m.options or {};
|
||||
config = m.config or {};
|
||||
}
|
||||
else
|
||||
{ file = m._file or file;
|
||||
key = toString m.key or key;
|
||||
imports = m.require or [] ++ m.imports or [];
|
||||
options = {};
|
||||
config = removeAttrs m ["key" "_file" "require" "imports"];
|
||||
};
|
||||
|
||||
applyIfFunction = f: arg: if builtins.isFunction f then f arg else f;
|
||||
|
||||
/* Merge a list of modules. This will recurse over the option
|
||||
declarations in all modules, combining them into a single set.
|
||||
At the same time, for each option declaration, it will merge the
|
||||
corresponding option definitions in all machines, returning them
|
||||
in the ‘value’ attribute of each option. */
|
||||
mergeModules = prefix: modules:
|
||||
mergeModules' prefix modules
|
||||
(concatMap (m: map (config: { inherit (m) file; inherit config; }) (pushDownProperties m.config)) modules);
|
||||
|
||||
mergeModules' = prefix: options: configs:
|
||||
listToAttrs (map (name: {
|
||||
# We're descending into attribute ‘name’.
|
||||
inherit name;
|
||||
value =
|
||||
let
|
||||
loc = prefix ++ [name];
|
||||
# Get all submodules that declare ‘name’.
|
||||
decls = concatLists (map (m:
|
||||
if hasAttr name m.options
|
||||
then [ { inherit (m) file; options = getAttr name m.options; } ]
|
||||
else []
|
||||
) options);
|
||||
# Get all submodules that define ‘name’.
|
||||
defns = concatLists (map (m:
|
||||
if hasAttr name m.config
|
||||
then map (config: { inherit (m) file; inherit config; })
|
||||
(pushDownProperties (getAttr name m.config))
|
||||
else []
|
||||
) configs);
|
||||
nrOptions = count (m: isOption m.options) decls;
|
||||
# Process mkMerge and mkIf properties.
|
||||
defns' = concatMap (m:
|
||||
if hasAttr name m.config
|
||||
then map (m': { inherit (m) file; value = m'; }) (dischargeProperties (getAttr name m.config))
|
||||
else []
|
||||
) configs;
|
||||
in
|
||||
if nrOptions == length decls then
|
||||
let opt = fixupOptionType loc (mergeOptionDecls loc decls);
|
||||
in evalOptionValue loc opt defns'
|
||||
else if nrOptions != 0 then
|
||||
let
|
||||
firstOption = findFirst (m: isOption m.options) "" decls;
|
||||
firstNonOption = findFirst (m: !isOption m.options) "" decls;
|
||||
in
|
||||
throw "The option `${showOption loc}' in `${firstOption.file}' is a prefix of options in `${firstNonOption.file}'."
|
||||
else
|
||||
{}
|
||||
);
|
||||
mergeModules' loc decls defns;
|
||||
}) (concatMap (m: attrNames m.options) options))
|
||||
// { _definedNames = map (m: { inherit (m) file; names = attrNames m.config; }) configs; };
|
||||
|
||||
/* Merge multiple option declarations into a single declaration. In
|
||||
general, there should be only one declaration of each option.
|
||||
The exception is the ‘options’ attribute, which specifies
|
||||
sub-options. These can be specified multiple times to allow one
|
||||
module to add sub-options to an option declared somewhere else
|
||||
(e.g. multiple modules define sub-options for ‘fileSystems’). */
|
||||
mergeOptionDecls = loc: opts:
|
||||
fold (opt: res:
|
||||
if opt.options ? default && res ? default ||
|
||||
opt.options ? example && res ? example ||
|
||||
opt.options ? description && res ? description ||
|
||||
opt.options ? apply && res ? apply ||
|
||||
opt.options ? type && res ? type
|
||||
then
|
||||
throw "The option `${showOption loc}' in `${opt.file}' is already declared in ${showFiles res.declarations}."
|
||||
else
|
||||
opt.options // res //
|
||||
{ declarations = [opt.file] ++ res.declarations;
|
||||
options = if opt.options ? options then [(toList opt.options.options ++ res.options)] else [];
|
||||
}
|
||||
) { inherit loc; declarations = []; options = []; } opts;
|
||||
|
||||
unifyOptionModule = {key ? "<unknown location>"}: name: index: m: (args:
|
||||
/* Merge all the definitions of an option to produce the final
|
||||
config value. */
|
||||
evalOptionValue = loc: opt: defs:
|
||||
let
|
||||
module = lib.applyIfFunction m args;
|
||||
key_ = rec {
|
||||
file = key;
|
||||
option = name;
|
||||
number = index;
|
||||
outPath = key;
|
||||
};
|
||||
in if lib.isModule module then
|
||||
{ key = key_; } // module
|
||||
else
|
||||
{ key = key_; options = module; }
|
||||
);
|
||||
|
||||
|
||||
moduleClosure = initModules: args:
|
||||
let
|
||||
moduleImport = origin: index: m:
|
||||
let m' = applyIfFunction (importIfPath m) args;
|
||||
in (unifyModuleSyntax m') // {
|
||||
# used by generic closure to avoid duplicated imports.
|
||||
key =
|
||||
if isPath m then m
|
||||
else m'.key or (newModuleName origin index);
|
||||
};
|
||||
|
||||
getImports = m: m.imports or [];
|
||||
|
||||
newModuleName = origin: index:
|
||||
"${origin.key}:<import-${toString index}>";
|
||||
|
||||
topLevel = {
|
||||
key = "<top-level>";
|
||||
# Process mkOverride properties, adding in the default
|
||||
# value specified in the option declaration (if any).
|
||||
defsFinal = filterOverrides
|
||||
((if opt ? default then [{ file = head opt.declarations; value = mkOptionDefault opt.default; }] else []) ++ defs);
|
||||
files = map (def: def.file) defsFinal;
|
||||
# Type-check the remaining definitions, and merge them if
|
||||
# possible.
|
||||
merged =
|
||||
if defsFinal == [] then
|
||||
throw "The option `${showOption loc}' is used but not defined."
|
||||
else
|
||||
fold (def: res:
|
||||
if opt.type.check def.value then res
|
||||
else throw "The option value `${showOption loc}' in `${def.file}' is not a ${opt.type.name}.")
|
||||
(opt.type.merge loc defsFinal) defsFinal;
|
||||
# Finally, apply the ‘apply’ function to the merged
|
||||
# value. This allows options to yield a value computed
|
||||
# from the definitions.
|
||||
value = (opt.apply or id) merged;
|
||||
in opt //
|
||||
{ value = addErrorContext "while evaluating the option `${showOption loc}':" value;
|
||||
definitions = map (def: def.value) defsFinal;
|
||||
isDefined = defsFinal != [];
|
||||
inherit files;
|
||||
};
|
||||
|
||||
in
|
||||
(lazyGenericClosure {
|
||||
startSet = imap (moduleImport topLevel) initModules;
|
||||
operator = m: imap (moduleImport m) (getImports m);
|
||||
});
|
||||
/* Given a config set, expand mkMerge properties, and push down the
|
||||
mkIf properties into the children. The result is a list of
|
||||
config sets that do not have properties at top-level. For
|
||||
example,
|
||||
|
||||
mkMerge [ { boot = set1; } (mkIf cond { boot = set2; services = set3; }) ]
|
||||
|
||||
moduleApply = funs: module:
|
||||
lib.mapAttrs (name: value:
|
||||
if builtins.hasAttr name funs then
|
||||
let fun = lib.getAttr name funs; in
|
||||
fun value
|
||||
is transformed into
|
||||
|
||||
[ { boot = set1; } { boot = mkIf cond set2; services mkIf cond set3; } ].
|
||||
|
||||
This transform is the critical step that allows mkIf conditions
|
||||
to refer to the full configuration without creating an infinite
|
||||
recursion.
|
||||
*/
|
||||
pushDownProperties = cfg:
|
||||
if cfg._type or "" == "merge" then
|
||||
concatMap pushDownProperties cfg.contents
|
||||
else if cfg._type or "" == "if" then
|
||||
map (mapAttrs (n: v: mkIf cfg.condition v)) (pushDownProperties cfg.content)
|
||||
else if cfg._type or "" == "override" then
|
||||
map (mapAttrs (n: v: mkOverride cfg.priority v)) (pushDownProperties cfg.content)
|
||||
else
|
||||
[ cfg ];
|
||||
|
||||
/* Given a config value, expand mkMerge properties, and discharge
|
||||
any mkIf conditions. That is, this is the place where mkIf
|
||||
conditions are actually evaluated. The result is a list of
|
||||
config values. For example, ‘mkIf false x’ yields ‘[]’,
|
||||
‘mkIf true x’ yields ‘[x]’, and
|
||||
|
||||
mkMerge [ 1 (mkIf true 2) (mkIf true (mkIf false 3)) ]
|
||||
|
||||
yields ‘[ 1 2 ]’.
|
||||
*/
|
||||
dischargeProperties = def:
|
||||
if def._type or "" == "merge" then
|
||||
concatMap dischargeProperties def.contents
|
||||
else if def._type or "" == "if" then
|
||||
if def.condition then
|
||||
dischargeProperties def.content
|
||||
else
|
||||
value
|
||||
) module;
|
||||
|
||||
|
||||
# Handle mkMerge function left behind after a delay property.
|
||||
moduleFlattenMerge = module:
|
||||
if module ? config &&
|
||||
isProperty module.config &&
|
||||
isMerge module.config.property
|
||||
then
|
||||
(map (cfg: { key = module.key; config = cfg; }) module.config.content)
|
||||
++ [ (module // { config = {}; }) ]
|
||||
[ ]
|
||||
else
|
||||
[ module ];
|
||||
[ def ];
|
||||
|
||||
/* Given a list of config values, process the mkOverride properties,
|
||||
that is, return the values that have the highest (that is,
|
||||
numerically lowest) priority, and strip the mkOverride
|
||||
properties. For example,
|
||||
|
||||
# Handle mkMerge attributes which are left behind by previous delay
|
||||
# properties and convert them into a list of modules. Delay properties
|
||||
# inside the config attribute of a module and create a second module if a
|
||||
# mkMerge attribute was left behind.
|
||||
#
|
||||
# Module -> [ Module ]
|
||||
delayModule = module:
|
||||
map (moduleApply { config = delayProperties; }) (moduleFlattenMerge module);
|
||||
[ { file = "/1"; value = mkOverride 10 "a"; }
|
||||
{ file = "/2"; value = mkOverride 20 "b"; }
|
||||
{ file = "/3"; value = "z"; }
|
||||
{ file = "/4"; value = mkOverride 10 "d"; }
|
||||
]
|
||||
|
||||
yields
|
||||
|
||||
evalDefinitions = opt: values:
|
||||
if opt.type.delayOnGlobalEval or false then
|
||||
map (delayPropertiesWithIter opt.type.iter opt.name)
|
||||
(evalLocalProperties values)
|
||||
else
|
||||
evalProperties values;
|
||||
[ { file = "/1"; value = "a"; }
|
||||
{ file = "/4"; value = "d"; }
|
||||
]
|
||||
|
||||
|
||||
selectModule = name: m:
|
||||
{ inherit (m) key;
|
||||
} // (
|
||||
if m ? options && builtins.hasAttr name m.options then
|
||||
{ options = lib.getAttr name m.options; }
|
||||
else {}
|
||||
) // (
|
||||
if m ? config && builtins.hasAttr name m.config then
|
||||
{ config = lib.getAttr name m.config; }
|
||||
else {}
|
||||
);
|
||||
|
||||
filterModules = name: modules:
|
||||
filter (m: m ? config || m ? options) (
|
||||
map (selectModule name) modules
|
||||
);
|
||||
|
||||
|
||||
modulesNames = modules:
|
||||
lib.concatMap (m: []
|
||||
++ optionals (m ? options) (lib.attrNames m.options)
|
||||
++ optionals (m ? config) (lib.attrNames m.config)
|
||||
) modules;
|
||||
|
||||
|
||||
moduleZip = funs: modules:
|
||||
lib.mapAttrs (name: fun:
|
||||
fun (catAttrs name modules)
|
||||
) funs;
|
||||
|
||||
|
||||
moduleMerge = path: modules_:
|
||||
Note that "z" has the default priority 100.
|
||||
*/
|
||||
filterOverrides = defs:
|
||||
let
|
||||
addName = name:
|
||||
if path == "" then name else path + "." + name;
|
||||
defaultPrio = 100;
|
||||
getPrio = def: if def.value._type or "" == "override" then def.value.priority else defaultPrio;
|
||||
min = x: y: if builtins.lessThan x y then x else y;
|
||||
highestPrio = fold (def: prio: min (getPrio def) prio) 9999 defs;
|
||||
strip = def: if def.value._type or "" == "override" then def // { value = def.value.content; } else def;
|
||||
in concatMap (def: if getPrio def == highestPrio then [(strip def)] else []) defs;
|
||||
|
||||
modules = concatLists (map delayModule modules_);
|
||||
|
||||
modulesOf = name: filterModules name modules;
|
||||
declarationsOf = name: filter (m: m ? options) (modulesOf name);
|
||||
definitionsOf = name: filter (m: m ? config ) (modulesOf name);
|
||||
|
||||
recurseInto = name:
|
||||
moduleMerge (addName name) (modulesOf name);
|
||||
|
||||
recurseForOption = name: modules: args:
|
||||
moduleMerge name (
|
||||
moduleClosure modules args
|
||||
);
|
||||
|
||||
errorSource = modules:
|
||||
"The error may come from the following files:\n" + (
|
||||
lib.concatStringsSep "\n" (
|
||||
map (m:
|
||||
if m ? key then toString m.key else "<unknown location>"
|
||||
) modules
|
||||
)
|
||||
);
|
||||
|
||||
eol = "\n";
|
||||
|
||||
allNames = modulesNames modules;
|
||||
|
||||
getResults = m:
|
||||
let fetchResult = s: mapAttrs (n: v: v.result) s; in {
|
||||
options = fetchResult m.options;
|
||||
config = fetchResult m.config;
|
||||
};
|
||||
|
||||
endRecursion = { options = {}; config = {}; };
|
||||
|
||||
in if modules == [] then endRecursion else
|
||||
getResults (fix (crossResults: moduleZip {
|
||||
options = lib.zipWithNames allNames (name: values: rec {
|
||||
config = lib.getAttr name crossResults.config;
|
||||
|
||||
declarations = declarationsOf name;
|
||||
declarationSources =
|
||||
map (m: {
|
||||
source = m.key;
|
||||
}) declarations;
|
||||
|
||||
hasOptions = values != [];
|
||||
isOption = any lib.isOption values;
|
||||
|
||||
decls = # add location to sub-module options.
|
||||
map (m:
|
||||
mapSubOptions
|
||||
(unifyOptionModule {inherit (m) key;} name)
|
||||
m.options
|
||||
) declarations;
|
||||
|
||||
decl =
|
||||
lib.addErrorContext "${eol
|
||||
}while enhancing option `${addName name}':${eol
|
||||
}${errorSource declarations}${eol
|
||||
}" (
|
||||
addOptionMakeUp
|
||||
{ name = addName name; recurseInto = recurseForOption; }
|
||||
(mergeOptionDecls decls)
|
||||
);
|
||||
|
||||
value = decl // (with config; {
|
||||
inherit (config) isNotDefined;
|
||||
isDefined = ! isNotDefined;
|
||||
declarations = declarationSources;
|
||||
definitions = definitionSources;
|
||||
config = strictResult;
|
||||
});
|
||||
|
||||
recurse = (recurseInto name).options;
|
||||
|
||||
result =
|
||||
if isOption then value
|
||||
else if !hasOptions then {}
|
||||
else if all isAttrs values then recurse
|
||||
else
|
||||
throw "${eol
|
||||
}Unexpected type where option declarations are expected.${eol
|
||||
}${errorSource declarations}${eol
|
||||
}";
|
||||
|
||||
});
|
||||
|
||||
config = lib.zipWithNames allNames (name: values_: rec {
|
||||
option = lib.getAttr name crossResults.options;
|
||||
|
||||
definitions = definitionsOf name;
|
||||
definitionSources =
|
||||
map (m: {
|
||||
source = m.key;
|
||||
value = m.config;
|
||||
}) definitions;
|
||||
|
||||
values = values_ ++
|
||||
optionals (option.isOption && option.decl ? extraConfigs)
|
||||
option.decl.extraConfigs;
|
||||
|
||||
defs = evalDefinitions option.decl values;
|
||||
|
||||
isNotDefined = defs == [];
|
||||
|
||||
value =
|
||||
lib.addErrorContext "${eol
|
||||
}while evaluating the option `${addName name}':${eol
|
||||
}${errorSource (modulesOf name)}${eol
|
||||
}" (
|
||||
let opt = option.decl; in
|
||||
opt.apply (
|
||||
if isNotDefined then
|
||||
opt.default or (throw "Option `${addName name}' not defined and does not have a default value.")
|
||||
else opt.merge defs
|
||||
)
|
||||
);
|
||||
|
||||
strictResult = builtins.tryEval (builtins.toXML value);
|
||||
|
||||
recurse = (recurseInto name).config;
|
||||
|
||||
configIsAnOption = v: isOption (rmProperties v);
|
||||
errConfigIsAnOption =
|
||||
let badModules = filter (m: configIsAnOption m.config) definitions; in
|
||||
"${eol
|
||||
}Option ${addName name} is defined in the configuration section.${eol
|
||||
}${errorSource badModules}${eol
|
||||
}";
|
||||
|
||||
errDefinedWithoutDeclaration =
|
||||
let badModules = definitions; in
|
||||
"${eol
|
||||
}Option '${addName name}' defined without option declaration.${eol
|
||||
}${errorSource badModules}${eol
|
||||
}";
|
||||
|
||||
result =
|
||||
if option.isOption then value
|
||||
else if !option.hasOptions then throw errDefinedWithoutDeclaration
|
||||
else if any configIsAnOption values then throw errConfigIsAnOption
|
||||
else if all isAttrs values then recurse
|
||||
# plain value during the traversal
|
||||
else throw errDefinedWithoutDeclaration;
|
||||
|
||||
});
|
||||
} modules));
|
||||
|
||||
|
||||
fixMergeModules = initModules: {...}@args:
|
||||
lib.fix (result:
|
||||
# This trick avoids an infinite loop because names of attribute
|
||||
# are know and it is not required to evaluate the result of
|
||||
# moduleMerge to know which attributes are present as arguments.
|
||||
let module = { inherit (result) options config; }; in
|
||||
moduleMerge "" (
|
||||
moduleClosure initModules (module // args)
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
# Visit all definitions to raise errors related to undeclared options.
|
||||
checkModule = path: {config, options, ...}@m:
|
||||
/* Hack for backward compatibility: convert options of type
|
||||
optionSet to configOf. FIXME: remove eventually. */
|
||||
fixupOptionType = loc: opt:
|
||||
let
|
||||
eol = "\n";
|
||||
addName = name:
|
||||
if path == "" then name else path + "." + name;
|
||||
in
|
||||
if lib.isOption options then
|
||||
if options ? options then
|
||||
options.type.fold
|
||||
(cfg: res: res && checkModule (options.type.docPath path) cfg._args)
|
||||
true config
|
||||
else
|
||||
true
|
||||
else if isAttrs options && lib.attrNames m.options != [] then
|
||||
all (name:
|
||||
lib.addErrorContext "${eol
|
||||
}while checking the attribute `${addName name}':${eol
|
||||
}" (checkModule (addName name) (selectModule name m))
|
||||
) (lib.attrNames m.config)
|
||||
else
|
||||
builtins.trace "try to evaluate config ${lib.showVal config}."
|
||||
false;
|
||||
options' = opt.options or
|
||||
(throw "Option `${showOption loc'}' has type optionSet but has no option attribute.");
|
||||
coerce = x:
|
||||
if builtins.isFunction x then x
|
||||
else { config, ... }: { options = x; };
|
||||
options = map coerce (flatten options');
|
||||
f = tp:
|
||||
if tp.name == "option set" then types.submodule options
|
||||
else if tp.name == "attribute set of option sets" then types.attrsOf (types.submodule options)
|
||||
else if tp.name == "list or attribute set of option sets" then types.loaOf (types.submodule options)
|
||||
else if tp.name == "list of option sets" then types.listOf (types.submodule options)
|
||||
else if tp.name == "null or option set" then types.nullOr (types.submodule options)
|
||||
else tp;
|
||||
in opt // { type = f (opt.type or types.unspecified); };
|
||||
|
||||
|
||||
/* Properties. */
|
||||
|
||||
mkIf = condition: content:
|
||||
{ _type = "if";
|
||||
inherit condition content;
|
||||
};
|
||||
|
||||
mkAssert = assertion: message: content:
|
||||
mkIf
|
||||
(if assertion then true else throw "\nFailed assertion: ${message}")
|
||||
content;
|
||||
|
||||
mkMerge = contents:
|
||||
{ _type = "merge";
|
||||
inherit contents;
|
||||
};
|
||||
|
||||
mkOverride = priority: content:
|
||||
{ _type = "override";
|
||||
inherit priority content;
|
||||
};
|
||||
|
||||
mkOptionDefault = mkOverride 1001; # priority of option defaults
|
||||
mkDefault = mkOverride 1000; # used in config sections of non-user modules to set a default
|
||||
mkForce = mkOverride 50;
|
||||
mkVMOverride = mkOverride 10; # used by ‘nixos-rebuild build-vm’
|
||||
|
||||
mkFixStrictness = id; # obsolete, no-op
|
||||
|
||||
# FIXME: Add mkOrder back in. It's not currently used anywhere in
|
||||
# NixOS, but it should be useful.
|
||||
|
||||
|
||||
/* Compatibility. */
|
||||
fixMergeModules = modules: args: evalModules { inherit modules args; check = false; };
|
||||
|
||||
}
|
||||
|
|
311
lib/options.nix
311
lib/options.nix
|
@ -2,28 +2,27 @@
|
|||
|
||||
let lib = import ./default.nix; in
|
||||
|
||||
with { inherit (builtins) head length; };
|
||||
with import ./trivial.nix;
|
||||
with import ./lists.nix;
|
||||
with import ./misc.nix;
|
||||
with import ./attrsets.nix;
|
||||
with import ./properties.nix;
|
||||
with import ./strings.nix;
|
||||
|
||||
rec {
|
||||
|
||||
isOption = lib.isType "option";
|
||||
mkOption = attrs: attrs // {
|
||||
_type = "option";
|
||||
# name (this is the name of the attributem it is automatically generated by the traversal)
|
||||
# default (value used when no definition exists)
|
||||
# example (documentation)
|
||||
# description (documentation)
|
||||
# type (option type, provide a default merge function and ensure type correctness)
|
||||
# merge (function used to merge definitions into one definition: [ /type/ ] -> /type/)
|
||||
# apply (convert the option value to ease the manipulation of the option result)
|
||||
# options (set of sub-options declarations & definitions)
|
||||
# extraConfigs (list of possible configurations)
|
||||
};
|
||||
mkOption =
|
||||
{ default ? null # Default value used when no definition is given in the configuration.
|
||||
, defaultText ? null # Textual representation of the default, for in the manual.
|
||||
, example ? null # Example value used in the manual.
|
||||
, description ? null # String describing the option.
|
||||
, type ? null # Option type, providing type-checking and value merging.
|
||||
, apply ? null # Function that converts the option value to something else.
|
||||
, internal ? null # Whether the option is for NixOS developers only.
|
||||
, visible ? null # Whether the option shows up in the manual.
|
||||
, options ? null # Obsolete, used by types.optionSet.
|
||||
} @ attrs:
|
||||
attrs // { _type = "option"; };
|
||||
|
||||
mkEnableOption = name: mkOption {
|
||||
default = false;
|
||||
|
@ -32,261 +31,65 @@ rec {
|
|||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
mapSubOptions = f: opt:
|
||||
if opt ? options then
|
||||
opt // {
|
||||
options = imap f (toList opt.options);
|
||||
}
|
||||
else
|
||||
opt;
|
||||
|
||||
# Make the option declaration more user-friendly by adding default
|
||||
# settings and some verifications based on the declaration content (like
|
||||
# type correctness).
|
||||
addOptionMakeUp = {name, recurseInto}: decl:
|
||||
let
|
||||
init = {
|
||||
inherit name;
|
||||
merge = mergeDefaultOption;
|
||||
apply = lib.id;
|
||||
};
|
||||
|
||||
functionsFromType = opt:
|
||||
opt // (builtins.intersectAttrs { merge = 1; check = 1; } (decl.type or {}));
|
||||
|
||||
addDeclaration = opt: opt // decl;
|
||||
|
||||
ensureMergeInputType = opt:
|
||||
if opt ? check then
|
||||
opt // {
|
||||
merge = list:
|
||||
if all opt.check list then
|
||||
opt.merge list
|
||||
else
|
||||
throw "A value of the option `${name}' has a bad type.";
|
||||
}
|
||||
else opt;
|
||||
|
||||
checkDefault = opt:
|
||||
if opt ? check && opt ? default then
|
||||
opt // {
|
||||
default =
|
||||
if opt.check opt.default then
|
||||
opt.default
|
||||
else
|
||||
throw "The default value of the option `${name}' has a bad type.";
|
||||
}
|
||||
else opt;
|
||||
|
||||
handleOptionSets = opt:
|
||||
if opt ? type && opt.type.hasOptions then
|
||||
let
|
||||
# Evaluate sub-modules.
|
||||
subModuleMerge = path: vals:
|
||||
lib.fix (args:
|
||||
let
|
||||
result = recurseInto path (opt.options ++ imap (index: v: args: {
|
||||
key = rec {
|
||||
#!!! Would be nice if we had the file the val was from
|
||||
option = path;
|
||||
number = index;
|
||||
outPath = "option ${option} config number ${toString number}";
|
||||
};
|
||||
} // (lib.applyIfFunction v args)) (toList vals)) args;
|
||||
name = lib.removePrefix (opt.name + ".") path;
|
||||
extraArgs = opt.extraArgs or {};
|
||||
individualExtraArgs = opt.individualExtraArgs or {};
|
||||
in {
|
||||
inherit (result) config options;
|
||||
inherit name;
|
||||
} //
|
||||
(opt.extraArgs or {}) //
|
||||
(if hasAttr name individualExtraArgs then getAttr name individualExtraArgs else {})
|
||||
);
|
||||
|
||||
# Add _options in sub-modules to make it viewable from other
|
||||
# modules.
|
||||
subModuleMergeConfig = path: vals:
|
||||
let result = subModuleMerge path vals; in
|
||||
{ _args = result; } // result.config;
|
||||
|
||||
in
|
||||
opt // {
|
||||
merge = list:
|
||||
opt.type.iter
|
||||
subModuleMergeConfig
|
||||
opt.name
|
||||
(opt.merge list);
|
||||
options =
|
||||
let path = opt.type.docPath opt.name; in
|
||||
(subModuleMerge path []).options;
|
||||
}
|
||||
else
|
||||
opt;
|
||||
in
|
||||
foldl (opt: f: f opt) init [
|
||||
# default settings
|
||||
functionsFromType
|
||||
|
||||
# user settings
|
||||
addDeclaration
|
||||
|
||||
# override settings
|
||||
ensureMergeInputType
|
||||
checkDefault
|
||||
handleOptionSets
|
||||
];
|
||||
|
||||
# Merge a list of options containning different field. This is useful to
|
||||
# separate the merge & apply fields from the interface.
|
||||
mergeOptionDecls = opts:
|
||||
if opts == [] then {}
|
||||
else if length opts == 1 then
|
||||
let opt = head opts; in
|
||||
if opt ? options then
|
||||
opt // { options = toList opt.options; }
|
||||
else
|
||||
opt
|
||||
else
|
||||
fold (opt1: opt2:
|
||||
lib.addErrorContext "opt1 = ${lib.showVal opt1}\nopt2 = ${lib.showVal opt2}" (
|
||||
# You cannot merge if two options have the same field.
|
||||
assert opt1 ? default -> ! opt2 ? default;
|
||||
assert opt1 ? example -> ! opt2 ? example;
|
||||
assert opt1 ? description -> ! opt2 ? description;
|
||||
assert opt1 ? merge -> ! opt2 ? merge;
|
||||
assert opt1 ? apply -> ! opt2 ? apply;
|
||||
assert opt1 ? type -> ! opt2 ? type;
|
||||
opt1 // opt2
|
||||
// optionalAttrs (opt1 ? options || opt2 ? options) {
|
||||
options =
|
||||
(toList (opt1.options or []))
|
||||
++ (toList (opt2.options or []));
|
||||
}
|
||||
// optionalAttrs (opt1 ? extraConfigs || opt2 ? extraConfigs) {
|
||||
extraConfigs = opt1.extraConfigs or [] ++ opt2.extraConfigs or [];
|
||||
}
|
||||
// optionalAttrs (opt1 ? extraArgs || opt2 ? extraArgs) {
|
||||
extraArgs = opt1.extraArgs or {} // opt2.extraArgs or {};
|
||||
}
|
||||
// optionalAttrs (opt1 ? individualExtraArgs || opt2 ? individualExtraArgs) {
|
||||
individualExtraArgs = zipAttrsWith (name: values:
|
||||
if length values == 1 then head values else (head values // (head (tail values)))
|
||||
) [ (opt1.individualExtraArgs or {}) (opt2.individualExtraArgs or {}) ];
|
||||
}
|
||||
)) {} opts;
|
||||
|
||||
|
||||
# !!! This function will be removed because this can be done with the
|
||||
# multiple option declarations.
|
||||
addDefaultOptionValues = defs: opts: opts //
|
||||
builtins.listToAttrs (map (defName:
|
||||
{ name = defName;
|
||||
value =
|
||||
let
|
||||
defValue = builtins.getAttr defName defs;
|
||||
optValue = builtins.getAttr defName opts;
|
||||
in
|
||||
if isOption defValue
|
||||
then
|
||||
# `defValue' is an option.
|
||||
if hasAttr defName opts
|
||||
then builtins.getAttr defName opts
|
||||
else defValue.default
|
||||
else
|
||||
# `defValue' is an attribute set containing options.
|
||||
# So recurse.
|
||||
if hasAttr defName opts && isAttrs optValue
|
||||
then addDefaultOptionValues defValue optValue
|
||||
else addDefaultOptionValues defValue {};
|
||||
}
|
||||
) (attrNames defs));
|
||||
|
||||
mergeDefaultOption = list:
|
||||
mergeDefaultOption = loc: defs:
|
||||
let list = getValues defs; in
|
||||
if length list == 1 then head list
|
||||
else if all builtins.isFunction list then x: mergeDefaultOption (map (f: f x) list)
|
||||
else if all builtins.isFunction list then x: mergeDefaultOption loc (map (f: f x) list)
|
||||
else if all isList list then concatLists list
|
||||
else if all isAttrs list then fold lib.mergeAttrs {} list
|
||||
else if all builtins.isBool list then fold lib.or false list
|
||||
else if all builtins.isString list then lib.concatStrings list
|
||||
else if all builtins.isInt list && all (x: x == head list) list
|
||||
then head list
|
||||
else throw "Cannot merge values.";
|
||||
else if all builtins.isInt list && all (x: x == head list) list then head list
|
||||
else throw "Cannot merge definitions of `${showOption loc}' given in ${showFiles (getFiles defs)}.";
|
||||
|
||||
mergeTypedOption = typeName: predicate: merge: list:
|
||||
if all predicate list then merge list
|
||||
else throw "Expect a ${typeName}.";
|
||||
/* Obsolete, will remove soon. Specify an option type or apply
|
||||
function instead. */
|
||||
mergeTypedOption = typeName: predicate: merge: loc: list:
|
||||
let list' = map (x: x.value) list; in
|
||||
if all predicate list then merge list'
|
||||
else throw "Expected a ${typeName}.";
|
||||
|
||||
mergeEnableOption = mergeTypedOption "boolean"
|
||||
(x: true == x || false == x) (fold lib.or false);
|
||||
|
||||
mergeListOption = mergeTypedOption "list" isList concatLists;
|
||||
|
||||
mergeStringOption = mergeTypedOption "string"
|
||||
(x: if builtins ? isString then builtins.isString x else x + "")
|
||||
lib.concatStrings;
|
||||
mergeStringOption = mergeTypedOption "string" builtins.isString lib.concatStrings;
|
||||
|
||||
mergeOneOption = list:
|
||||
if list == [] then abort "This case should never happen."
|
||||
else if length list != 1 then throw "Multiple definitions. Only one is allowed for this option."
|
||||
else head list;
|
||||
mergeOneOption = loc: defs:
|
||||
if defs == [] then abort "This case should never happen."
|
||||
else if length defs != 1 then
|
||||
throw "The unique option `${showOption loc}' is defined multiple times, in ${showFiles (getFiles defs)}."
|
||||
else (head defs).value;
|
||||
|
||||
|
||||
fixableMergeFun = merge: f: config:
|
||||
merge (
|
||||
# generate the list of option sets.
|
||||
f config
|
||||
);
|
||||
|
||||
fixableMergeModules = merge: initModules: {...}@args: config:
|
||||
fixableMergeFun merge (config:
|
||||
lib.moduleClosure initModules (args // { inherit config; })
|
||||
) config;
|
||||
|
||||
|
||||
fixableDefinitionsOf = initModules: {...}@args:
|
||||
fixableMergeModules (modules: (lib.moduleMerge "" modules).config) initModules args;
|
||||
|
||||
fixableDeclarationsOf = initModules: {...}@args:
|
||||
fixableMergeModules (modules: (lib.moduleMerge "" modules).options) initModules args;
|
||||
|
||||
definitionsOf = initModules: {...}@args:
|
||||
(lib.fix (module:
|
||||
fixableMergeModules (lib.moduleMerge "") initModules args module.config
|
||||
)).config;
|
||||
|
||||
declarationsOf = initModules: {...}@args:
|
||||
(lib.fix (module:
|
||||
fixableMergeModules (lib.moduleMerge "") initModules args module.config
|
||||
)).options;
|
||||
getValues = map (x: x.value);
|
||||
getFiles = map (x: x.file);
|
||||
|
||||
|
||||
# Generate documentation template from the list of option declaration like
|
||||
# the set generated with filterOptionSets.
|
||||
optionAttrSetToDocList = attrs:
|
||||
let options = collect isOption attrs; in
|
||||
fold (opt: rest:
|
||||
let
|
||||
docOption = {
|
||||
inherit (opt) name;
|
||||
description = opt.description or (throw "Option ${opt.name}: No description.");
|
||||
declarations = map (x: toString x.source) opt.declarations;
|
||||
#definitions = map (x: toString x.source) opt.definitions;
|
||||
internal = opt.internal or false;
|
||||
visible = opt.visible or true;
|
||||
}
|
||||
// optionalAttrs (opt ? example) { example = scrubOptionValue opt.example; }
|
||||
// optionalAttrs (opt ? default) { default = scrubOptionValue opt.default; }
|
||||
// optionalAttrs (opt ? defaultText) { default = opt.defaultText; };
|
||||
optionAttrSetToDocList = optionAttrSetToDocList' [];
|
||||
|
||||
subOptions =
|
||||
if opt ? options then
|
||||
optionAttrSetToDocList opt.options
|
||||
else
|
||||
[];
|
||||
in
|
||||
[ docOption ] ++ subOptions ++ rest
|
||||
) [] options;
|
||||
optionAttrSetToDocList' = prefix: options:
|
||||
fold (opt: rest:
|
||||
let
|
||||
docOption = rec {
|
||||
name = showOption opt.loc;
|
||||
description = opt.description or (throw "Option `${name}' has no description.");
|
||||
declarations = filter (x: x != unknownModule) opt.declarations;
|
||||
internal = opt.internal or false;
|
||||
visible = opt.visible or true;
|
||||
}
|
||||
// optionalAttrs (opt ? example) { example = scrubOptionValue opt.example; }
|
||||
// optionalAttrs (opt ? default) { default = scrubOptionValue opt.default; }
|
||||
// optionalAttrs (opt ? defaultText) { default = opt.defaultText; };
|
||||
|
||||
subOptions =
|
||||
let ss = opt.type.getSubOptions opt.loc;
|
||||
in if ss != {} then optionAttrSetToDocList' opt.loc ss else [];
|
||||
in
|
||||
# FIXME: expensive, O(n^2)
|
||||
[ docOption ] ++ subOptions ++ rest) [] (collect isOption options);
|
||||
|
||||
|
||||
/* This function recursively removes all derivation attributes from
|
||||
|
@ -295,7 +98,8 @@ rec {
|
|||
representation of derivations is very large (on the order of
|
||||
megabytes) and is not actually used by the manual generator. */
|
||||
scrubOptionValue = x:
|
||||
if isDerivation x then { type = "derivation"; drvPath = x.name; outPath = x.name; name = x.name; }
|
||||
if isDerivation x then
|
||||
{ type = "derivation"; drvPath = x.name; outPath = x.name; name = x.name; }
|
||||
else if isList x then map scrubOptionValue x
|
||||
else if isAttrs x then mapAttrs (n: v: scrubOptionValue v) (removeAttrs x ["_args"])
|
||||
else x;
|
||||
|
@ -308,4 +112,9 @@ rec {
|
|||
literalExample = text: { _type = "literalExample"; inherit text; };
|
||||
|
||||
|
||||
/* Helper functions. */
|
||||
showOption = concatStringsSep ".";
|
||||
showFiles = files: concatStringsSep " and " (map (f: "`${f}'") files);
|
||||
unknownModule = "<unknown-file>";
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -22,7 +22,7 @@ rec {
|
|||
};
|
||||
|
||||
|
||||
isCpuType = x: typeOf x == "cpu-type"
|
||||
isCpuType = x: isType "cpu-type" x
|
||||
&& elem x.bits [8 16 32 64 128]
|
||||
&& (builtins.lessThan 8 x.bits -> isSignificantByte x.significantByte);
|
||||
|
||||
|
@ -69,7 +69,7 @@ rec {
|
|||
};
|
||||
|
||||
|
||||
isSystem = x: typeOf x == "system"
|
||||
isSystem = x: isType "system" x
|
||||
&& isCpuType x.cpu
|
||||
&& isArchitecture x.arch
|
||||
&& isKernel x.kernel;
|
||||
|
|
244
lib/types.nix
244
lib/types.nix
|
@ -1,17 +1,15 @@
|
|||
# Definitions related to run-time type checking. Used in particular
|
||||
# to type-check NixOS configurations.
|
||||
|
||||
let lib = import ./default.nix; in
|
||||
|
||||
with import ./lists.nix;
|
||||
with import ./attrsets.nix;
|
||||
with import ./options.nix;
|
||||
with import ./trivial.nix;
|
||||
with import ./strings.nix;
|
||||
|
||||
rec {
|
||||
|
||||
isType = type: x: (x._type or "") == type;
|
||||
hasType = x: isAttrs x && x ? _type;
|
||||
typeOf = x: x._type or "";
|
||||
|
||||
setType = typeName: value: value // {
|
||||
|
@ -19,208 +17,194 @@ rec {
|
|||
};
|
||||
|
||||
|
||||
# name (name of the type)
|
||||
# check (check the config value. Before returning false it should trace the bad value eg using traceValIfNot)
|
||||
# merge (default merge function)
|
||||
# iter (iterate on all elements contained in this type)
|
||||
# fold (fold all elements contained in this type)
|
||||
# hasOptions (boolean: whatever this option contains an option set)
|
||||
# delayOnGlobalEval (boolean: should properties go through the evaluation of this option)
|
||||
# docPath (path concatenated to the option name contained in the option set)
|
||||
isOptionType = isType "option-type";
|
||||
mkOptionType =
|
||||
{ name
|
||||
, check ? (x: true)
|
||||
, merge ? mergeDefaultOption
|
||||
# Handle complex structure types.
|
||||
, iter ? (f: path: v: f path v)
|
||||
, fold ? (op: nul: v: op v nul)
|
||||
, docPath ? lib.id
|
||||
# If the type can contains option sets.
|
||||
, hasOptions ? false
|
||||
, delayOnGlobalEval ? false
|
||||
{ # Human-readable representation of the type.
|
||||
name
|
||||
, # Function applied to each definition that should return true if
|
||||
# its type-correct, false otherwise.
|
||||
check ? (x: true)
|
||||
, # Merge a list of definitions together into a single value.
|
||||
# This function is called with two arguments: the location of
|
||||
# the option in the configuration as a list of strings
|
||||
# (e.g. ["boot" "loader "grub" "enable"]), and a list of
|
||||
# definition values and locations (e.g. [ { file = "/foo.nix";
|
||||
# value = 1; } { file = "/bar.nix"; value = 2 } ]).
|
||||
merge ? mergeDefaultOption
|
||||
, # Return a flat list of sub-options. Used to generate
|
||||
# documentation.
|
||||
getSubOptions ? prefix: {}
|
||||
}:
|
||||
|
||||
{ _type = "option-type";
|
||||
inherit name check merge iter fold docPath hasOptions delayOnGlobalEval;
|
||||
inherit name check merge getSubOptions;
|
||||
};
|
||||
|
||||
|
||||
types = rec {
|
||||
|
||||
unspecified = mkOptionType {
|
||||
name = "unspecified";
|
||||
};
|
||||
|
||||
bool = mkOptionType {
|
||||
name = "boolean";
|
||||
check = lib.traceValIfNot builtins.isBool;
|
||||
merge = fold lib.or false;
|
||||
check = builtins.isBool;
|
||||
merge = loc: fold (x: y: x.value || y) false;
|
||||
};
|
||||
|
||||
int = mkOptionType {
|
||||
name = "integer";
|
||||
check = lib.traceValIfNot builtins.isInt;
|
||||
check = builtins.isInt;
|
||||
merge = mergeOneOption;
|
||||
};
|
||||
|
||||
string = mkOptionType {
|
||||
str = mkOptionType {
|
||||
name = "string";
|
||||
check = lib.traceValIfNot builtins.isString;
|
||||
merge = lib.concatStrings;
|
||||
check = builtins.isString;
|
||||
merge = mergeOneOption;
|
||||
};
|
||||
|
||||
# Like ‘string’, but add newlines between every value. Useful for
|
||||
# configuration file contents.
|
||||
lines = mkOptionType {
|
||||
# Merge multiple definitions by concatenating them (with the given
|
||||
# separator between the values).
|
||||
separatedString = sep: mkOptionType {
|
||||
name = "string";
|
||||
check = lib.traceValIfNot builtins.isString;
|
||||
merge = lib.concatStringsSep "\n";
|
||||
check = builtins.isString;
|
||||
merge = loc: defs: concatStringsSep sep (getValues defs);
|
||||
};
|
||||
|
||||
envVar = mkOptionType {
|
||||
name = "environment variable";
|
||||
inherit (string) check;
|
||||
merge = lib.concatStringsSep ":";
|
||||
};
|
||||
lines = separatedString "\n";
|
||||
commas = separatedString ",";
|
||||
envVar = separatedString ":";
|
||||
|
||||
# Deprecated; should not be used because it quietly concatenates
|
||||
# strings, which is usually not what you want.
|
||||
string = separatedString "";
|
||||
|
||||
attrs = mkOptionType {
|
||||
name = "attribute set";
|
||||
check = lib.traceValIfNot isAttrs;
|
||||
merge = fold lib.mergeAttrs {};
|
||||
check = isAttrs;
|
||||
merge = loc: fold (def: mergeAttrs def.value) {};
|
||||
};
|
||||
|
||||
# derivation is a reserved keyword.
|
||||
package = mkOptionType {
|
||||
name = "derivation";
|
||||
check = lib.traceValIfNot isDerivation;
|
||||
check = isDerivation;
|
||||
merge = mergeOneOption;
|
||||
};
|
||||
|
||||
path = mkOptionType {
|
||||
name = "path";
|
||||
# Hacky: there is no ‘isPath’ primop.
|
||||
check = lib.traceValIfNot (x: builtins.unsafeDiscardStringContext (builtins.substring 0 1 (toString x)) == "/");
|
||||
check = x: builtins.unsafeDiscardStringContext (builtins.substring 0 1 (toString x)) == "/";
|
||||
merge = mergeOneOption;
|
||||
};
|
||||
|
||||
# drop this in the future:
|
||||
list = builtins.trace "types.list is deprecated, use types.listOf instead" types.listOf;
|
||||
list = builtins.trace "`types.list' is deprecated; use `types.listOf' instead" types.listOf;
|
||||
|
||||
listOf = elemType: mkOptionType {
|
||||
listOf = elemType: mkOptionType {
|
||||
name = "list of ${elemType.name}s";
|
||||
check = value: lib.traceValIfNot isList value && all elemType.check value;
|
||||
merge = concatLists;
|
||||
iter = f: path: list: map (elemType.iter f (path + ".*")) list;
|
||||
fold = op: nul: list: lib.fold (e: l: elemType.fold op l e) nul list;
|
||||
docPath = path: elemType.docPath (path + ".*");
|
||||
inherit (elemType) hasOptions;
|
||||
|
||||
# You cannot define multiple configurations of one entity, therefore
|
||||
# no reason justify to delay properties inside list elements.
|
||||
delayOnGlobalEval = false;
|
||||
check = value: isList value && all elemType.check value;
|
||||
merge = loc: defs:
|
||||
concatLists (imap (n: def: imap (m: def':
|
||||
elemType.merge (loc ++ ["[${toString n}-${toString m}]"])
|
||||
[{ inherit (def) file; value = def'; }]) def.value) defs);
|
||||
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["*"]);
|
||||
};
|
||||
|
||||
attrsOf = elemType: mkOptionType {
|
||||
name = "attribute set of ${elemType.name}s";
|
||||
check = x: lib.traceValIfNot isAttrs x
|
||||
&& all elemType.check (lib.attrValues x);
|
||||
merge = lib.zipAttrsWith (name: elemType.merge);
|
||||
iter = f: path: set: lib.mapAttrs (name: elemType.iter f (path + "." + name)) set;
|
||||
fold = op: nul: set: fold (e: l: elemType.fold op l e) nul (lib.attrValues set);
|
||||
docPath = path: elemType.docPath (path + ".<name>");
|
||||
inherit (elemType) hasOptions delayOnGlobalEval;
|
||||
check = x: isAttrs x && all elemType.check (attrValues x);
|
||||
merge = loc: defs:
|
||||
zipAttrsWith (name: elemType.merge (loc ++ [name]))
|
||||
# Push down position info.
|
||||
(map (def: listToAttrs (mapAttrsToList (n: def':
|
||||
{ name = n; value = { inherit (def) file; value = def'; }; }) def.value)) defs);
|
||||
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name>"]);
|
||||
};
|
||||
|
||||
# List or attribute set of ...
|
||||
loaOf = elemType:
|
||||
let
|
||||
convertIfList = defIdx: def:
|
||||
if isList def then
|
||||
listToAttrs (
|
||||
flip imap def (elemIdx: elem:
|
||||
nameValuePair "unnamed-${toString defIdx}.${toString elemIdx}" elem))
|
||||
if isList def.value then
|
||||
{ inherit (def) file;
|
||||
value = listToAttrs (
|
||||
imap (elemIdx: elem:
|
||||
{ name = "unnamed-${toString defIdx}.${toString elemIdx}";
|
||||
value = elem;
|
||||
}) def.value);
|
||||
}
|
||||
else
|
||||
def;
|
||||
listOnly = listOf elemType;
|
||||
attrOnly = attrsOf elemType;
|
||||
|
||||
in mkOptionType {
|
||||
name = "list or attribute set of ${elemType.name}s";
|
||||
check = x:
|
||||
if isList x then listOnly.check x
|
||||
else if isAttrs x then attrOnly.check x
|
||||
else lib.traceValIfNot (x: false) x;
|
||||
## The merge function returns an attribute set
|
||||
merge = defs:
|
||||
attrOnly.merge (imap convertIfList defs);
|
||||
iter = f: path: def:
|
||||
if isList def then listOnly.iter f path def
|
||||
else if isAttrs def then attrOnly.iter f path def
|
||||
else throw "Unexpected value";
|
||||
fold = op: nul: def:
|
||||
if isList def then listOnly.fold op nul def
|
||||
else if isAttrs def then attrOnly.fold op nul def
|
||||
else throw "Unexpected value";
|
||||
|
||||
docPath = path: elemType.docPath (path + ".<name?>");
|
||||
inherit (elemType) hasOptions delayOnGlobalEval;
|
||||
}
|
||||
;
|
||||
else false;
|
||||
merge = loc: defs: attrOnly.merge loc (imap convertIfList defs);
|
||||
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name?>"]);
|
||||
};
|
||||
|
||||
uniq = elemType: mkOptionType {
|
||||
inherit (elemType) name check iter fold docPath hasOptions;
|
||||
merge = list:
|
||||
if length list == 1 then
|
||||
head list
|
||||
else
|
||||
throw "Multiple definitions of ${elemType.name}. Only one is allowed for this option.";
|
||||
};
|
||||
|
||||
none = elemType: mkOptionType {
|
||||
inherit (elemType) name check iter fold docPath hasOptions;
|
||||
merge = list:
|
||||
throw "No definitions are allowed for this option.";
|
||||
inherit (elemType) name check;
|
||||
merge = mergeOneOption;
|
||||
getSubOptions = elemType.getSubOptions;
|
||||
};
|
||||
|
||||
nullOr = elemType: mkOptionType {
|
||||
inherit (elemType) name merge docPath hasOptions;
|
||||
name = "null or ${elemType.name}";
|
||||
check = x: builtins.isNull x || elemType.check x;
|
||||
iter = f: path: v: if v == null then v else elemType.iter f path v;
|
||||
fold = op: nul: v: if v == null then nul else elemType.fold op nul v;
|
||||
merge = loc: defs:
|
||||
let nrNulls = count (def: isNull def.value) defs; in
|
||||
if nrNulls == length defs then null
|
||||
else if nrNulls != 0 then
|
||||
throw "The option `${showOption loc}' is defined both null and not null, in ${showFiles (getFiles defs)}."
|
||||
else elemType.merge loc defs;
|
||||
getSubOptions = elemType.getSubOptions;
|
||||
};
|
||||
|
||||
functionTo = elemType: mkOptionType {
|
||||
name = "function that evaluates to a(n) ${elemType.name}";
|
||||
check = lib.traceValIfNot builtins.isFunction;
|
||||
merge = fns:
|
||||
args: elemType.merge (map (fn: fn args) fns);
|
||||
# These are guesses, I don't fully understand iter, fold, delayOnGlobalEval
|
||||
iter = f: path: v:
|
||||
args: elemType.iter f path (v args);
|
||||
fold = op: nul: v:
|
||||
args: elemType.fold op nul (v args);
|
||||
inherit (elemType) delayOnGlobalEval;
|
||||
hasOptions = false;
|
||||
check = builtins.isFunction;
|
||||
merge = loc: defs:
|
||||
fnArgs: elemType.merge loc (map (fn: { inherit (fn) file; value = fn.value fnArgs; }) defs);
|
||||
getSubOptions = elemType.getSubOptions;
|
||||
};
|
||||
|
||||
# usually used with listOf, attrsOf, loaOf like this:
|
||||
# users = mkOption {
|
||||
# type = loaOf optionSet;
|
||||
#
|
||||
# # you can omit the list if there is one element only
|
||||
# options = [ {
|
||||
# name = mkOption {
|
||||
# description = "name of the user"
|
||||
# ...
|
||||
# };
|
||||
# # more options here
|
||||
# } { more options } ];
|
||||
# }
|
||||
# TODO: !!! document passing options as an argument to optionSet,
|
||||
# deprecate the current approach.
|
||||
submodule = opts:
|
||||
let
|
||||
opts' = toList opts;
|
||||
inherit (import ./modules.nix) evalModules;
|
||||
in
|
||||
mkOptionType rec {
|
||||
name = "submodule";
|
||||
check = x: isAttrs x || builtins.isFunction x;
|
||||
merge = loc: defs:
|
||||
let
|
||||
coerce = def: if builtins.isFunction def then def else { config = def; };
|
||||
modules = opts' ++ map (def: { _file = def.file; imports = [(coerce def.value)]; }) defs;
|
||||
in (evalModules { inherit modules; args.name = last loc; prefix = loc; }).config;
|
||||
getSubOptions = prefix: (evalModules
|
||||
{ modules = opts'; inherit prefix;
|
||||
# FIXME: hack to get shit to evaluate.
|
||||
args = { name = ""; }; }).options;
|
||||
};
|
||||
|
||||
# Obsolete alternative to configOf. It takes its option
|
||||
# declarations from the ‘options’ attribute of containing option
|
||||
# declaration.
|
||||
optionSet = mkOptionType {
|
||||
name = "option set";
|
||||
# merge is done in "options.nix > addOptionMakeUp > handleOptionSets"
|
||||
merge = lib.id;
|
||||
check = x: isAttrs x || builtins.isFunction x;
|
||||
hasOptions = true;
|
||||
delayOnGlobalEval = true;
|
||||
name = /* builtins.trace "types.optionSet is deprecated; use types.submodule instead" */ "option set";
|
||||
};
|
||||
|
||||
# Augment the given type with an additional type check function.
|
||||
addCheck = elemType: check: elemType // { check = x: elemType.check x && check x; };
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ let
|
|||
modules = [ configuration ];
|
||||
};
|
||||
|
||||
inherit (eval) config pkgs;
|
||||
inherit (eval) pkgs;
|
||||
|
||||
# This is for `nixos-rebuild build-vm'.
|
||||
vmConfig = (import ./lib/eval-config.nix {
|
||||
|
@ -30,9 +30,9 @@ let
|
|||
in
|
||||
|
||||
{
|
||||
inherit eval config;
|
||||
inherit (eval) config options;
|
||||
|
||||
system = config.system.build.toplevel;
|
||||
system = eval.config.system.build.toplevel;
|
||||
|
||||
vm = vmConfig.system.build.vm;
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<para>This chapter describes how to configure various aspects of a
|
||||
NixOS machine through the configuration file
|
||||
<filename>/etc/nixos/configuration.nix</filename>. As described in
|
||||
<xref linkend="sec-changing-config" />, changes to that file only take
|
||||
<xref linkend="sec-changing-config" />, changes to this file only take
|
||||
effect after you run <command>nixos-rebuild</command>.</para>
|
||||
|
||||
|
||||
|
@ -15,7 +15,703 @@ effect after you run <command>nixos-rebuild</command>.</para>
|
|||
|
||||
<section xml:id="sec-configuration-syntax"><title>Configuration syntax</title>
|
||||
|
||||
<para>TODO</para>
|
||||
<section><title>The basics</title>
|
||||
|
||||
<para>The NixOS configuration file
|
||||
<filename>/etc/nixos/configuration.nix</filename> is actually a
|
||||
<emphasis>Nix expression</emphasis>, which is the Nix package
|
||||
manager’s 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 doesn’t exist (that is,
|
||||
doesn’t 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 it’s 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 NixOS’s 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, it’s 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>, that’s 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, it’s 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 you’re
|
||||
wondering how it’s possible that the (indirect)
|
||||
<emphasis>result</emphasis> of a function is passed as an
|
||||
<emphasis>input</emphasis> to that same function: that’s 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. It’s not installed by
|
||||
default; run <literal>nix-env -i nix-repl</literal> to get it. A
|
||||
typical use:
|
||||
|
||||
<screen>
|
||||
$ nix-repl '<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. It’s not complete. In particular, there
|
||||
are many other built-in functions. See the <link
|
||||
xlink:href="http://nixos.org/nix/manual/#chap-writing-nix-expressions">Nix
|
||||
manual</link> for the rest.</para>
|
||||
|
||||
<informaltable frame='none'>
|
||||
<tgroup cols='2'>
|
||||
<colspec colname='c1' rowsep='1' colsep='1' />
|
||||
<colspec colname='c2' rowsep='1' />
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Example</entry>
|
||||
<entry>Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
<row>
|
||||
<entry namest="c1" nameend="c2"><emphasis>Basic values</emphasis></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>"Hello world"</literal></entry>
|
||||
<entry>A string</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>"${pkgs.bash}/bin/sh"</literal></entry>
|
||||
<entry>A string containing an expression (expands to <literal>"/nix/store/<replaceable>hash</replaceable>-bash-<replaceable>version</replaceable>/bin/sh"</literal>)</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>true</literal>, <literal>false</literal></entry>
|
||||
<entry>Booleans</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>123</literal></entry>
|
||||
<entry>An integer</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>./foo.png</literal></entry>
|
||||
<entry>A path (relative to the containing Nix expression)</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry namest="c1" nameend="c2"><emphasis>Compound values</emphasis></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>{ x = 1; y = 2; }</literal></entry>
|
||||
<entry>An set with attributes names <literal>x</literal> and <literal>y</literal></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>{ foo.bar = 1; }</literal></entry>
|
||||
<entry>A nested set, equivalent to <literal>{ foo = { bar = 1; }; }</literal></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>rec { x = "bla"; y = x + "bar"; }</literal></entry>
|
||||
<entry>A recursive set, equivalent to <literal>{ x = "foo"; y = "foobar"; }</literal></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>[ "foo" "bar" ]</literal></entry>
|
||||
<entry>A list with two elements</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry namest="c1" nameend="c2"><emphasis>Operators</emphasis></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>"foo" + "bar"</literal></entry>
|
||||
<entry>String concatenation</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>1 + 2</literal></entry>
|
||||
<entry>Integer addition</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>"foo" == "f" + "oo"</literal></entry>
|
||||
<entry>Equality test (evaluates to <literal>true</literal>)</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>"foo" != "bar"</literal></entry>
|
||||
<entry>Inequality test (evaluates to <literal>true</literal>)</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>!true</literal></entry>
|
||||
<entry>Boolean negation</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>{ x = 1; y = 2; }.x</literal></entry>
|
||||
<entry>Attribute selection (evaluates to <literal>1</literal>)</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>{ x = 1; y = 2; }.z or 3</literal></entry>
|
||||
<entry>Attribute selection with default (evaluates to <literal>3</literal>)</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>{ x = 1; y = 2; } // { z = 3; }</literal></entry>
|
||||
<entry>Merge two sets (attributes in the right-hand set taking precedence)</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry namest="c1" nameend="c2"><emphasis>Control structures</emphasis></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>if 1 + 1 == 2 then "yes!" else "no!"</literal></entry>
|
||||
<entry>Conditional expression</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>assert 1 + 1 == 2; "yes!"</literal></entry>
|
||||
<entry>Assertion check (evaluates to <literal>"yes!"</literal>)</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>let x = "foo"; y = "bar"; in x + y</literal></entry>
|
||||
<entry>Variable definition</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>with pkgs.lib; head [ 1 2 3 ]</literal></entry>
|
||||
<entry>Add all attributes from the given set to the scope
|
||||
(evaluates to <literal>1</literal>)</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry namest="c1" nameend="c2"><emphasis>Functions (lambdas)</emphasis></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>x: x + 1</literal></entry>
|
||||
<entry>A function that expects an integer and returns it increased by 1</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>(x: x + 1) 100</literal></entry>
|
||||
<entry>A function call (evaluates to 101)</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>let inc = x: x + 1; in inc (inc (inc 100))</literal></entry>
|
||||
<entry>A function bound to a variable and subsequently called by name (evaluates to 103)</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>{ x, y }: x + y</literal></entry>
|
||||
<entry>A function that expects a set with required attributes
|
||||
<literal>x</literal> and <literal>y</literal> and concatenates
|
||||
them</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>{ x, y ? "bar" }: x + y</literal></entry>
|
||||
<entry>A function that expects a set with required attribute
|
||||
<literal>x</literal> and optional <literal>y</literal>, using
|
||||
<literal>"bar"</literal> as default value for
|
||||
<literal>y</literal></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>{ x, y, ... }: x + y</literal></entry>
|
||||
<entry>A function that expects a set with required attributes
|
||||
<literal>x</literal> and <literal>y</literal> and ignores any
|
||||
other attributes</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>{ x, y } @ args: x + y</literal></entry>
|
||||
<entry>A function that expects a set with required attributes
|
||||
<literal>x</literal> and <literal>y</literal>, and binds the
|
||||
whole set to <literal>args</literal></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry namest="c1" nameend="c2"><emphasis>Built-in functions</emphasis></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>import ./foo.nix</literal></entry>
|
||||
<entry>Load and return Nix expression in given file</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>map (x: x + x) [ 1 2 3 ]</literal></entry>
|
||||
<entry>Apply a function to every element of a list (evaluates to <literal>[ 2 4 6 ]</literal>)</entry>
|
||||
</row>
|
||||
<!--
|
||||
<row>
|
||||
<entry><literal>throw "Urgh"</literal></entry>
|
||||
<entry>Raise an error condition</entry>
|
||||
</row>
|
||||
-->
|
||||
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
|
@ -170,7 +866,7 @@ recursion.)</para>
|
|||
|
||||
</section>
|
||||
|
||||
<section><title>Adding custom packages</title>
|
||||
<section xml:id="sec-custom-packages"><title>Adding custom packages</title>
|
||||
|
||||
<para>It’s possible that a package you need is not available in NixOS.
|
||||
In that case, you can do two things. First, you can clone the Nixpkgs
|
||||
|
@ -316,7 +1012,7 @@ manpage or the Nix manual.</para>
|
|||
|
||||
<!--===============================================================-->
|
||||
|
||||
<section><title>User management</title>
|
||||
<section xml:id="sec-user-management"><title>User management</title>
|
||||
|
||||
<para>NixOS supports both declarative and imperative styles of user
|
||||
management. In the declarative style, users are specified in
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -18,6 +18,33 @@ details, see the <link
|
|||
xlink:href="https://nixos.org/wiki/Installing_NixOS_from_a_USB_stick">NixOS
|
||||
Wiki</link>.</para>
|
||||
|
||||
<para>As an alternative to installing NixOS yourself, you can get a
|
||||
running NixOS system through several other means:
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Using virtual appliances in Open Virtualization Format (OVF)
|
||||
that can be imported into VirtualBox. These are available from
|
||||
the <link xlink:href="http://nixos.org/nixos/download.html">NixOS
|
||||
homepage</link>.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Using AMIs for Amazon’s EC2. To find one for your region
|
||||
and instance type, please refer to the <link
|
||||
xlink:href="https://github.com/NixOS/nixops/blob/master/nix/ec2-amis.nix">list
|
||||
of most recent AMIs</link>.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Using NixOps, the NixOS-based cloud deployment tool, which
|
||||
allows you to provision VirtualBox and EC2 NixOS instances from
|
||||
declarative specifications. Check out the <link
|
||||
xlink:href="https://github.com/NixOS/nixops">NixOps
|
||||
homepage</link> for details.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
@ -62,9 +89,14 @@ Wiki</link>.</para>
|
|||
<listitem><para>For initialising Ext4 partitions:
|
||||
<command>mkfs.ext4</command>. It is recommended that you assign a
|
||||
unique symbolic label to the file system using the option
|
||||
<option>-L <replaceable>label</replaceable></option>. This will
|
||||
make the file system configuration independent from device
|
||||
changes.</para></listitem>
|
||||
<option>-L <replaceable>label</replaceable></option>, since this
|
||||
makes the file system configuration independent from device
|
||||
changes. For example:
|
||||
|
||||
<screen>
|
||||
$ mkfs.ext4 -L nixos /dev/sda1</screen>
|
||||
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>For creating swap partitions:
|
||||
<command>mkswap</command>. Again it’s recommended to assign a
|
||||
|
@ -97,6 +129,12 @@ $ mount /dev/disk/by-label/nixos /mnt
|
|||
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>If your machine has a limited amount of memory, you
|
||||
may want to activate swap devices now (<command>swapon
|
||||
<replaceable>device</replaceable></command>). The installer (or
|
||||
rather, the build actions that it may spawn) may need quite a bit of
|
||||
RAM, depending on your configuration.</para></listitem>
|
||||
|
||||
<listitem>
|
||||
|
||||
<para>You now need to create a file
|
||||
|
@ -161,28 +199,16 @@ $ nano /mnt/etc/nixos/configuration.nix
|
|||
|
||||
</listitem>
|
||||
|
||||
<listitem><para>If your machine has a limited amount of memory, you
|
||||
may want to activate swap devices now (<command>swapon
|
||||
<replaceable>device</replaceable></command>). The installer (or
|
||||
rather, the build actions that it may spawn) may need quite a bit of
|
||||
RAM, depending on your configuration.</para></listitem>
|
||||
|
||||
<!--
|
||||
<listitem><para>Optionally, you can run
|
||||
|
||||
<screen>
|
||||
$ nixos-checkout</screen>
|
||||
|
||||
to make the installer use the latest NixOS/Nixpkgs sources from the
|
||||
Git repository, rather than the sources on CD.</para></listitem>
|
||||
-->
|
||||
|
||||
<listitem><para>Do the installation:
|
||||
|
||||
<screen>
|
||||
$ nixos-install</screen>
|
||||
|
||||
Cross fingers.</para></listitem>
|
||||
Cross fingers. If this fails due to a temporary problem (such as
|
||||
a network issue while downloading binaries from the NixOS binary
|
||||
cache), you can just re-run <command>nixos-install</command>.
|
||||
Otherwise, fix your <filename>configuration.nix</filename> and
|
||||
then re-run <command>nixos-install</command>.</para></listitem>
|
||||
|
||||
<listitem><para>If everything went well:
|
||||
|
||||
|
@ -194,7 +220,7 @@ $ reboot</screen>
|
|||
<listitem>
|
||||
|
||||
<para>You should now be able to boot into the installed NixOS.
|
||||
The Grub boot menu shows a list of <emphasis>available
|
||||
The GRUB boot menu shows a list of <emphasis>available
|
||||
configurations</emphasis> (initially just one). Every time you
|
||||
change the NixOS configuration (see <xref
|
||||
linkend="sec-changing-config" />), a new item appears in the menu.
|
||||
|
@ -229,26 +255,28 @@ $ nix-env -i w3m</screen>
|
|||
|
||||
</orderedlist>
|
||||
|
||||
<para><xref linkend="ex-install-sequence" /> shows a typical sequence
|
||||
of commands for installing NixOS on an empty hard drive (here
|
||||
<filename>/dev/sda</filename>). <xref linkend="ex-config" /> shows a
|
||||
corresponding configuration Nix expression.</para>
|
||||
<para>To summarise, <xref linkend="ex-install-sequence" /> shows a
|
||||
typical sequence of commands for installing NixOS on an empty hard
|
||||
drive (here <filename>/dev/sda</filename>). <xref linkend="ex-config"
|
||||
/> shows a corresponding configuration Nix expression.</para>
|
||||
|
||||
<example xml:id='ex-install-sequence'><title>Commands for installing NixOS on <filename>/dev/sda</filename></title>
|
||||
<screen>
|
||||
$ fdisk /dev/sda <lineannotation>(or whatever device you want to install on)</lineannotation>
|
||||
$ mkfs.ext4 -L nixos /dev/sda1 <lineannotation>(idem)</lineannotation>
|
||||
$ mkswap -L swap /dev/sda2 <lineannotation>(idem)</lineannotation>
|
||||
$ mount LABEL=nixos /mnt
|
||||
$ nixos-generate-config
|
||||
$ fdisk /dev/sda # <lineannotation>(or whatever device you want to install on)</lineannotation>
|
||||
$ mkfs.ext4 -L nixos /dev/sda1
|
||||
$ mkswap -L swap /dev/sda2
|
||||
$ swapon /dev/sda2
|
||||
$ mount /dev/disk/by-label/nixos /mnt
|
||||
$ nixos-generate-config --root /mnt
|
||||
$ nano /mnt/etc/nixos/configuration.nix
|
||||
<lineannotation>(in particular, set the fileSystems and swapDevices options)</lineannotation>
|
||||
$ nixos-install
|
||||
$ reboot</screen>
|
||||
</example>
|
||||
|
||||
<example xml:id='ex-config'><title>NixOS configuration</title>
|
||||
<screen>
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
imports =
|
||||
[ # Include the results of the hardware scan.
|
||||
|
@ -257,14 +285,12 @@ $ reboot</screen>
|
|||
|
||||
boot.loader.grub.device = "/dev/sda";
|
||||
|
||||
# Note: setting fileSystems and swapDevices is generally not
|
||||
# necessary, since nixos-generate-config has set them automatically
|
||||
# in hardware-configuration.nix.
|
||||
fileSystems."/".device = "/dev/disk/by-label/nixos";
|
||||
|
||||
swapDevices =
|
||||
[ { device = "/dev/disk/by-label/swap"; } ];
|
||||
# Note: setting fileSystems is generally not
|
||||
# necessary, since nixos-generate-config figures them out
|
||||
# automatically in hardware-configuration.nix.
|
||||
#fileSystems."/".device = "/dev/disk/by-label/nixos";
|
||||
|
||||
# Enable the OpenSSH server.
|
||||
services.sshd.enable = true;
|
||||
}</screen>
|
||||
</example>
|
||||
|
@ -290,6 +316,10 @@ to build the new configuration, make it the default configuration for
|
|||
booting, and try to realise the configuration in the running system
|
||||
(e.g., by restarting system services).</para>
|
||||
|
||||
<warning><para>These commands must be executed as root, so you should
|
||||
either run them from a root shell or by prefixing them with
|
||||
<literal>sudo -i</literal>.</para></warning>
|
||||
|
||||
<para>You can also do
|
||||
|
||||
<screen>
|
||||
|
@ -309,6 +339,18 @@ to build the configuration and make it the boot default, but not
|
|||
switch to it now (so it will only take effect after the next
|
||||
reboot).</para>
|
||||
|
||||
<para>You can make your configuration show up in a different submenu
|
||||
of the GRUB 2 boot screen by giving it a different <emphasis>profile
|
||||
name</emphasis>, e.g.
|
||||
|
||||
<screen>
|
||||
$ nixos-rebuild switch -p test </screen>
|
||||
|
||||
which causes the new configuration (and previous ones created using
|
||||
<literal>-p test</literal>) to show up in the GRUB submenu “NixOS -
|
||||
Profile 'test'”. This can be useful to separate test configurations
|
||||
from “stable” configurations.</para>
|
||||
|
||||
<para>Finally, you can do
|
||||
|
||||
<screen>
|
||||
|
@ -319,7 +361,7 @@ whether everything compiles cleanly.</para>
|
|||
|
||||
<para>If you have a machine that supports hardware virtualisation, you
|
||||
can also test the new configuration in a sandbox by building and
|
||||
running a <emphasis>virtual machine</emphasis> that contains the
|
||||
running a QEMU <emphasis>virtual machine</emphasis> that contains the
|
||||
desired configuration. Just do
|
||||
|
||||
<screen>
|
||||
|
@ -334,7 +376,6 @@ available.</para>
|
|||
</section>
|
||||
|
||||
|
||||
|
||||
<!--===============================================================-->
|
||||
|
||||
<section xml:id="sec-upgrading">
|
||||
|
@ -342,28 +383,86 @@ available.</para>
|
|||
<title>Upgrading NixOS</title>
|
||||
|
||||
<para>The best way to keep your NixOS installation up to date is to
|
||||
use the <literal>nixos-unstable</literal> channel. (A channel is a
|
||||
use one of the NixOS <emphasis>channels</emphasis>. A channel is a
|
||||
Nix mechanism for distributing Nix expressions and associated
|
||||
binaries.) The NixOS channel is updated automatically from NixOS’s
|
||||
Git repository after running certain tests and building most
|
||||
packages.</para>
|
||||
binaries. The NixOS channels are updated automatically from NixOS’s
|
||||
Git repository after certain tests have passed and all packages have
|
||||
been built. These channels are:
|
||||
|
||||
<para>NixOS automatically subscribes you to the NixOS channel. If for
|
||||
some reason this is not the case, just do
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Stable channels, such as <literal
|
||||
xlink:href="http://nixos.org/channels/nixos-13.10">nixos-13.10</literal>.
|
||||
These only get conservative bug fixes and package upgrades. For
|
||||
instance, a channel update may cause the Linux kernel on your
|
||||
system to be upgraded from 3.4.66 to 3.4.67 (a minor bug fix), but
|
||||
not from 3.4.<replaceable>x</replaceable> to
|
||||
3.11.<replaceable>x</replaceable> (a major change that has the
|
||||
potential to break things). Stable channels are generally
|
||||
maintained until the next stable branch is created.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>The unstable channel, <literal
|
||||
xlink:href="http://nixos.org/channels/nixos-unstable">nixos-unstable</literal>.
|
||||
This corresponds to NixOS’s main development branch, and may thus
|
||||
see radical changes between channel updates. It’s 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 channel’s
|
||||
latest version and includes ISO images and VirtualBox
|
||||
appliances.)</para>
|
||||
|
||||
<para>When you first install NixOS, you’re 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 you’re subscribed to, run the following as root:
|
||||
|
||||
<screen>
|
||||
$ nix-channel --add http://nixos.org/channels/nixos-unstable
|
||||
$ nix-channel --list | grep nixos
|
||||
nixos https://nixos.org/channels/nixos-unstable
|
||||
</screen>
|
||||
|
||||
You can then upgrade NixOS to the latest version in the channel by
|
||||
running
|
||||
To switch to a different NixOS channel, do
|
||||
|
||||
<screen>
|
||||
$ nix-channel --update nixos
|
||||
$ nix-channel --add http://nixos.org/channels/<replaceable>channel-name</replaceable> nixos
|
||||
</screen>
|
||||
|
||||
and running the <command>nixos-rebuild</command> command as described
|
||||
in <xref linkend="sec-changing-config"/>.</para>
|
||||
(Be sure to include the <literal>nixos</literal> parameter at the
|
||||
end.) For instance, to use the NixOS 13.10 stable channel:
|
||||
|
||||
<screen>
|
||||
$ nix-channel --add http://nixos.org/channels/nixos-13.10 nixos
|
||||
</screen>
|
||||
|
||||
But it you want to live on the bleeding edge:
|
||||
|
||||
<screen>
|
||||
$ nix-channel --add http://nixos.org/channels/nixos-unstable nixos
|
||||
</screen>
|
||||
|
||||
</para>
|
||||
|
||||
<para>You can then upgrade NixOS to the latest version in your chosen
|
||||
channel by running
|
||||
|
||||
<screen>
|
||||
$ nixos-rebuild switch --upgrade
|
||||
</screen>
|
||||
|
||||
which is equivalent to the more verbose <literal>nix-channel --update
|
||||
nixos; nixos-rebuild switch</literal>.</para>
|
||||
|
||||
<warning><para>It is generally safe to switch back and forth between
|
||||
channels. The only exception is that a newer NixOS may also have a
|
||||
newer Nix version, which may involve an upgrade of Nix’s 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>
|
||||
|
||||
|
|
|
@ -36,23 +36,15 @@
|
|||
select="attr[@name = 'description']/string/@value" />
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<emphasis>Default:</emphasis>
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:choose>
|
||||
<xsl:when test="attr[@name = 'default']">
|
||||
<literal>
|
||||
<xsl:apply-templates select="attr[@name = 'default']" />
|
||||
</literal>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
none
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</para>
|
||||
<xsl:if test="attr[@name = 'default']">
|
||||
<para>
|
||||
<emphasis>Default:</emphasis>
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:apply-templates select="attr[@name = 'default']" mode="top" />
|
||||
</para>
|
||||
</xsl:if>
|
||||
|
||||
<xsl:if test="attr[@name = 'example']">
|
||||
|
||||
<para>
|
||||
<emphasis>Example:</emphasis>
|
||||
<xsl:text> </xsl:text>
|
||||
|
@ -61,9 +53,7 @@
|
|||
<programlisting><xsl:value-of select="attr[@name = 'example']/attrs/attr[@name = 'text']/string/@value" /></programlisting>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<literal>
|
||||
<xsl:apply-templates select="attr[@name = 'example']" />
|
||||
</literal>
|
||||
<xsl:apply-templates select="attr[@name = 'example']" mode="top" />
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</para>
|
||||
|
@ -94,9 +84,34 @@
|
|||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="*" mode="top">
|
||||
<xsl:choose>
|
||||
<xsl:when test="string[contains(@value, '
')]">
|
||||
<programlisting>
|
||||
<xsl:text>''
|
||||
</xsl:text><xsl:value-of select='str:replace(string/@value, "${", "''${")' /><xsl:text>''</xsl:text></programlisting>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<literal><xsl:apply-templates /></literal>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="null">
|
||||
<xsl:text>null</xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="string">
|
||||
<!-- !!! escaping -->
|
||||
<xsl:text>"</xsl:text><xsl:value-of select="str:replace(str:replace(str:replace(@value, '\', '\\'), '"', '\"'), '
', '\n')" /><xsl:text>"</xsl:text>
|
||||
<xsl:choose>
|
||||
<xsl:when test="(contains(@value, '"') or contains(@value, '\')) and not(contains(@value, '
'))">
|
||||
<xsl:text>''</xsl:text><xsl:value-of select='str:replace(@value, "${", "''${")' /><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, '\', '\\'), '"', '\"'), '
', '\n'), '$', '\$')" /><xsl:text>"</xsl:text>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
|
@ -142,14 +157,7 @@
|
|||
|
||||
|
||||
<xsl:template match="derivation">
|
||||
<xsl:choose>
|
||||
<xsl:when test="attr[@name = 'url']/string/@value">
|
||||
<replaceable>(download of <xsl:value-of select="attr[@name = 'url']/string/@value" />)</replaceable>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<replaceable>(build of <xsl:value-of select="attr[@name = 'name']/string/@value" />)</replaceable>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
<replaceable>(build of <xsl:value-of select="attr[@name = 'name']/string/@value" />)</replaceable>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="attr[@name = 'declarations' or @name = 'definitions']">
|
||||
|
|
|
@ -7,23 +7,20 @@
|
|||
, baseModules ? import ../modules/module-list.nix
|
||||
, extraArgs ? {}
|
||||
, modules
|
||||
, check ? true
|
||||
}:
|
||||
|
||||
let extraArgs_ = extraArgs; pkgs_ = pkgs; system_ = system; in
|
||||
|
||||
rec {
|
||||
|
||||
# These are the NixOS modules that constitute the system configuration.
|
||||
configComponents = modules ++ baseModules;
|
||||
|
||||
# Merge the option definitions in all modules, forming the full
|
||||
# system configuration. It's not checked for undeclared options.
|
||||
systemModule =
|
||||
pkgs.lib.fixMergeModules configComponents extraArgs;
|
||||
|
||||
optionDefinitions = systemModule.config;
|
||||
optionDeclarations = systemModule.options;
|
||||
inherit (systemModule) options;
|
||||
# system configuration.
|
||||
inherit (pkgs.lib.evalModules {
|
||||
modules = modules ++ baseModules;
|
||||
args = extraArgs;
|
||||
check = check && options.environment.checkConfigurationOptions.value;
|
||||
}) config options;
|
||||
|
||||
# These are the extra arguments passed to every module. In
|
||||
# particular, Nixpkgs is passed through the "pkgs" argument.
|
||||
|
@ -56,16 +53,12 @@ rec {
|
|||
# define nixpkgs.config, so it's pointless to evaluate them.
|
||||
baseModules = [ ../modules/misc/nixpkgs.nix ];
|
||||
pkgs = import ./nixpkgs.nix { system = system_; config = {}; };
|
||||
}).optionDefinitions.nixpkgs;
|
||||
check = false;
|
||||
}).config.nixpkgs;
|
||||
in
|
||||
{
|
||||
inherit system;
|
||||
inherit (nixpkgsOptions) config;
|
||||
});
|
||||
|
||||
# Optionally check wether all config values have corresponding
|
||||
# option declarations.
|
||||
config =
|
||||
assert optionDefinitions.environment.checkConfigurationOptions -> pkgs.lib.checkModule "" systemModule;
|
||||
systemModule.config;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ with pkgs.lib;
|
|||
fonts = {
|
||||
|
||||
enableFontConfig = mkOption { # !!! should be enableFontconfig
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
If enabled, a Fontconfig configuration file will be built
|
||||
|
|
|
@ -5,6 +5,7 @@ with pkgs.lib;
|
|||
{
|
||||
options = {
|
||||
gnu = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description =
|
||||
'' When enabled, GNU software is chosen by default whenever a there is
|
||||
|
|
|
@ -18,16 +18,18 @@ in
|
|||
|
||||
i18n = {
|
||||
defaultLocale = mkOption {
|
||||
type = types.str;
|
||||
default = "en_US.UTF-8";
|
||||
example = "nl_NL.UTF-8";
|
||||
description = "
|
||||
description = ''
|
||||
The default locale. It determines the language for program
|
||||
messages, the format for dates and times, sort order, and so on.
|
||||
It also determines the character set, such as UTF-8.
|
||||
";
|
||||
'';
|
||||
};
|
||||
|
||||
supportedLocales = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = ["all"];
|
||||
example = ["en_US.UTF-8/UTF-8" "nl_NL.UTF-8/UTF-8" "nl_NL/ISO-8859-1"];
|
||||
description = ''
|
||||
|
@ -40,22 +42,23 @@ in
|
|||
};
|
||||
|
||||
consoleFont = mkOption {
|
||||
type = types.str;
|
||||
default = "lat9w-16";
|
||||
example = "LatArCyrHeb-16";
|
||||
description = "
|
||||
description = ''
|
||||
The font used for the virtual consoles. Leave empty to use
|
||||
whatever the <command>setfont</command> program considers the
|
||||
default font.
|
||||
";
|
||||
'';
|
||||
};
|
||||
|
||||
consoleKeyMap = mkOption {
|
||||
type = types.str;
|
||||
default = "us";
|
||||
example = "fr";
|
||||
description = "
|
||||
description = ''
|
||||
The keyboard mapping table for the virtual consoles.
|
||||
";
|
||||
type = types.uniq types.string;
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -15,6 +15,7 @@ in
|
|||
options = {
|
||||
|
||||
networking.extraHosts = pkgs.lib.mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
example = "192.168.0.1 lanlocalhost";
|
||||
description = ''
|
||||
|
@ -23,6 +24,7 @@ in
|
|||
};
|
||||
|
||||
networking.dnsSingleRequest = pkgs.lib.mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Recent versions of glibc will issue both ipv4 (A) and ipv6 (AAAA)
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
{
|
||||
options = {
|
||||
environment.noXlibs = pkgs.lib.mkOption {
|
||||
environment.noXlibs = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = ''
|
||||
Switch off the options in the default configuration that require X libraries.
|
||||
Currently this includes: ssh X11 forwarding, dbus, fonts.enableCoreFonts,
|
||||
|
@ -13,7 +15,7 @@
|
|||
};
|
||||
};
|
||||
|
||||
config = pkgs.lib.mkIf config.environment.noXlibs {
|
||||
config = mkIf config.environment.noXlibs {
|
||||
programs.ssh.setXAuthLocation = false;
|
||||
fonts = {
|
||||
enableCoreFonts = false;
|
||||
|
|
|
@ -16,6 +16,7 @@ in
|
|||
|
||||
# NSS modules. Hacky!
|
||||
system.nssModules = mkOption {
|
||||
type = types.listOf types.path;
|
||||
internal = true;
|
||||
default = [];
|
||||
description = ''
|
||||
|
@ -23,7 +24,6 @@ in
|
|||
several DNS resolution methods to be specified via
|
||||
<filename>/etc/nsswitch.conf</filename>.
|
||||
'';
|
||||
merge = mergeListOption;
|
||||
apply = list:
|
||||
{
|
||||
inherit list;
|
||||
|
|
|
@ -17,6 +17,7 @@ in
|
|||
powerManagement = {
|
||||
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description =
|
||||
''
|
||||
|
@ -26,11 +27,13 @@ in
|
|||
};
|
||||
|
||||
resumeCommands = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = "Commands executed after the system resumes from suspend-to-RAM.";
|
||||
};
|
||||
|
||||
powerUpCommands = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
example = "${pkgs.hdparm}/sbin/hdparm -B 255 /dev/sda";
|
||||
description =
|
||||
|
@ -42,6 +45,7 @@ in
|
|||
};
|
||||
|
||||
powerDownCommands = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
example = "${pkgs.hdparm}/sbin/hdparm -B 255 /dev/sda";
|
||||
description =
|
||||
|
|
|
@ -46,6 +46,7 @@ in {
|
|||
|
||||
hardware.pulseaudio = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to enable the PulseAudio sound server.
|
||||
|
@ -72,12 +73,13 @@ in {
|
|||
The path to the configuration the PulseAudio server
|
||||
should use. By default, the "default.pa" configuration
|
||||
from the PulseAudio distribution is used.
|
||||
'';
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
package = mkOption {
|
||||
type = types.path;
|
||||
default = pulseaudio;
|
||||
example = "pulseaudio.override { jackaudioSupport = true; }";
|
||||
example = literalExample "pulseaudio.override { jackaudioSupport = true; }";
|
||||
description = ''
|
||||
The PulseAudio derivation to use. This can be used to enable
|
||||
features (such as JACK support) that are not enabled in the
|
||||
|
@ -125,9 +127,9 @@ in {
|
|||
description = "PulseAudio system service user";
|
||||
home = pulseRuntimePath;
|
||||
};
|
||||
|
||||
|
||||
users.extraGroups.pulse.gid = gid;
|
||||
|
||||
|
||||
systemd.services.pulseaudio = {
|
||||
description = "PulseAudio system-wide server";
|
||||
wantedBy = [ "sound.target" ];
|
||||
|
|
|
@ -25,12 +25,17 @@ in
|
|||
'';
|
||||
type = types.attrsOf (mkOptionType {
|
||||
name = "a string or a list of strings";
|
||||
merge = xs:
|
||||
let xs' = evalProperties xs; in
|
||||
if isList (head xs') then concatLists xs'
|
||||
else if builtins.lessThan 1 (length xs') then abort "variable in ‘environment.variables’ has multiple values"
|
||||
else if !builtins.isString (head xs') then abort "variable in ‘environment.variables’ does not have a string value"
|
||||
else head xs';
|
||||
merge = loc: defs:
|
||||
let
|
||||
defs' = filterOverrides defs;
|
||||
res = (head defs').value;
|
||||
in
|
||||
if isList res then concatLists (getValues defs')
|
||||
else if builtins.lessThan 1 (length defs') then
|
||||
throw "The option `${showOption loc}' is defined multiple times, in ${showFiles (getFiles defs)}."
|
||||
else if !builtins.isString res then
|
||||
throw "The option `${showOption loc}' does not have a string value, in ${showFiles (getFiles defs)}."
|
||||
else res;
|
||||
});
|
||||
apply = mapAttrs (n: v: if isList v then concatStringsSep ":" v else v);
|
||||
};
|
||||
|
|
|
@ -34,13 +34,13 @@ with utils;
|
|||
|
||||
device = mkOption {
|
||||
example = "/dev/sda3";
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
description = "Path of the device.";
|
||||
};
|
||||
|
||||
label = mkOption {
|
||||
example = "swap";
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
Label of the device. Can be used instead of <varname>device</varname>.
|
||||
'';
|
||||
|
@ -72,11 +72,8 @@ with utils;
|
|||
};
|
||||
|
||||
config = {
|
||||
device =
|
||||
if options.label.isDefined then
|
||||
"/dev/disk/by-label/${config.label}"
|
||||
else
|
||||
mkNotdef;
|
||||
device = mkIf options.label.isDefined
|
||||
"/dev/disk/by-label/${config.label}";
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -7,7 +7,7 @@ let
|
|||
sysctlOption = mkOptionType {
|
||||
name = "sysctl option value";
|
||||
check = x: builtins.isBool x || builtins.isString x || builtins.isInt x;
|
||||
merge = xs: last xs; # FIXME: hacky way to allow overriding in configuration.nix.
|
||||
merge = args: defs: (last defs).value; # FIXME: hacky way to allow overriding in configuration.nix.
|
||||
};
|
||||
|
||||
in
|
||||
|
|
|
@ -14,7 +14,7 @@ let
|
|||
'';
|
||||
|
||||
requiredPackages =
|
||||
[ config.environment.nix
|
||||
[ config.nix.package
|
||||
pkgs.acl
|
||||
pkgs.attr
|
||||
pkgs.bashInteractive # bash with ncurses support
|
||||
|
@ -60,6 +60,7 @@ in
|
|||
environment = {
|
||||
|
||||
systemPackages = mkOption {
|
||||
type = types.listOf types.path;
|
||||
default = [];
|
||||
example = "[ pkgs.icecat3 pkgs.thunderbird ]";
|
||||
description = ''
|
||||
|
@ -74,6 +75,7 @@ in
|
|||
};
|
||||
|
||||
pathsToLink = mkOption {
|
||||
type = types.listOf types.str;
|
||||
# Note: We need `/lib' to be among `pathsToLink' for NSS modules
|
||||
# to work.
|
||||
default = [];
|
||||
|
@ -122,7 +124,7 @@ in
|
|||
postBuild =
|
||||
''
|
||||
if [ -x $out/bin/update-mime-database -a -w $out/share/mime/packages ]; then
|
||||
$out/bin/update-mime-database -V $out/share/mime
|
||||
XDG_DATA_DIRS=$out/share $out/bin/update-mime-database -V $out/share/mime > /dev/null
|
||||
fi
|
||||
|
||||
if [ -x $out/bin/gtk-update-icon-cache -a -f $out/share/icons/hicolor/index.theme ]; then
|
||||
|
|
|
@ -9,7 +9,7 @@ with pkgs.lib;
|
|||
|
||||
timeZone = mkOption {
|
||||
default = "CET";
|
||||
type = with types; uniq string;
|
||||
type = types.str;
|
||||
example = "America/New_York";
|
||||
description = "The time zone used when displaying times and dates.";
|
||||
};
|
||||
|
|
|
@ -12,14 +12,19 @@ let
|
|||
options = {
|
||||
|
||||
name = mkOption {
|
||||
type = with types; uniq string;
|
||||
type = types.str;
|
||||
description = "The name of the user account. If undefined, the name of the attribute set will be used.";
|
||||
};
|
||||
|
||||
description = mkOption {
|
||||
type = with types; uniq string;
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "A short description of the user account.";
|
||||
example = "Alice Q. User";
|
||||
description = ''
|
||||
A short description of the user account, typically the
|
||||
user's full name. This is actually the “GECOS” or “comment”
|
||||
field in <filename>/etc/passwd</filename>.
|
||||
'';
|
||||
};
|
||||
|
||||
uid = mkOption {
|
||||
|
@ -29,25 +34,25 @@ let
|
|||
};
|
||||
|
||||
group = mkOption {
|
||||
type = with types; uniq string;
|
||||
type = types.str;
|
||||
default = "nogroup";
|
||||
description = "The user's primary group.";
|
||||
};
|
||||
|
||||
extraGroups = mkOption {
|
||||
type = types.listOf types.string;
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = "The user's auxiliary groups.";
|
||||
};
|
||||
|
||||
home = mkOption {
|
||||
type = with types; uniq string;
|
||||
type = types.str;
|
||||
default = "/var/empty";
|
||||
description = "The user's home directory.";
|
||||
};
|
||||
|
||||
shell = mkOption {
|
||||
type = with types; uniq string;
|
||||
type = types.str;
|
||||
default = "/run/current-system/sw/sbin/nologin";
|
||||
description = "The path to the user's shell.";
|
||||
};
|
||||
|
@ -65,9 +70,15 @@ let
|
|||
};
|
||||
|
||||
password = mkOption {
|
||||
type = with types; uniq (nullOr string);
|
||||
type = with types; uniq (nullOr str);
|
||||
default = null;
|
||||
description = "The user's password. If undefined, no password is set for the user. Warning: do not set confidential information here because this data would be readable by all. This option should only be used for public account such as guest.";
|
||||
description = ''
|
||||
The user's password. If undefined, no password is set for
|
||||
the user. Warning: do not set confidential information here
|
||||
because it is world-readable in the Nix store. This option
|
||||
should only be used for public accounts such as
|
||||
<literal>guest</literal>.
|
||||
'';
|
||||
};
|
||||
|
||||
isSystemUser = mkOption {
|
||||
|
@ -79,11 +90,11 @@ let
|
|||
createUser = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "
|
||||
description = ''
|
||||
Indicates if the user should be created automatically as a local user.
|
||||
Set this to false if the user for instance is an LDAP user. NixOS will
|
||||
then not modify any of the basic properties for the user account.
|
||||
";
|
||||
'';
|
||||
};
|
||||
|
||||
isAlias = mkOption {
|
||||
|
@ -107,7 +118,7 @@ let
|
|||
options = {
|
||||
|
||||
name = mkOption {
|
||||
type = with types; uniq string;
|
||||
type = types.str;
|
||||
description = "The name of the group. If undefined, the name of the attribute set will be used.";
|
||||
};
|
||||
|
||||
|
@ -149,13 +160,12 @@ in
|
|||
example = {
|
||||
alice = {
|
||||
uid = 1234;
|
||||
description = "Alice";
|
||||
description = "Alice Q. User";
|
||||
home = "/home/alice";
|
||||
createHome = true;
|
||||
group = "users";
|
||||
extraGroups = ["wheel"];
|
||||
shell = "/bin/sh";
|
||||
password = "foobar";
|
||||
};
|
||||
};
|
||||
description = ''
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
{pkgs, config, ...}:
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
{
|
||||
|
||||
|
@ -6,9 +8,9 @@
|
|||
|
||||
options = {
|
||||
|
||||
hardware.enableAllFirmware = pkgs.lib.mkOption {
|
||||
hardware.enableAllFirmware = mkOption {
|
||||
default = false;
|
||||
type = pkgs.lib.types.bool;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Turn on this option if you want to enable all the firmware shipped with Debian/Ubuntu.
|
||||
'';
|
||||
|
@ -19,7 +21,7 @@
|
|||
|
||||
###### implementation
|
||||
|
||||
config = pkgs.lib.mkIf config.hardware.enableAllFirmware {
|
||||
config = mkIf config.hardware.enableAllFirmware {
|
||||
hardware.firmware = [ "${pkgs.firmwareLinuxNonfree}/lib/firmware" ];
|
||||
};
|
||||
|
||||
|
|
|
@ -18,16 +18,16 @@ in
|
|||
|
||||
hardware.pcmcia = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
merge = mergeEnableOption;
|
||||
description = ''
|
||||
Enable this option to support PCMCIA card.
|
||||
'';
|
||||
};
|
||||
|
||||
firmware = mkOption {
|
||||
type = types.listOf types.path;
|
||||
default = [];
|
||||
merge = mergeListOption;
|
||||
description = ''
|
||||
List of firmware used to handle specific PCMCIA card.
|
||||
'';
|
||||
|
@ -36,7 +36,7 @@ in
|
|||
config = mkOption {
|
||||
default = null;
|
||||
description = ''
|
||||
Path to the configuration file which map the memory, irq
|
||||
Path to the configuration file which maps the memory, IRQs
|
||||
and ports used by the PCMCIA hardware.
|
||||
'';
|
||||
};
|
||||
|
|
|
@ -33,7 +33,7 @@ in
|
|||
if ! [ -e /var/lib/nixos/did-channel-init ]; then
|
||||
echo "unpacking the NixOS/Nixpkgs sources..."
|
||||
mkdir -p /nix/var/nix/profiles/per-user/root
|
||||
${config.environment.nix}/bin/nix-env -p /nix/var/nix/profiles/per-user/root/channels \
|
||||
${config.nix.package}/bin/nix-env -p /nix/var/nix/profiles/per-user/root/channels \
|
||||
-i ${channelSources} --quiet --option use-substitutes false
|
||||
mkdir -m 0700 -p /root/.nix-defexpr
|
||||
ln -s /nix/var/nix/profiles/per-user/root/channels /root/.nix-defexpr/channels
|
||||
|
|
|
@ -298,12 +298,12 @@ in
|
|||
''
|
||||
# After booting, register the contents of the Nix store on the
|
||||
# CD in the Nix database in the tmpfs.
|
||||
${config.environment.nix}/bin/nix-store --load-db < /nix/store/nix-path-registration
|
||||
${config.nix.package}/bin/nix-store --load-db < /nix/store/nix-path-registration
|
||||
|
||||
# nixos-rebuild also requires a "system" profile and an
|
||||
# /etc/NIXOS tag.
|
||||
touch /etc/NIXOS
|
||||
${config.environment.nix}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system
|
||||
${config.nix.package}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system
|
||||
'';
|
||||
|
||||
# Add vfat support to the initrd to enable people to copy the
|
||||
|
|
|
@ -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
|
||||
];
|
||||
|
||||
}
|
|
@ -152,7 +152,7 @@ in
|
|||
# default root password is empty.
|
||||
services.openssh.enable = true;
|
||||
|
||||
jobs.openssh.startOn = pkgs.lib.mkOverrideTemplate 50 {} "";
|
||||
jobs.openssh.startOn = pkgs.lib.mkOverride 50 "";
|
||||
|
||||
boot.loader.grub.enable = false;
|
||||
boot.loader.generationsDir.enable = false;
|
||||
|
|
|
@ -109,7 +109,7 @@ in
|
|||
# not be started by default on the installation CD because the
|
||||
# default root password is empty.
|
||||
services.openssh.enable = true;
|
||||
jobs.openssh.startOn = pkgs.lib.mkOverrideTemplate 50 {} "";
|
||||
jobs.openssh.startOn = pkgs.lib.mkOverride 50 "";
|
||||
|
||||
# To be able to use the systemTarball to catch troubles.
|
||||
boot.crashDump = {
|
||||
|
|
|
@ -165,7 +165,7 @@ in
|
|||
# not be started by default on the installation CD because the
|
||||
# default root password is empty.
|
||||
services.openssh.enable = true;
|
||||
jobs.openssh.startOn = pkgs.lib.mkOverrideTemplate 50 {} "";
|
||||
jobs.openssh.startOn = pkgs.lib.mkOverride 50 "";
|
||||
|
||||
# cpufrequtils fails to build on non-pc
|
||||
powerManagement.enable = false;
|
||||
|
|
|
@ -77,14 +77,14 @@ in
|
|||
# After booting, register the contents of the Nix store on the
|
||||
# CD in the Nix database in the tmpfs.
|
||||
if [ -f /nix-path-registration ]; then
|
||||
${config.environment.nix}/bin/nix-store --load-db < /nix-path-registration &&
|
||||
${config.nix.package}/bin/nix-store --load-db < /nix-path-registration &&
|
||||
rm /nix-path-registration
|
||||
fi
|
||||
|
||||
# nixos-rebuild also requires a "system" profile and an
|
||||
# /etc/NIXOS tag.
|
||||
touch /etc/NIXOS
|
||||
${config.environment.nix}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system
|
||||
${config.nix.package}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system
|
||||
'';
|
||||
|
||||
};
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#! @shell@ -e
|
||||
|
||||
# FIXME: rewrite this in a more suitable language.
|
||||
|
||||
usage () {
|
||||
exec man nixos-option
|
||||
exit 1
|
||||
|
@ -90,24 +92,25 @@ evalNix(){
|
|||
}
|
||||
|
||||
evalAttr(){
|
||||
local prefix=$1
|
||||
local suffix=$2
|
||||
local strict=$3
|
||||
local prefix="$1"
|
||||
local strict="$2"
|
||||
local suffix="$3"
|
||||
echo "(import <nixos> {}).$prefix${option:+.$option}${suffix:+.$suffix}" |
|
||||
evalNix ${strict:+--strict}
|
||||
}
|
||||
|
||||
evalOpt(){
|
||||
evalAttr "eval.options" "$@"
|
||||
evalAttr "options" "" "$@"
|
||||
}
|
||||
|
||||
evalCfg(){
|
||||
evalAttr "config" "$@"
|
||||
local strict="$1"
|
||||
evalAttr "config" "$strict"
|
||||
}
|
||||
|
||||
findSources(){
|
||||
local suffix=$1
|
||||
echo "builtins.map (f: f.source) (import <nixos> {}).eval.options${option:+.$option}.$suffix" |
|
||||
echo "(import <nixos> {}).options${option:+.$option}.$suffix" |
|
||||
evalNix --strict
|
||||
}
|
||||
|
||||
|
@ -143,7 +146,7 @@ let
|
|||
nixos = import <nixos> {};
|
||||
nixpkgs = import <nixpkgs> {};
|
||||
sources = builtins.map (f: f.source);
|
||||
opt = reach nixos.eval.options;
|
||||
opt = reach nixos.options;
|
||||
cfg = reach nixos.config;
|
||||
in
|
||||
|
||||
|
@ -186,7 +189,7 @@ EOF
|
|||
fi
|
||||
|
||||
if test "$(evalOpt "_type" 2> /dev/null)" = '"option"'; then
|
||||
$value && evalCfg;
|
||||
$value && evalCfg 1
|
||||
|
||||
if $desc; then
|
||||
$value && echo;
|
||||
|
@ -212,14 +215,14 @@ if test "$(evalOpt "_type" 2> /dev/null)" = '"option"'; then
|
|||
nixMap printPath "$(findSources "declarations")"
|
||||
echo ""
|
||||
echo "Defined by:"
|
||||
nixMap printPath "$(findSources "definitions")"
|
||||
nixMap printPath "$(findSources "files")"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
else
|
||||
# echo 1>&2 "Warning: This value is not an option."
|
||||
|
||||
result=$(evalCfg)
|
||||
result=$(evalCfg "")
|
||||
if names=$(attrNames "$result" 2> /dev/null); then
|
||||
echo 1>&2 "This attribute set contains:"
|
||||
escapeQuotes () { eval echo "$1"; }
|
||||
|
|
|
@ -109,7 +109,7 @@ fi
|
|||
# more conservative.
|
||||
if [ "$action" != dry-run -a -n "$buildNix" ]; then
|
||||
echo "building Nix..." >&2
|
||||
if ! nix-build '<nixpkgs/nixos>' -A config.environment.nix -o $tmpDir/nix "${extraBuildFlags[@]}" > /dev/null; then
|
||||
if ! nix-build '<nixpkgs/nixos>' -A config.nix.package -o $tmpDir/nix "${extraBuildFlags[@]}" > /dev/null; then
|
||||
if ! nix-build '<nixpkgs/nixos>' -A nixFallback -o $tmpDir/nix "${extraBuildFlags[@]}" > /dev/null; then
|
||||
nix-build '<nixpkgs>' -A nixUnstable -o $tmpDir/nix "${extraBuildFlags[@]}" > /dev/null
|
||||
fi
|
||||
|
@ -121,7 +121,7 @@ fi
|
|||
# Update the version suffix if we're building from Git (so that
|
||||
# nixos-version shows something useful).
|
||||
if nixpkgs=$(nix-instantiate --find-file nixpkgs "${extraBuildFlags[@]}"); then
|
||||
suffix=$(@shell@ $nixpkgs/nixos/modules/installer/tools/get-version-suffix "${extraBuildFlags[@]}")
|
||||
suffix=$(@shell@ $nixpkgs/nixos/modules/installer/tools/get-version-suffix "${extraBuildFlags[@]}" || true)
|
||||
if [ -n "$suffix" ]; then
|
||||
echo -n "$suffix" > "$nixpkgs/.version-suffix" || true
|
||||
fi
|
||||
|
|
|
@ -22,10 +22,10 @@ let
|
|||
src = ./nixos-install.sh;
|
||||
|
||||
inherit (pkgs) perl pathsFromGraph;
|
||||
nix = config.environment.nix;
|
||||
nix = config.nix.package;
|
||||
|
||||
nixClosure = pkgs.runCommand "closure"
|
||||
{ exportReferencesGraph = ["refs" config.environment.nix]; }
|
||||
{ exportReferencesGraph = ["refs" config.nix.package]; }
|
||||
"cp refs $out";
|
||||
};
|
||||
|
||||
|
@ -52,6 +52,7 @@ let
|
|||
inherit (config.system) nixosVersion nixosCodeName;
|
||||
};
|
||||
|
||||
/*
|
||||
nixos-gui = pkgs.xulrunnerWrapper {
|
||||
launcher = "nixos-gui";
|
||||
application = pkgs.stdenv.mkDerivation {
|
||||
|
@ -71,10 +72,12 @@ let
|
|||
};
|
||||
};
|
||||
};
|
||||
*/
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
/*
|
||||
options = {
|
||||
|
||||
installer.enableGraphicalTools = pkgs.lib.mkOption {
|
||||
|
@ -87,6 +90,7 @@ in
|
|||
};
|
||||
|
||||
};
|
||||
*/
|
||||
|
||||
config = {
|
||||
environment.systemPackages =
|
||||
|
@ -96,10 +100,10 @@ in
|
|||
nixos-generate-config
|
||||
nixos-option
|
||||
nixos-version
|
||||
] ++ pkgs.lib.optional cfg.enableGraphicalTools nixos-gui;
|
||||
];
|
||||
|
||||
system.build = {
|
||||
inherit nixos-install nixos-generate-config nixos-option;
|
||||
inherit nixos-install nixos-generate-config nixos-option nixos-rebuild;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -15,10 +15,10 @@ in
|
|||
options = {
|
||||
|
||||
assertions = mkOption {
|
||||
type = types.listOf types.unspecified;
|
||||
internal = true;
|
||||
default = [];
|
||||
example = [ { assertion = false; message = "you can't enable this for that reason"; } ];
|
||||
merge = pkgs.lib.mergeListOption;
|
||||
description = ''
|
||||
This option allows modules to express conditions that must
|
||||
hold for the evaluation of the system configuration to
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
{pkgs, ...}:
|
||||
{ pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
{
|
||||
options = {
|
||||
environment.checkConfigurationOptions = pkgs.lib.mkOption {
|
||||
environment.checkConfigurationOptions = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
example = false;
|
||||
description = ''
|
||||
Whether to check the validity of the entire configuration.
|
||||
'';
|
||||
|
|
|
@ -14,8 +14,8 @@ in
|
|||
boot = {
|
||||
crashDump = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = ''
|
||||
If enabled, NixOS will set up a kernel that will
|
||||
boot on crash, and leave the user to a stage1 debug1devices
|
||||
|
@ -35,6 +35,7 @@ in
|
|||
'';
|
||||
};
|
||||
kernelParams = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ "debug1devices" ];
|
||||
description = ''
|
||||
Parameters that will be passed to the kernel kexec-ed on crash.
|
||||
|
|
|
@ -7,12 +7,14 @@
|
|||
options = {
|
||||
|
||||
ids.uids = pkgs.lib.mkOption {
|
||||
internal = true;
|
||||
description = ''
|
||||
The user IDs used in NixOS.
|
||||
'';
|
||||
};
|
||||
|
||||
ids.gids = pkgs.lib.mkOption {
|
||||
internal = true;
|
||||
description = ''
|
||||
The group IDs used in NixOS.
|
||||
'';
|
||||
|
@ -102,6 +104,8 @@
|
|||
tcpcryptd = 93; # tcpcryptd uses a hard-coded uid. We patch it in Nixpkgs to match this choice.
|
||||
zope2 = 94;
|
||||
firebird = 95;
|
||||
redis = 96;
|
||||
haproxy = 97;
|
||||
|
||||
# When adding a uid, make sure it doesn't match an existing gid.
|
||||
|
||||
|
@ -188,6 +192,7 @@
|
|||
quassel = 89;
|
||||
amule = 90;
|
||||
minidlna = 91;
|
||||
haproxy = 92;
|
||||
|
||||
# When adding a gid, make sure it doesn't match an existing uid.
|
||||
|
||||
|
|
|
@ -17,8 +17,8 @@ in
|
|||
services.locate = {
|
||||
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = ''
|
||||
If enabled, NixOS will periodically update the database of
|
||||
files used by the <command>locate</command> command.
|
||||
|
@ -26,11 +26,12 @@ in
|
|||
};
|
||||
|
||||
period = mkOption {
|
||||
type = types.str;
|
||||
default = "15 02 * * *";
|
||||
description = ''
|
||||
This option defines (in the format used by cron) when the
|
||||
locate database is updated.
|
||||
The default is to update at 02:15 (at night) every day.
|
||||
The default is to update at 02:15 at night every day.
|
||||
'';
|
||||
};
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ let
|
|||
configType = mkOptionType {
|
||||
name = "nixpkgs config";
|
||||
check = traceValIfNot isConfig;
|
||||
merge = fold mergeConfig {};
|
||||
merge = args: fold (def: mergeConfig def.value) {};
|
||||
};
|
||||
|
||||
in
|
||||
|
@ -59,7 +59,7 @@ in
|
|||
};
|
||||
|
||||
nixpkgs.system = mkOption {
|
||||
default = pkgs.stdenv.system;
|
||||
type = types.str;
|
||||
description = ''
|
||||
Specifies the Nix platform type for which NixOS should be built.
|
||||
If unset, it defaults to the platform type of your host system
|
||||
|
@ -70,4 +70,8 @@ in
|
|||
};
|
||||
|
||||
};
|
||||
|
||||
config = {
|
||||
nixpkgs.system = mkDefault pkgs.stdenv.system;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
{
|
||||
options = {
|
||||
passthru = pkgs.lib.mkOption {
|
||||
visible = false;
|
||||
description = ''
|
||||
This attribute set will be exported as a system attribute.
|
||||
You can put whatever you want here.
|
||||
|
|
|
@ -8,31 +8,31 @@ with pkgs.lib;
|
|||
|
||||
system.nixosVersion = mkOption {
|
||||
internal = true;
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
description = "NixOS version.";
|
||||
};
|
||||
|
||||
system.nixosVersionSuffix = mkOption {
|
||||
internal = true;
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
description = "NixOS version suffix.";
|
||||
};
|
||||
|
||||
system.nixosRevision = mkOption {
|
||||
internal = true;
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
description = "NixOS Git revision hash.";
|
||||
};
|
||||
|
||||
system.nixosCodeName = mkOption {
|
||||
internal = true;
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
description = "NixOS release code name.";
|
||||
};
|
||||
|
||||
system.defaultChannel = mkOption {
|
||||
internal = true;
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
default = https://nixos.org/channels/nixos-unstable;
|
||||
description = "Default NixOS channel to which the root user is subscribed.";
|
||||
};
|
||||
|
@ -58,18 +58,15 @@ with pkgs.lib;
|
|||
# Generate /etc/os-release. See
|
||||
# http://0pointer.de/public/systemd-man/os-release.html for the
|
||||
# format.
|
||||
environment.etc = singleton
|
||||
{ source = pkgs.writeText "os-release"
|
||||
''
|
||||
NAME=NixOS
|
||||
ID=nixos
|
||||
VERSION="${config.system.nixosVersion} (${config.system.nixosCodeName})"
|
||||
VERSION_ID="${config.system.nixosVersion}"
|
||||
PRETTY_NAME="NixOS ${config.system.nixosVersion} (${config.system.nixosCodeName})"
|
||||
HOME_URL="http://nixos.org/"
|
||||
'';
|
||||
target = "os-release";
|
||||
};
|
||||
environment.etc."os-release".text =
|
||||
''
|
||||
NAME=NixOS
|
||||
ID=nixos
|
||||
VERSION="${config.system.nixosVersion} (${config.system.nixosCodeName})"
|
||||
VERSION_ID="${config.system.nixosVersion}"
|
||||
PRETTY_NAME="NixOS ${config.system.nixosVersion} (${config.system.nixosCodeName})"
|
||||
HOME_URL="http://nixos.org/"
|
||||
'';
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -150,12 +150,12 @@
|
|||
./services/networking/cntlm.nix
|
||||
./services/networking/chrony.nix
|
||||
./services/networking/ddclient.nix
|
||||
#./services/networking/dhclient.nix
|
||||
./services/networking/dhcpcd.nix
|
||||
./services/networking/dhcpd.nix
|
||||
./services/networking/dnsmasq.nix
|
||||
./services/networking/ejabberd.nix
|
||||
./services/networking/firewall.nix
|
||||
./services/networking/haproxy.nix
|
||||
./services/networking/tcpcrypt.nix
|
||||
./services/networking/flashpolicyd.nix
|
||||
./services/networking/freenet.nix
|
||||
|
@ -276,7 +276,7 @@
|
|||
./tasks/scsi-link-power-management.nix
|
||||
./tasks/swraid.nix
|
||||
./virtualisation/libvirtd.nix
|
||||
./virtualisation/nova.nix
|
||||
#./virtualisation/nova.nix
|
||||
./virtualisation/virtualbox-guest.nix
|
||||
./virtualisation/xen-dom0.nix
|
||||
]
|
||||
|
|
|
@ -16,7 +16,8 @@ let
|
|||
# cannot serialized attribute set given in the list of modules (that's why
|
||||
# you should use files).
|
||||
moduleFiles =
|
||||
filter isPath modules;
|
||||
# FIXME: use typeOf (Nix 1.6.1).
|
||||
filter (x: !isAttrs x && !builtins.isFunction x) modules;
|
||||
|
||||
# Partition module files because between NixOS and non-NixOS files. NixOS
|
||||
# files may change if the repository is updated.
|
||||
|
|
|
@ -48,7 +48,7 @@ in
|
|||
Rather, it should be the path of a symlink that points to the
|
||||
actual shell in the Nix store.
|
||||
'';
|
||||
type = types.uniq types.path;
|
||||
type = types.path;
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -16,6 +16,7 @@ in
|
|||
programs.ssh = {
|
||||
|
||||
forwardX11 = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to request X11 forwarding on outgoing connections by default.
|
||||
|
@ -29,18 +30,21 @@ in
|
|||
};
|
||||
|
||||
setXAuthLocation = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to set the path to <command>xauth</command> for X11-forwarded connections.
|
||||
Pulls in X11 dependency.
|
||||
This causes a dependency on X11 packages.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Extra configuration text appended to <filename>ssh_config</filename>.
|
||||
See the ssh_config(5) man page for help.
|
||||
See <citerefentry><refentrytitle>ssh_config</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
for help.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
|
|
@ -32,7 +32,6 @@ let
|
|||
zipAttrsWith (n: v:
|
||||
if tail v != [] then
|
||||
if n == "_type" then (head v)
|
||||
else if n == "extraConfigs" then concatLists v
|
||||
else if n == "warnings" then concatLists v
|
||||
else if n == "description" || n == "apply" then
|
||||
abort "Cannot rename an option to multiple options."
|
||||
|
@ -55,12 +54,7 @@ let
|
|||
inherit visible;
|
||||
});
|
||||
}
|
||||
{ options = setTo (mkOption {
|
||||
extraConfigs =
|
||||
let externalDefs = (fromOf options).definitions; in
|
||||
if externalDefs == [] then []
|
||||
else map (def: def.value) (define externalDefs);
|
||||
});
|
||||
{ config = setTo (mkIf (fromOf options).isDefined (define (mkMerge (fromOf options).definitions)));
|
||||
}
|
||||
];
|
||||
|
||||
|
@ -75,10 +69,9 @@ let
|
|||
|
||||
in zipModules ([]
|
||||
|
||||
# usage example:
|
||||
# ++ alias [ "services" "xserver" "slim" "theme" ] [ "services" "xserver" "displayManager" "slim" "theme" ]
|
||||
++ obsolete [ "environment" "extraPackages" ] [ "environment" "systemPackages" ]
|
||||
++ obsolete [ "environment" "x11Packages" ] [ "environment" "systemPackages" ]
|
||||
++ obsolete [ "environment" "enableBashCompletion" ] [ "programs" "bash" "enableCompletion" ]
|
||||
++ obsolete [ "environment" "nix" ] [ "nix" "package" ]
|
||||
|
||||
++ obsolete [ "security" "extraSetuidPrograms" ] [ "security" "setuidPrograms" ]
|
||||
++ obsolete [ "networking" "enableWLAN" ] [ "networking" "wireless" "enable" ]
|
||||
|
@ -98,6 +91,7 @@ in zipModules ([]
|
|||
++ obsolete [ "boot" "grubSplashImage" ] [ "boot" "loader" "grub" "splashImage" ]
|
||||
|
||||
++ obsolete [ "boot" "initrd" "extraKernelModules" ] [ "boot" "initrd" "kernelModules" ]
|
||||
++ obsolete [ "boot" "extraKernelParams" ] [ "boot" "kernelParams" ]
|
||||
|
||||
# OpenSSH
|
||||
++ obsolete [ "services" "sshd" "ports" ] [ "services" "openssh" "ports" ]
|
||||
|
|
|
@ -15,6 +15,7 @@ with pkgs.lib;
|
|||
security.apparmor = {
|
||||
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Enable AppArmor application security system. Enable only if
|
||||
|
@ -23,8 +24,8 @@ with pkgs.lib;
|
|||
};
|
||||
|
||||
profiles = mkOption {
|
||||
type = types.listOf types.path;
|
||||
default = [];
|
||||
merge = mergeListOption;
|
||||
description = ''
|
||||
List of file names of AppArmor profiles.
|
||||
'';
|
||||
|
|
|
@ -13,7 +13,7 @@ let
|
|||
|
||||
name = mkOption {
|
||||
example = "sshd";
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
description = "Name of the PAM service.";
|
||||
};
|
||||
|
||||
|
@ -133,7 +133,7 @@ let
|
|||
};
|
||||
|
||||
text = mkOption {
|
||||
type = types.nullOr types.string;
|
||||
type = types.nullOr types.lines;
|
||||
description = "Contents of the PAM service file.";
|
||||
};
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ in
|
|||
|
||||
security.pam.usb = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Enable USB login for all login systems that support it. For
|
||||
|
|
|
@ -13,11 +13,13 @@ in
|
|||
options = {
|
||||
|
||||
security.polkit.enable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Whether to enable PolKit.";
|
||||
};
|
||||
|
||||
security.polkit.permissions = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
example =
|
||||
''
|
||||
|
@ -49,6 +51,7 @@ in
|
|||
};
|
||||
|
||||
security.polkit.adminIdentities = mkOption {
|
||||
type = types.str;
|
||||
default = "unix-user:0;unix-group:wheel";
|
||||
example = "";
|
||||
description =
|
||||
|
|
|
@ -5,6 +5,7 @@ with pkgs.lib;
|
|||
{
|
||||
options = {
|
||||
security.rngd.enable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to enable the rng daemon, which adds entropy from
|
||||
|
|
|
@ -10,6 +10,7 @@ with pkgs.lib;
|
|||
options = {
|
||||
|
||||
security.rtkit.enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to enable the RealtimeKit system service, which hands
|
||||
|
|
|
@ -25,7 +25,9 @@ in
|
|||
options = {
|
||||
|
||||
security.setuidPrograms = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = ["passwd"];
|
||||
description = ''
|
||||
The Nix store cannot contain setuid/setgid programs directly.
|
||||
For this reason, NixOS can automatically generate wrapper
|
||||
|
@ -36,6 +38,7 @@ in
|
|||
};
|
||||
|
||||
security.setuidOwners = mkOption {
|
||||
type = types.listOf types.attrs;
|
||||
default = [];
|
||||
example =
|
||||
[ { program = "sendmail";
|
||||
|
@ -53,6 +56,8 @@ in
|
|||
};
|
||||
|
||||
security.wrapperDir = mkOption {
|
||||
internal = true;
|
||||
type = types.path;
|
||||
default = "/var/setuid-wrappers";
|
||||
description = ''
|
||||
This option defines the path to the setuid wrappers. It
|
||||
|
|
|
@ -17,6 +17,7 @@ in
|
|||
options = {
|
||||
|
||||
security.sudo.enable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description =
|
||||
''
|
||||
|
@ -26,6 +27,7 @@ in
|
|||
};
|
||||
|
||||
security.sudo.wheelNeedsPassword = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description =
|
||||
''
|
||||
|
@ -35,6 +37,7 @@ in
|
|||
};
|
||||
|
||||
security.sudo.configFile = mkOption {
|
||||
type = types.lines;
|
||||
# Note: if syntax errors are detected in this file, the NixOS
|
||||
# configuration will fail to build.
|
||||
description =
|
||||
|
|
|
@ -20,14 +20,15 @@ in
|
|||
sound = {
|
||||
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to enable ALSA sound.
|
||||
'';
|
||||
merge = mergeEnableOption;
|
||||
};
|
||||
|
||||
enableOSSEmulation = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to enable ALSA OSS emulation (with certain cards sound mixing may not work!).
|
||||
|
|
|
@ -21,7 +21,7 @@ with pkgs.lib;
|
|||
|
||||
name = mkOption {
|
||||
example = "Media Center";
|
||||
type = with types; uniq string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
Enables Fuppes (UPnP A/V Media Server). Can be used to watch
|
||||
photos, video and listen to music from a phone/tv connected to the
|
||||
|
@ -41,7 +41,7 @@ with pkgs.lib;
|
|||
|
||||
file = mkOption {
|
||||
default = "/var/log/fuppes.log";
|
||||
type = with types; uniq string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
File which will contains the log produced by the daemon.
|
||||
'';
|
||||
|
@ -50,7 +50,7 @@ with pkgs.lib;
|
|||
|
||||
config = mkOption {
|
||||
example = "/etc/fuppes/fuppes.cfg";
|
||||
type = with types; uniq string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
Mutable configuration file which can be edited with the web
|
||||
interface. Due to possible modification, double quote the full
|
||||
|
@ -69,7 +69,7 @@ with pkgs.lib;
|
|||
|
||||
database = mkOption {
|
||||
default = "/var/lib/fuppes/fuppes.db";
|
||||
type = with types; uniq string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
Database file which index all shared files.
|
||||
'';
|
||||
|
@ -88,7 +88,7 @@ with pkgs.lib;
|
|||
user = mkOption {
|
||||
default = "root"; # The default is not secure.
|
||||
example = "fuppes";
|
||||
type = with types; uniq string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
Name of the user which own the configuration files and under which
|
||||
the fuppes daemon will be executed.
|
||||
|
|
|
@ -24,12 +24,12 @@ with pkgs.lib;
|
|||
};
|
||||
|
||||
listenAddress = mkOption {
|
||||
default = null;
|
||||
default = null;
|
||||
description = "IP address to listen on.";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
default = 8080;
|
||||
default = 8080;
|
||||
description = "port to listen on.";
|
||||
};
|
||||
|
||||
|
@ -45,9 +45,12 @@ with pkgs.lib;
|
|||
|
||||
###### implementation
|
||||
|
||||
config = mkIf cfg.enable (
|
||||
mkAssert (cfg.enable -> cfg.database != "")
|
||||
"Must specify database name" {
|
||||
config = mkIf cfg.enable {
|
||||
|
||||
assertions = singleton
|
||||
{ assertion = cfg.enable -> cfg.database != "";
|
||||
message = "Must specify 4Store database name";
|
||||
};
|
||||
|
||||
users.extraUsers = singleton
|
||||
{ name = endpointUser;
|
||||
|
@ -63,10 +66,10 @@ with pkgs.lib;
|
|||
startOn = "filesystem";
|
||||
|
||||
exec = ''
|
||||
${run} '${pkgs.rdf4store}/bin/4s-httpd -D ${cfg.options} ${if cfg.listenAddress!=null then "-H ${cfg.listenAddress}" else "" } -p ${toString cfg.port} ${cfg.database}'
|
||||
${run} '${pkgs.rdf4store}/bin/4s-httpd -D ${cfg.options} ${if cfg.listenAddress!=null then "-H ${cfg.listenAddress}" else "" } -p ${toString cfg.port} ${cfg.database}'
|
||||
'';
|
||||
};
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -36,9 +36,12 @@ with pkgs.lib;
|
|||
|
||||
###### implementation
|
||||
|
||||
config = mkIf cfg.enable (
|
||||
mkAssert (cfg.enable -> cfg.database != "")
|
||||
"Must specify database name" {
|
||||
config = mkIf cfg.enable {
|
||||
|
||||
assertions = singleton
|
||||
{ assertion = cfg.enable -> cfg.database != "";
|
||||
message = "Must specify 4Store database name.";
|
||||
};
|
||||
|
||||
users.extraUsers = singleton
|
||||
{ name = fourStoreUser;
|
||||
|
@ -56,16 +59,16 @@ with pkgs.lib;
|
|||
preStart = ''
|
||||
mkdir -p ${stateDir}/
|
||||
chown ${fourStoreUser} ${stateDir}
|
||||
if ! test -e "${stateDir}/${cfg.database}"; then
|
||||
${run} -c '${pkgs.rdf4store}/bin/4s-backend-setup ${cfg.database}'
|
||||
if ! test -e "${stateDir}/${cfg.database}"; then
|
||||
${run} -c '${pkgs.rdf4store}/bin/4s-backend-setup ${cfg.database}'
|
||||
fi
|
||||
'';
|
||||
|
||||
exec = ''
|
||||
${run} -c '${pkgs.rdf4store}/bin/4s-backend -D ${cfg.options} ${cfg.database}'
|
||||
${run} -c '${pkgs.rdf4store}/bin/4s-backend -D ${cfg.options} ${cfg.database}'
|
||||
'';
|
||||
};
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ in
|
|||
services.postgresql = {
|
||||
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to run PostgreSQL.
|
||||
|
@ -53,6 +54,7 @@ in
|
|||
};
|
||||
|
||||
package = mkOption {
|
||||
type = types.path;
|
||||
example = literalExample "pkgs.postgresql92";
|
||||
description = ''
|
||||
PostgreSQL package to use.
|
||||
|
@ -60,6 +62,7 @@ in
|
|||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.int;
|
||||
default = "5432";
|
||||
description = ''
|
||||
Port for PostgreSQL.
|
||||
|
@ -67,6 +70,7 @@ in
|
|||
};
|
||||
|
||||
dataDir = mkOption {
|
||||
type = types.path;
|
||||
default = "/var/db/postgresql";
|
||||
description = ''
|
||||
Data directory for PostgreSQL.
|
||||
|
@ -74,6 +78,7 @@ in
|
|||
};
|
||||
|
||||
authentication = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Defines how users authenticate themselves to the server.
|
||||
|
@ -81,6 +86,7 @@ in
|
|||
};
|
||||
|
||||
identMap = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Defines the mapping from system users to database users.
|
||||
|
@ -88,14 +94,15 @@ in
|
|||
};
|
||||
|
||||
initialScript = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.path;
|
||||
default = null;
|
||||
description = ''
|
||||
A file containing SQL statements to execute on first startup.
|
||||
'';
|
||||
};
|
||||
|
||||
enableTCPIP = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to run PostgreSQL with -i flag to enable TCP/IP connections.
|
||||
|
@ -103,8 +110,9 @@ in
|
|||
};
|
||||
|
||||
extraPlugins = mkOption {
|
||||
type = types.listOf types.path;
|
||||
default = [];
|
||||
example = "pkgs.postgis"; # of course don't use a string here!
|
||||
example = literalExample "pkgs.postgis";
|
||||
description = ''
|
||||
When this list contains elements a new store path is created.
|
||||
PostgreSQL and the elments are symlinked into it. Then pg_config,
|
||||
|
@ -118,15 +126,16 @@ in
|
|||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = "Additional text to be appended to <filename>postgresql.conf</filename>.";
|
||||
};
|
||||
|
||||
recoveryConfig = mkOption {
|
||||
type = types.nullOr types.lines;
|
||||
default = null;
|
||||
type = types.nullOr types.string;
|
||||
description = ''
|
||||
Values to put into recovery.conf file.
|
||||
Contents of the <filename>recovery.conf</filename> file.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
|
|
@ -14,6 +14,7 @@ let
|
|||
${condOption "unixsocket" cfg.unixSocket}
|
||||
loglevel ${cfg.logLevel}
|
||||
logfile ${cfg.logfile}
|
||||
syslog-enabled ${redisBool cfg.syslog}
|
||||
databases ${toString cfg.databases}
|
||||
${concatMapStrings (d: "save ${toString (builtins.elemAt d 0)} ${toString (builtins.elemAt d 1)}\n") cfg.save}
|
||||
dbfilename ${cfg.dbFilename}
|
||||
|
@ -82,12 +83,18 @@ in
|
|||
};
|
||||
|
||||
logfile = mkOption {
|
||||
default = "stdout";
|
||||
default = "/dev/null";
|
||||
description = "Specify the log file name. Also 'stdout' can be used to force Redis to log on the standard output.";
|
||||
example = "/var/log/redis.log";
|
||||
type = with types; string;
|
||||
};
|
||||
|
||||
syslog = mkOption {
|
||||
default = true;
|
||||
description = "Enable logging to the system logger.";
|
||||
type = with types; bool;
|
||||
};
|
||||
|
||||
databases = mkOption {
|
||||
default = 16;
|
||||
description = "Set the number of databases.";
|
||||
|
@ -177,8 +184,9 @@ in
|
|||
|
||||
config = mkIf config.services.redis.enable {
|
||||
|
||||
users.extraUsers = singleton
|
||||
users.extraUsers.redis =
|
||||
{ name = cfg.user;
|
||||
uid = config.ids.uids.redis;
|
||||
description = "Redis database user";
|
||||
};
|
||||
|
||||
|
|
|
@ -21,7 +21,8 @@ in
|
|||
|
||||
language = mkOption {
|
||||
default = "English";
|
||||
check = lang: elem lang [ "English" "Spanish" "Russian" "Serbian" "Turkish" ];
|
||||
type = types.addCheck types.str
|
||||
(lang: elem lang [ "English" "Spanish" "Russian" "Serbian" "Turkish" ]);
|
||||
description = "The language of bot messages: English, Spanish, Russian, Serbian or Turkish.";
|
||||
};
|
||||
|
||||
|
|
|
@ -66,21 +66,25 @@ in
|
|||
services.acpid = {
|
||||
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether to enable the ACPI daemon.";
|
||||
};
|
||||
|
||||
powerEventCommands = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = "Shell commands to execute on a button/power.* event.";
|
||||
};
|
||||
|
||||
lidEventCommands = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = "Shell commands to execute on a button/lid.* event.";
|
||||
};
|
||||
|
||||
acEventCommands = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = "Shell commands to execute on an ac_adapter.* event.";
|
||||
};
|
||||
|
|
|
@ -9,6 +9,7 @@ with pkgs.lib;
|
|||
options = {
|
||||
|
||||
hardware.bluetooth.enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether to enable support for Bluetooth.";
|
||||
};
|
||||
|
|
|
@ -2,6 +2,12 @@
|
|||
|
||||
with pkgs.lib;
|
||||
|
||||
let
|
||||
|
||||
pkg = if config.hardware.sane.snapshot then pkgs.saneBackendsGit else pkgs.saneBackends;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
|
||||
###### interface
|
||||
|
@ -9,11 +15,13 @@ with pkgs.lib;
|
|||
options = {
|
||||
|
||||
hardware.sane.enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Enable support for SANE scanners.";
|
||||
};
|
||||
|
||||
hardware.sane.snapshot = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Use a development snapshot of SANE scanner drivers.";
|
||||
};
|
||||
|
@ -23,18 +31,13 @@ with pkgs.lib;
|
|||
|
||||
###### implementation
|
||||
|
||||
config = let pkg = if config.hardware.sane.snapshot
|
||||
then pkgs.saneBackendsGit
|
||||
else pkgs.saneBackends;
|
||||
in mkIf config.hardware.sane.enable {
|
||||
environment.systemPackages = [ pkg ];
|
||||
services.udev.packages = [ pkg ];
|
||||
|
||||
users.extraGroups = singleton {
|
||||
name = "scanner";
|
||||
gid = config.ids.gids.scanner;
|
||||
};
|
||||
config = mkIf config.hardware.sane.enable {
|
||||
|
||||
};
|
||||
environment.systemPackages = [ pkg ];
|
||||
services.udev.packages = [ pkg ];
|
||||
|
||||
users.extraGroups."scanner".gid = config.ids.gids.scanner;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -114,6 +114,7 @@ in
|
|||
options = {
|
||||
|
||||
boot.hardwareScan = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to try to load kernel modules for all detected hardware.
|
||||
|
@ -126,8 +127,8 @@ in
|
|||
services.udev = {
|
||||
|
||||
packages = mkOption {
|
||||
type = types.listOf types.path;
|
||||
default = [];
|
||||
merge = mergeListOption;
|
||||
description = ''
|
||||
List of packages containing <command>udev</command> rules.
|
||||
All files found in
|
||||
|
@ -138,8 +139,8 @@ in
|
|||
};
|
||||
|
||||
path = mkOption {
|
||||
type = types.listOf types.path;
|
||||
default = [];
|
||||
merge = mergeListOption;
|
||||
description = ''
|
||||
Packages added to the <envar>PATH</envar> environment variable when
|
||||
executing programs from Udev rules.
|
||||
|
@ -162,9 +163,9 @@ in
|
|||
};
|
||||
|
||||
hardware.firmware = mkOption {
|
||||
type = types.listOf types.path;
|
||||
default = [];
|
||||
example = [ "/root/my-firmware" ];
|
||||
merge = mergeListOption;
|
||||
description = ''
|
||||
List of directories containing firmware files. Such files
|
||||
will be loaded automatically if the kernel asks for them
|
||||
|
|
|
@ -13,6 +13,7 @@ with pkgs.lib;
|
|||
services.udisks = {
|
||||
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to enable Udisks, a DBus service that allows
|
||||
|
|
|
@ -13,6 +13,7 @@ with pkgs.lib;
|
|||
services.udisks2 = {
|
||||
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to enable Udisks, a DBus service that allows
|
||||
|
|
|
@ -13,6 +13,7 @@ with pkgs.lib;
|
|||
services.upower = {
|
||||
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to enable Upower, a DBus service that provides power
|
||||
|
|
|
@ -52,7 +52,7 @@ let
|
|||
|
||||
levelOption = mkOption {
|
||||
default = "server";
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
Set the logcheck level. Either "workstation", "server", or "paranoid".
|
||||
'';
|
||||
|
@ -63,7 +63,7 @@ let
|
|||
|
||||
regex = mkOption {
|
||||
default = "";
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
Regex specifying which log lines to ignore.
|
||||
'';
|
||||
|
@ -73,7 +73,7 @@ let
|
|||
ignoreCronOptions = {
|
||||
user = mkOption {
|
||||
default = "root";
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
User that runs the cronjob.
|
||||
'';
|
||||
|
@ -81,7 +81,7 @@ let
|
|||
|
||||
cmdline = mkOption {
|
||||
default = "";
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
Command line for the cron job. Will be turned into a regex for the logcheck ignore rule.
|
||||
'';
|
||||
|
@ -89,7 +89,7 @@ let
|
|||
|
||||
timeArgs = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr (types.uniq types.string);
|
||||
type = types.nullOr (types.str);
|
||||
example = "02 06 * * *";
|
||||
description = ''
|
||||
"min hr dom mon dow" crontab time args, to auto-create a cronjob too.
|
||||
|
@ -112,7 +112,7 @@ in
|
|||
|
||||
user = mkOption {
|
||||
default = "logcheck";
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
Username for the logcheck user.
|
||||
'';
|
||||
|
@ -121,7 +121,7 @@ in
|
|||
timeOfDay = mkOption {
|
||||
default = "*";
|
||||
example = "6";
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
Time of day to run logcheck. A logcheck will be scheduled at xx:02 each day.
|
||||
Leave default (*) to run every hour. Of course when nothing special was logged,
|
||||
|
@ -132,7 +132,7 @@ in
|
|||
mailTo = mkOption {
|
||||
default = "root";
|
||||
example = "you@domain.com";
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
Email address to send reports to.
|
||||
'';
|
||||
|
@ -140,7 +140,7 @@ in
|
|||
|
||||
level = mkOption {
|
||||
default = "server";
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
Set the logcheck level. Either "workstation", "server", or "paranoid".
|
||||
'';
|
||||
|
|
|
@ -99,7 +99,7 @@ in
|
|||
mkHash functions, which take a string representation of a float and an
|
||||
attrset, respectively.
|
||||
'';
|
||||
merge = mergeConfigs;
|
||||
apply = mergeConfigs;
|
||||
};
|
||||
|
||||
filterConfig = mkOption {
|
||||
|
@ -109,7 +109,7 @@ in
|
|||
representing a logstash configuration's filter section.
|
||||
See inputConfig description for details.
|
||||
'';
|
||||
merge = mergeConfigs;
|
||||
apply = mergeConfigs;
|
||||
};
|
||||
|
||||
outputConfig = mkOption {
|
||||
|
@ -119,7 +119,7 @@ in
|
|||
representing a logstash configuration's output section.
|
||||
See inputConfig description for details.
|
||||
'';
|
||||
merge = mergeConfigs;
|
||||
apply = mergeConfigs;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -46,7 +46,7 @@ in
|
|||
};
|
||||
|
||||
tty = mkOption {
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
default = "tty10";
|
||||
description = ''
|
||||
The tty device on which syslogd will print important log
|
||||
|
@ -55,7 +55,7 @@ in
|
|||
};
|
||||
|
||||
defaultConfig = mkOption {
|
||||
type = types.string;
|
||||
type = types.lines;
|
||||
default = defaultConf;
|
||||
description = ''
|
||||
The default <filename>syslog.conf</filename> file configures a
|
||||
|
@ -73,7 +73,7 @@ in
|
|||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.string;
|
||||
type = types.lines;
|
||||
default = "";
|
||||
example = "news.* -/var/log/news";
|
||||
description = ''
|
||||
|
|
|
@ -35,7 +35,7 @@ in
|
|||
|
||||
bind = mkOption {
|
||||
default = "0.0.0.0";
|
||||
type = with types; uniq string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
Bind over an IPv4 address instead of any.
|
||||
'';
|
||||
|
@ -44,7 +44,7 @@ in
|
|||
logFile = mkOption {
|
||||
default = "/var/log/freepopsd";
|
||||
example = "syslog";
|
||||
type = with types; uniq string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
Filename of the log file or syslog to rely on the logging daemon.
|
||||
'';
|
||||
|
@ -53,7 +53,7 @@ in
|
|||
suid = {
|
||||
user = mkOption {
|
||||
default = "nobody";
|
||||
type = with types; uniq string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
User name under which freepopsd will be after binding the port.
|
||||
'';
|
||||
|
@ -61,7 +61,7 @@ in
|
|||
|
||||
group = mkOption {
|
||||
default = "nogroup";
|
||||
type = with types; uniq string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
Group under which freepopsd will be after binding the port.
|
||||
'';
|
||||
|
|
|
@ -6,7 +6,7 @@ let
|
|||
|
||||
cfg = config.nix;
|
||||
|
||||
inherit (config.environment) nix;
|
||||
nix = cfg.package;
|
||||
|
||||
makeNixBuildUser = nr:
|
||||
{ name = "nixbld${toString nr}";
|
||||
|
@ -55,19 +55,20 @@ in
|
|||
|
||||
options = {
|
||||
|
||||
environment.nix = mkOption {
|
||||
default = pkgs.nix;
|
||||
merge = mergeOneOption;
|
||||
description = ''
|
||||
This option specifies the Nix package instance to use throughout the system.
|
||||
'';
|
||||
};
|
||||
|
||||
nix = {
|
||||
|
||||
package = mkOption {
|
||||
type = types.path;
|
||||
default = pkgs.nix;
|
||||
description = ''
|
||||
This option specifies the Nix package instance to use throughout the system.
|
||||
'';
|
||||
};
|
||||
|
||||
maxJobs = mkOption {
|
||||
type = types.int;
|
||||
default = 1;
|
||||
example = 2;
|
||||
example = 64;
|
||||
description = "
|
||||
This option defines the maximum number of jobs that Nix will try
|
||||
to build in parallel. The default is 1. You should generally
|
||||
|
@ -77,8 +78,8 @@ in
|
|||
};
|
||||
|
||||
useChroot = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = "
|
||||
If set, Nix will perform builds in a chroot-environment that it
|
||||
will set up automatically for each build. This prevents
|
||||
|
@ -88,6 +89,7 @@ in
|
|||
};
|
||||
|
||||
chrootDirs = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = [ "/dev" "/proc" ];
|
||||
description =
|
||||
|
@ -98,15 +100,17 @@ in
|
|||
};
|
||||
|
||||
extraOptions = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
example = "
|
||||
example = ''
|
||||
gc-keep-outputs = true
|
||||
gc-keep-derivations = true
|
||||
";
|
||||
'';
|
||||
description = "Additional text appended to <filename>nix.conf</filename>.";
|
||||
};
|
||||
|
||||
distributedBuilds = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to distribute builds to the machines listed in
|
||||
|
@ -115,22 +119,25 @@ in
|
|||
};
|
||||
|
||||
daemonNiceLevel = mkOption {
|
||||
type = types.int;
|
||||
default = 0;
|
||||
description = "
|
||||
description = ''
|
||||
Nix daemon process priority. This priority propagates to build processes.
|
||||
0 is the default Unix process priority, 20 is the lowest.
|
||||
";
|
||||
'';
|
||||
};
|
||||
|
||||
daemonIONiceLevel = mkOption {
|
||||
type = types.int;
|
||||
default = 0;
|
||||
description = "
|
||||
description = ''
|
||||
Nix daemon process I/O priority. This priority propagates to build processes.
|
||||
0 is the default Unix process I/O priority, 7 is the lowest.
|
||||
";
|
||||
'';
|
||||
};
|
||||
|
||||
buildMachines = mkOption {
|
||||
type = types.listOf types.attrs;
|
||||
default = [];
|
||||
example = [
|
||||
{ hostName = "voila.labs.cs.uu.nl";
|
||||
|
@ -160,7 +167,7 @@ in
|
|||
user name to be used for the SSH connection
|
||||
(<varname>sshUser</varname>), the Nix system type
|
||||
(<varname>system</varname>, e.g.,
|
||||
<literal>\"i686-linux\"</literal>), the maximum number of
|
||||
<literal>"i686-linux"</literal>), the maximum number of
|
||||
jobs to be run in parallel on that machine
|
||||
(<varname>maxJobs</varname>), the path to the SSH private
|
||||
key to be used to connect (<varname>sshKey</varname>), a
|
||||
|
@ -176,24 +183,26 @@ in
|
|||
};
|
||||
|
||||
proxy = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "
|
||||
description = ''
|
||||
This option specifies the proxy to use for fetchurl. The real effect
|
||||
is just exporting http_proxy, https_proxy and ftp_proxy with that
|
||||
value.
|
||||
";
|
||||
'';
|
||||
example = "http://127.0.0.1:3128";
|
||||
};
|
||||
|
||||
# Environment variables for running Nix.
|
||||
envVars = mkOption {
|
||||
type = types.attrs;
|
||||
internal = true;
|
||||
default = {};
|
||||
type = types.attrs;
|
||||
description = "Environment variables used by Nix.";
|
||||
};
|
||||
|
||||
nrBuildUsers = mkOption {
|
||||
type = types.int;
|
||||
default = 10;
|
||||
description = ''
|
||||
Number of <literal>nixbld</literal> user accounts created to
|
||||
|
@ -204,6 +213,7 @@ in
|
|||
};
|
||||
|
||||
readOnlyStore = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
If set, NixOS will enforce the immutability of the Nix store
|
||||
|
@ -214,8 +224,8 @@ in
|
|||
};
|
||||
|
||||
binaryCaches = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ http://cache.nixos.org/ ];
|
||||
type = types.listOf types.string;
|
||||
description = ''
|
||||
List of binary cache URLs used to obtain pre-built binaries
|
||||
of Nix packages.
|
||||
|
@ -223,9 +233,9 @@ in
|
|||
};
|
||||
|
||||
trustedBinaryCaches = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ ];
|
||||
example = [ http://hydra.nixos.org/ ];
|
||||
type = types.listOf types.string;
|
||||
description = ''
|
||||
List of binary cache URLs that non-root users can use (in
|
||||
addition to those specified using
|
||||
|
@ -302,7 +312,7 @@ in
|
|||
}
|
||||
|
||||
// optionalAttrs cfg.distributedBuilds {
|
||||
NIX_BUILD_HOOK = "${config.environment.nix}/libexec/nix/build-remote.pl";
|
||||
NIX_BUILD_HOOK = "${nix}/libexec/nix/build-remote.pl";
|
||||
NIX_REMOTE_SYSTEMS = "/etc/nix/machines";
|
||||
NIX_CURRENT_LOAD = "/run/nix/current-load";
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ in
|
|||
|
||||
dates = mkOption {
|
||||
default = "03:15";
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
Specification (in the format described by
|
||||
<citerefentry><refentrytitle>systemd.time</refentrytitle>
|
||||
|
@ -34,7 +34,7 @@ in
|
|||
options = mkOption {
|
||||
default = "";
|
||||
example = "--max-freed $((64 * 1024**3))";
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
Options given to <filename>nix-collect-garbage</filename> when the
|
||||
garbage collector is run automatically.
|
||||
|
@ -52,7 +52,7 @@ in
|
|||
|
||||
systemd.services.nix-gc =
|
||||
{ description = "Nix Garbage Collector";
|
||||
script = "exec ${config.environment.nix}/bin/nix-collect-garbage ${cfg.options}";
|
||||
script = "exec ${config.nix.package}/bin/nix-collect-garbage ${cfg.options}";
|
||||
startAt = optionalString cfg.automatic cfg.dates;
|
||||
};
|
||||
|
||||
|
|
|
@ -16,13 +16,15 @@ let
|
|||
system.nixosRevision = config.system.nixosRevision;
|
||||
};
|
||||
|
||||
eval = evalModules {
|
||||
modules = [ versionModule ] ++ baseModules;
|
||||
args = (removeAttrs extraArgs ["config" "options"]) // { modules = [ ]; };
|
||||
};
|
||||
|
||||
manual = import ../../../doc/manual {
|
||||
inherit pkgs;
|
||||
revision = config.system.nixosRevision;
|
||||
options = (fixMergeModules ([ versionModule ] ++ baseModules)
|
||||
(removeAttrs extraArgs ["config" "options"]) // {
|
||||
modules = [ ];
|
||||
}).options;
|
||||
options = eval.options;
|
||||
};
|
||||
|
||||
entry = "${manual.manual}/share/doc/nixos/manual.html";
|
||||
|
@ -51,14 +53,15 @@ in
|
|||
options = {
|
||||
|
||||
services.nixosManual.enable = mkOption {
|
||||
default = true;
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to build the NixOS manual pages.
|
||||
'';
|
||||
};
|
||||
|
||||
services.nixosManual.showManual = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to show the NixOS manual on one of the virtual
|
||||
|
@ -74,6 +77,7 @@ in
|
|||
};
|
||||
|
||||
services.nixosManual.browser = mkOption {
|
||||
type = types.path;
|
||||
default = "${pkgs.w3m}/bin/w3m";
|
||||
description = ''
|
||||
Browser used to show the manual.
|
||||
|
|
|
@ -17,6 +17,7 @@ in
|
|||
options = {
|
||||
|
||||
services.rogue.enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to enable the Rogue game on one of the virtual
|
||||
|
@ -25,6 +26,7 @@ in
|
|||
};
|
||||
|
||||
services.rogue.tty = mkOption {
|
||||
type = types.str;
|
||||
default = "tty9";
|
||||
description = ''
|
||||
Virtual console on which to run Rogue.
|
||||
|
|
|
@ -22,58 +22,56 @@ in
|
|||
enable = mkOption {
|
||||
default = false;
|
||||
description = "
|
||||
Whether to enable the synergy client (receive keyboard and mouse events from a synergy server)
|
||||
Whether to enable the Synergy client (receive keyboard and mouse events from a Synergy server).
|
||||
";
|
||||
};
|
||||
screenName = mkOption {
|
||||
default = "";
|
||||
description = "
|
||||
use screen-name instead the hostname to identify
|
||||
description = ''
|
||||
Use the given name instead of the hostname to identify
|
||||
ourselves to the server.
|
||||
";
|
||||
'';
|
||||
};
|
||||
serverAddress = mkOption {
|
||||
description = "
|
||||
description = ''
|
||||
The server address is of the form: [hostname][:port]. The
|
||||
hostname must be the address or hostname of the server. The
|
||||
port overrides the default port, 24800.
|
||||
";
|
||||
'';
|
||||
};
|
||||
autoStart = mkOption {
|
||||
default = true;
|
||||
type = types.bool;
|
||||
description = "Whether synergy-client should be started automatically.";
|
||||
description = "Whether the Synergy client should be started automatically.";
|
||||
};
|
||||
};
|
||||
|
||||
server = {
|
||||
enable = mkOption {
|
||||
default = false;
|
||||
description = "
|
||||
Whether to enable the synergy server (send keyboard and mouse events)
|
||||
";
|
||||
description = ''
|
||||
Whether to enable the Synergy server (send keyboard and mouse events).
|
||||
'';
|
||||
};
|
||||
configFile = mkOption {
|
||||
default = "/etc/synergy-server.conf";
|
||||
description = "
|
||||
The synergy server configuration file. open upstart-jobs/synergy.nix to see an example
|
||||
";
|
||||
description = "The Synergy server configuration file.";
|
||||
};
|
||||
screenName = mkOption {
|
||||
default = "";
|
||||
description = "
|
||||
use screen-name instead the hostname to identify
|
||||
description = ''
|
||||
Use the given name instead of the hostname to identify
|
||||
this screen in the configuration.
|
||||
";
|
||||
'';
|
||||
};
|
||||
address = mkOption {
|
||||
default = "";
|
||||
description = "listen for clients on the given address";
|
||||
description = "Address on which to listen for clients.";
|
||||
};
|
||||
autoStart = mkOption {
|
||||
default = true;
|
||||
type = types.bool;
|
||||
description = "Whether synergy-server should be started automatically.";
|
||||
description = "Whether the Synergy server should be started automatically.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -26,7 +26,7 @@ in {
|
|||
|
||||
example = "ae0aa6a8f08efa988ba0a17578f009ab";
|
||||
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
};
|
||||
|
||||
hostname = mkOption {
|
||||
|
|
|
@ -8,7 +8,7 @@ let
|
|||
|
||||
dataDir = "/var/db/graphite";
|
||||
carbonOpts = name: with config.ids; ''
|
||||
--nodaemon --syslog --prefix=${name} \
|
||||
--nodaemon --syslog --prefix=${name} --pidfile /var/run/${name}.pid \
|
||||
--uid ${toString uids.graphite} --gid ${toString uids.graphite} ${name}
|
||||
'';
|
||||
carbonEnv = {
|
||||
|
@ -32,13 +32,13 @@ in {
|
|||
host = mkOption {
|
||||
description = "Graphite web frontend listen address";
|
||||
default = "127.0.0.1";
|
||||
types = type.uniq types.string;
|
||||
type = types.str;
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
description = "Graphite web frontend port";
|
||||
default = "8080";
|
||||
types = type.uniq types.string;
|
||||
type = types.str;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -52,8 +52,11 @@ in {
|
|||
PICKLE_RECEIVER_INTERFACE = 127.0.0.1
|
||||
LINE_RECEIVER_INTERFACE = 127.0.0.1
|
||||
CACHE_QUERY_INTERFACE = 127.0.0.1
|
||||
# Do not log every update
|
||||
LOG_UPDATES = False
|
||||
LOG_CACHE_HITS = False
|
||||
'';
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
};
|
||||
|
||||
enableCache = mkOption {
|
||||
|
|
|
@ -12,16 +12,15 @@ let
|
|||
|
||||
device = mkOption {
|
||||
example = "/dev/sda";
|
||||
type = types.string;
|
||||
type = types.str;
|
||||
description = "Location of the device.";
|
||||
};
|
||||
|
||||
options = mkOption {
|
||||
default = "";
|
||||
example = "-d sat";
|
||||
type = types.string;
|
||||
merge = pkgs.lib.concatStringsSep " ";
|
||||
description = "Options that determine how smartd monitors the device";
|
||||
type = types.separatedString " ";
|
||||
description = "Options that determine how smartd monitors the device.";
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ in
|
|||
host = mkOption {
|
||||
description = "Address that statsd listens on over UDP";
|
||||
default = "127.0.0.1";
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
|
@ -48,7 +48,7 @@ in
|
|||
mgmt_address = mkOption {
|
||||
description = "Address to run managment TCP interface on";
|
||||
default = "127.0.0.1";
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
};
|
||||
|
||||
mgmt_port = mkOption {
|
||||
|
@ -65,7 +65,7 @@ in
|
|||
graphiteHost = mkOption {
|
||||
description = "Hostname or IP of Graphite server";
|
||||
default = "127.0.0.1";
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
};
|
||||
|
||||
graphitePort = mkOption {
|
||||
|
@ -77,7 +77,7 @@ in
|
|||
extraConfig = mkOption {
|
||||
default = "";
|
||||
description = "Extra configuration options for statsd";
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -15,7 +15,7 @@ let
|
|||
# This can be infered from the UPS model by looking at
|
||||
# /nix/store/nut/share/driver.list
|
||||
driver = mkOption {
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
Specify the program to run to talk to this UPS. apcsmart,
|
||||
bestups, and sec are some examples.
|
||||
|
@ -23,7 +23,7 @@ let
|
|||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
The serial port to which your UPS is connected. /dev/ttyS0 is
|
||||
usually the first port on Linux boxes, for example.
|
||||
|
@ -115,7 +115,7 @@ in
|
|||
# This option is not used yet.
|
||||
mode = mkOption {
|
||||
default = "standalone";
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
The MODE determines which part of the NUT is to be started, and
|
||||
which configuration files must be modified.
|
||||
|
@ -142,7 +142,7 @@ in
|
|||
|
||||
schedulerRules = mkOption {
|
||||
example = "/etc/nixos/upssched.conf";
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
File which contains the rules to handle UPS events.
|
||||
'';
|
||||
|
|
|
@ -50,7 +50,7 @@ in
|
|||
};
|
||||
|
||||
hostName = mkOption {
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
description = ''Host name advertised on the LAN.'';
|
||||
};
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ in
|
|||
|
||||
authMode = mkOption {
|
||||
default = "Open";
|
||||
check = authModeCheck;
|
||||
type = types.addCheck types.str authModeCheck;
|
||||
description = ''
|
||||
The following authentication modes are available:
|
||||
Open -- Accept connections from anyone, use NickServ for user authentication.
|
||||
|
|
|
@ -39,7 +39,7 @@ in
|
|||
};
|
||||
|
||||
netbios_hostname = mkOption {
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
description = ''
|
||||
The hostname of your machine.
|
||||
'';
|
||||
|
|
|
@ -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
|
||||
'';
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@ let
|
|||
|
||||
inherit (pkgs) dhcpcd;
|
||||
|
||||
# Don't start dhclient on explicitly configured interfaces or on
|
||||
# Don't start dhcpcd on explicitly configured interfaces or on
|
||||
# interfaces that are part of a bridge.
|
||||
ignoredInterfaces =
|
||||
map (i: i.name) (filter (i: i.ipAddress != null) (attrValues config.networking.interfaces))
|
||||
|
|
|
@ -15,7 +15,7 @@ let
|
|||
authoritative;
|
||||
ddns-update-style ad-hoc;
|
||||
log-facility local1; # see dhcpd.nix
|
||||
|
||||
|
||||
${cfg.extraConfig}
|
||||
|
||||
${pkgs.lib.concatMapStrings
|
||||
|
@ -30,13 +30,13 @@ let
|
|||
'';
|
||||
|
||||
in
|
||||
|
||||
|
||||
{
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
|
||||
services.dhcpd = {
|
||||
|
||||
enable = mkOption {
|
||||
|
@ -48,16 +48,16 @@ in
|
|||
|
||||
extraConfig = mkOption {
|
||||
default = "";
|
||||
example = "
|
||||
example = ''
|
||||
option subnet-mask 255.255.255.0;
|
||||
option broadcast-address 192.168.1.255;
|
||||
option routers 192.168.1.5;
|
||||
option domain-name-servers 130.161.158.4, 130.161.33.17, 130.161.180.1;
|
||||
option domain-name \"example.org\";
|
||||
option domain-name "example.org";
|
||||
subnet 192.168.1.0 netmask 255.255.255.0 {
|
||||
range 192.168.1.100 192.168.1.200;
|
||||
}
|
||||
";
|
||||
'';
|
||||
description = "
|
||||
Extra text to be appended to the DHCP server configuration
|
||||
file. Currently, you almost certainly need to specify
|
||||
|
@ -100,9 +100,9 @@ in
|
|||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
###### implementation
|
||||
|
||||
|
@ -127,5 +127,5 @@ in
|
|||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ in
|
|||
options = {
|
||||
|
||||
networking.firewall.enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description =
|
||||
''
|
||||
|
@ -64,6 +65,7 @@ in
|
|||
};
|
||||
|
||||
networking.firewall.logRefusedConnections = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description =
|
||||
''
|
||||
|
@ -72,6 +74,7 @@ in
|
|||
};
|
||||
|
||||
networking.firewall.logRefusedPackets = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description =
|
||||
''
|
||||
|
@ -82,6 +85,7 @@ in
|
|||
};
|
||||
|
||||
networking.firewall.logRefusedUnicastsOnly = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description =
|
||||
''
|
||||
|
@ -93,6 +97,7 @@ in
|
|||
};
|
||||
|
||||
networking.firewall.rejectPackets = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description =
|
||||
''
|
||||
|
@ -193,6 +198,7 @@ in
|
|||
};
|
||||
|
||||
networking.firewall.extraCommands = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
example = "iptables -A INPUT -p icmp -j ACCEPT";
|
||||
description =
|
||||
|
@ -209,11 +215,8 @@ in
|
|||
|
||||
###### implementation
|
||||
|
||||
# !!! Maybe if `enable' is false, the firewall should still be built
|
||||
# but not started by default. However, currently nixos-rebuild
|
||||
# doesn't deal with such Upstart jobs properly (it starts them if
|
||||
# they are changed, regardless of whether the start condition
|
||||
# holds).
|
||||
# FIXME: Maybe if `enable' is false, the firewall should still be
|
||||
# built but not started by default?
|
||||
config = mkIf cfg.enable {
|
||||
|
||||
networking.firewall.trustedInterfaces = [ "lo" ];
|
||||
|
|
|
@ -15,38 +15,35 @@ in
|
|||
default = false;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Enable the gogoclient ipv6 tunnel.
|
||||
Enable the gogoCLIENT IPv6 tunnel.
|
||||
'';
|
||||
};
|
||||
autorun = mkOption {
|
||||
default = true;
|
||||
description = "
|
||||
Switch to false to create upstart-job and configuration,
|
||||
but not run it automatically
|
||||
";
|
||||
description = ''
|
||||
Whether to automatically start the tunnel.
|
||||
'';
|
||||
};
|
||||
|
||||
username = mkOption {
|
||||
default = "";
|
||||
description = "
|
||||
description = ''
|
||||
Your Gateway6 login name, if any.
|
||||
";
|
||||
'';
|
||||
};
|
||||
|
||||
password = mkOption {
|
||||
default = "";
|
||||
type = types.string;
|
||||
description = "
|
||||
Path to a file (as a string), containing your gogonet password, if any.
|
||||
";
|
||||
description = ''
|
||||
Path to a file (as a string), containing your gogoNET password, if any.
|
||||
'';
|
||||
};
|
||||
|
||||
server = mkOption {
|
||||
default = "anonymous.freenet6.net";
|
||||
example = "broker.freenet6.net";
|
||||
description = "
|
||||
Used Gateway6 server.
|
||||
";
|
||||
description = "The Gateway6 server to be used.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
87
nixos/modules/services/networking/haproxy.nix
Normal file
87
nixos/modules/services/networking/haproxy.nix
Normal 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;
|
||||
};
|
||||
}
|
|
@ -9,10 +9,7 @@ let
|
|||
cfg = config.networking.interfaceMonitor;
|
||||
|
||||
# The ifplugd action script, which is called whenever the link
|
||||
# status changes (i.e., a cable is plugged in or unplugged). We do
|
||||
# nothing when a cable is unplugged. When a cable is plugged in, we
|
||||
# restart dhclient, which will hopefully give us a new IP address
|
||||
# if appropriate.
|
||||
# status changes (i.e., a cable is plugged in or unplugged).
|
||||
plugScript = pkgs.writeScript "ifplugd.action"
|
||||
''
|
||||
#! ${pkgs.stdenv.shell}
|
||||
|
@ -30,17 +27,19 @@ in
|
|||
options = {
|
||||
|
||||
networking.interfaceMonitor.enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
If <literal>true</literal>, monitor Ethernet interfaces for
|
||||
cables being plugged in or unplugged. When this occurs, the
|
||||
<command>dhclient</command> service is restarted to
|
||||
automatically obtain a new IP address. This is useful for
|
||||
roaming users (laptops).
|
||||
commands specified in
|
||||
<option>networking.interfaceMonitor.commands</option> are
|
||||
executed.
|
||||
'';
|
||||
};
|
||||
|
||||
networking.interfaceMonitor.beep = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
If <literal>true</literal>, beep when an Ethernet cable is
|
||||
|
@ -49,6 +48,7 @@ in
|
|||
};
|
||||
|
||||
networking.interfaceMonitor.commands = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Shell commands to be executed when the link status of an
|
||||
|
|
|
@ -32,21 +32,21 @@ in
|
|||
};
|
||||
|
||||
ip = mkOption {
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "Assigned ip address or ip range";
|
||||
example = "172.16.10.1/24";
|
||||
};
|
||||
|
||||
domain = mkOption {
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "Domain or subdomain of which nameservers point to us";
|
||||
example = "tunnel.mydomain.com";
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.uniq types.string;
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "Additional command line parameters";
|
||||
example = "-P mysecurepassword -l 192.168.1.10 -p 23";
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue