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