f3d94cfc23
This reverts commit cad8957eabcbf73062226d28366fd446c15c8737. It breaks NixOps, but more importantly, such major changes to the module system really need to be reviewed.
320 lines
6.9 KiB
Bash
320 lines
6.9 KiB
Bash
#! @shell@ -e
|
|
|
|
# FIXME: rewrite this in a more suitable language.
|
|
|
|
usage () {
|
|
exec man nixos-option
|
|
exit 1
|
|
}
|
|
|
|
#####################
|
|
# Process Arguments #
|
|
#####################
|
|
|
|
xml=false
|
|
verbose=false
|
|
nixPath=""
|
|
|
|
option=""
|
|
|
|
argfun=""
|
|
for arg; do
|
|
if test -z "$argfun"; then
|
|
case $arg in
|
|
-*)
|
|
sarg="$arg"
|
|
longarg=""
|
|
while test "$sarg" != "-"; do
|
|
case $sarg in
|
|
--*) longarg=$arg; sarg="--";;
|
|
-I) argfun="include_nixpath";;
|
|
-*) usage;;
|
|
esac
|
|
# remove the first letter option
|
|
sarg="-${sarg#??}"
|
|
done
|
|
;;
|
|
*) longarg=$arg;;
|
|
esac
|
|
for larg in $longarg; do
|
|
case $larg in
|
|
--xml) xml=true;;
|
|
--verbose) verbose=true;;
|
|
--help) usage;;
|
|
-*) usage;;
|
|
*) if test -z "$option"; then
|
|
option="$larg"
|
|
else
|
|
usage
|
|
fi;;
|
|
esac
|
|
done
|
|
else
|
|
case $argfun in
|
|
set_*)
|
|
var=$(echo $argfun | sed 's,^set_,,')
|
|
eval $var=$arg
|
|
;;
|
|
include_nixpath)
|
|
nixPath="-I $arg $nixPath"
|
|
;;
|
|
esac
|
|
argfun=""
|
|
fi
|
|
done
|
|
|
|
if $verbose; then
|
|
set -x
|
|
else
|
|
set +x
|
|
fi
|
|
|
|
#############################
|
|
# Process the configuration #
|
|
#############################
|
|
|
|
evalNix(){
|
|
result=$(nix-instantiate ${nixPath:+$nixPath} - --eval-only "$@" 2>&1)
|
|
if test $? -eq 0; then
|
|
cat <<EOF
|
|
$result
|
|
EOF
|
|
return 0;
|
|
else
|
|
sed -n '
|
|
/^error/ { s/, at (string):[0-9]*:[0-9]*//; p; };
|
|
/^warning: Nix search path/ { p; };
|
|
' <<EOF
|
|
$result
|
|
EOF
|
|
return 1;
|
|
fi
|
|
}
|
|
|
|
header="let
|
|
nixos = import <nixpkgs/nixos> {};
|
|
nixpkgs = import <nixpkgs> {};
|
|
in with nixpkgs.lib;
|
|
"
|
|
|
|
# This function is used for converting the option definition path given by
|
|
# the user into accessors for reaching the definition and the declaration
|
|
# corresponding to this option.
|
|
generateAccessors(){
|
|
if result=$(evalNix --strict --show-trace <<EOF
|
|
$header
|
|
|
|
let
|
|
path = "${option:+$option}";
|
|
pathList = splitString "." path;
|
|
|
|
walkOptions = attrsNames: result:
|
|
if attrsNames == [] then
|
|
result
|
|
else
|
|
let name = head attrsNames; rest = tail attrsNames; in
|
|
if isOption result.options then
|
|
walkOptions rest {
|
|
options = result.options.type.getSubOptions "";
|
|
opt = ''(\${result.opt}.type.getSubOptions "")'';
|
|
cfg = ''\${result.cfg}."\${name}"'';
|
|
}
|
|
else
|
|
walkOptions rest {
|
|
options = result.options.\${name};
|
|
opt = ''\${result.opt}."\${name}"'';
|
|
cfg = ''\${result.cfg}."\${name}"'';
|
|
}
|
|
;
|
|
|
|
walkResult = (if path == "" then x: x else walkOptions pathList) {
|
|
options = nixos.options;
|
|
opt = ''nixos.options'';
|
|
cfg = ''nixos.config'';
|
|
};
|
|
|
|
in
|
|
''let option = \${walkResult.opt}; config = \${walkResult.cfg}; in''
|
|
EOF
|
|
)
|
|
then
|
|
echo $result
|
|
else
|
|
# In case of error we want to ignore the error message roduced by the
|
|
# script above, as it is iterating over each attribute, which does not
|
|
# produce a nice error message. The following code is a fallback
|
|
# solution which is cause a nicer error message in the next
|
|
# evaluation.
|
|
echo "\"let option = nixos.options${option:+.$option}; config = nixos.config${option:+.$option}; in\""
|
|
fi
|
|
}
|
|
|
|
header="$header
|
|
$(eval echo $(generateAccessors))
|
|
"
|
|
|
|
evalAttr(){
|
|
local prefix="$1"
|
|
local strict="$2"
|
|
local suffix="$3"
|
|
|
|
# If strict is set, then set it to "true".
|
|
test -n "$strict" && strict=true
|
|
|
|
evalNix ${strict:+--strict} <<EOF
|
|
$header
|
|
|
|
let
|
|
value = $prefix${suffix:+.$suffix};
|
|
strict = ${strict:-false};
|
|
cleanOutput = x: with nixpkgs.lib;
|
|
if isDerivation x then x.outPath
|
|
else if isFunction x then "<CODE>"
|
|
else if strict then
|
|
if isAttrs x then mapAttrs (n: cleanOutput) x
|
|
else if isList x then map cleanOutput x
|
|
else x
|
|
else x;
|
|
in
|
|
cleanOutput value
|
|
EOF
|
|
}
|
|
|
|
evalOpt(){
|
|
evalAttr "option" "" "$@"
|
|
}
|
|
|
|
evalCfg(){
|
|
local strict="$1"
|
|
evalAttr "config" "$strict"
|
|
}
|
|
|
|
findSources(){
|
|
local suffix=$1
|
|
evalNix --strict <<EOF
|
|
$header
|
|
|
|
option.$suffix
|
|
EOF
|
|
}
|
|
|
|
# Given a result from nix-instantiate, recover the list of attributes it
|
|
# contains.
|
|
attrNames() {
|
|
local attributeset=$1
|
|
# sed is used to replace un-printable subset by 0s, and to remove most of
|
|
# the inner-attribute set, which reduce the likelyhood to encounter badly
|
|
# pre-processed input.
|
|
echo "builtins.attrNames $attributeset" | \
|
|
sed 's,<[A-Z]*>,0,g; :inner; s/{[^\{\}]*};/0;/g; t inner;' | \
|
|
evalNix --strict
|
|
}
|
|
|
|
# map a simple list which contains strings or paths.
|
|
nixMap() {
|
|
local fun="$1"
|
|
local list="$2"
|
|
local elem
|
|
for elem in $list; do
|
|
test $elem = '[' -o $elem = ']' && continue;
|
|
$fun $elem
|
|
done
|
|
}
|
|
|
|
# This duplicates the work made below, but it is useful for processing
|
|
# the output of nixos-option with other tools such as nixos-gui.
|
|
if $xml; then
|
|
evalNix --xml --no-location <<EOF
|
|
$header
|
|
|
|
let
|
|
sources = builtins.map (f: f.source);
|
|
opt = option;
|
|
cfg = config;
|
|
in
|
|
|
|
with nixpkgs.lib;
|
|
|
|
let
|
|
optStrict = v:
|
|
let
|
|
traverse = x :
|
|
if isAttrs x then
|
|
if x ? outPath then true
|
|
else all id (mapAttrsFlatten (n: traverseNoAttrs) x)
|
|
else traverseNoAttrs x;
|
|
traverseNoAttrs = x:
|
|
# do not continue in attribute sets
|
|
if isAttrs x then true
|
|
else if isList x then all id (map traverse x)
|
|
else true;
|
|
in assert traverse v; v;
|
|
in
|
|
|
|
if isOption opt then
|
|
optStrict ({}
|
|
// optionalAttrs (opt ? default) { inherit (opt) default; }
|
|
// optionalAttrs (opt ? example) { inherit (opt) example; }
|
|
// optionalAttrs (opt ? description) { inherit (opt) description; }
|
|
// optionalAttrs (opt ? type) { typename = opt.type.name; }
|
|
// optionalAttrs (opt ? options) { inherit (opt) options; }
|
|
// {
|
|
# to disambiguate the xml output.
|
|
_isOption = true;
|
|
declarations = sources opt.declarations;
|
|
definitions = sources opt.definitions;
|
|
value = cfg;
|
|
})
|
|
else
|
|
opt
|
|
EOF
|
|
exit $?
|
|
fi
|
|
|
|
if test "$(evalOpt "_type" 2> /dev/null)" = '"option"'; then
|
|
echo "Value:"
|
|
evalCfg 1
|
|
|
|
echo
|
|
|
|
echo "Default:"
|
|
if default=$(evalOpt "default" - 2> /dev/null); then
|
|
echo "$default"
|
|
else
|
|
echo "<None>"
|
|
fi
|
|
echo
|
|
if example=$(evalOpt "example" - 2> /dev/null); then
|
|
echo "Example:"
|
|
echo "$example"
|
|
echo
|
|
fi
|
|
echo "Description:"
|
|
echo
|
|
eval printf $(evalOpt "description")
|
|
|
|
echo $desc;
|
|
|
|
printPath () { echo " $1"; }
|
|
|
|
echo "Declared by:"
|
|
nixMap printPath "$(findSources "declarations")"
|
|
echo
|
|
echo "Defined by:"
|
|
nixMap printPath "$(findSources "files")"
|
|
echo
|
|
|
|
else
|
|
# echo 1>&2 "Warning: This value is not an option."
|
|
|
|
result=$(evalCfg "")
|
|
if names=$(attrNames "$result" 2> /dev/null); then
|
|
echo 1>&2 "This attribute set contains:"
|
|
escapeQuotes () { eval echo "$1"; }
|
|
nixMap escapeQuotes "$names"
|
|
else
|
|
echo 1>&2 "An error occurred while looking for attribute names."
|
|
echo $result
|
|
fi
|
|
fi
|