Files
nix-stuff/common/units-impl.nix

128 lines
4.6 KiB
Nix
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
config,
lib,
pkgs,
vaculib,
...
}:
let
inherit (lib) mkOption types;
unitNameRegex =
let
# Unit names cannot begin or end with an underscore (_), a comma (,) or a decimal point (.). Names must not contain any of the operator characters +, -, *, /, |, ^, ;, ~, the comment character #, or parentheses. To facilitate copying and pasting from documents, several typographical characters are converted to operators: the figure dash (U+2012), minus (-; U+2212), and en dash (; U+2013) are converted to the operator -; the multiplication sign (×; U+00D7), N-ary times operator (U+2A09), dot operator (‘⋅’; U+22C5), and middle dot (‘·’; U+00B7) are converted to the operator *; the division sign (‘÷’; U+00F7) is converted to the operator /; and the fraction slash (U+2044) is converted to the operator |; accordingly, none of these characters can appear in unit names.
disallowedAnywhere =
"+*/|^;~#()" + (builtins.fromJSON ''"\u2012\u2212\u2013\u00d7\u2a09\u22c5\u00b7\u00f7\u2044"'');
disallowedMiddle = "-" + disallowedAnywhere;
disallowedAtEnd = "23456789_,." + disallowedAnywhere;
disallowedAtBegin = "-01" + disallowedAtEnd;
anyExcept = chars: "[^${lib.escapeRegex chars}]";
singleChar = anyExcept disallowedAtBegin;
multiChar = "${anyExcept disallowedAtBegin}${anyExcept disallowedMiddle}*${anyExcept disallowedAtEnd}";
numberSuffix = regex: "${regex}_[0-9\\.,]+";
fullRegex = "${singleChar}|${multiChar}|${numberSuffix singleChar}|${numberSuffix multiChar}";
in
fullRegex;
unitsAttrsType = types.addCheck (types.attrsOf types.str) (
attrs: builtins.all (name: (builtins.match unitNameRegex name) != null) (builtins.attrNames attrs)
);
unitsDir = pkgs.stdenvNoCC.mkDerivation {
name = "vacu-units-files";
src = pkgs.units.src;
phases = [
"unpackPhase"
"installPhase"
];
installPhase = ''
mkdir -p "$out"
cp {definitions,elements}.units "$out"
ln -s ${../units/currency.units} "$out"/currency.units
ln -s ${../units/cpi.units} "$out"/cpi.units
printf '%s' ${lib.escapeShellArg config.vacu.units.lines} > "$out"/vacu.units
'';
};
in
{
options.vacu.units = {
originalPackage = mkOption {
type = types.package;
default = pkgs.units.override { enableCurrenciesUpdater = false; };
defaultText = "pkgs.units.override { ... }";
};
finalPackage = mkOption {
type = types.package;
readOnly = true;
};
check = mkOption {
type = types.package;
readOnly = true;
};
generatedConfigDir = mkOption {
readOnly = true;
type = types.package;
};
generatedConfigFile = mkOption {
readOnly = true;
type = types.pathInStore;
};
lines = mkOption {
default = "";
type = types.lines;
};
extraUnits = mkOption {
type = unitsAttrsType;
default = { };
};
};
config = lib.mkMerge [
{
vacu.units = {
finalPackage = vaculib.makeWrapper {
original = config.vacu.units.originalPackage;
new = "units";
prepend_flags = [
"--file"
config.vacu.units.generatedConfigFile
];
};
generatedConfigDir = unitsDir;
generatedConfigFile = "${unitsDir}/vacu.units";
lines = lib.mkOrder 750 ''
# default units file, includes elements.units, currency.units, cpi.units
!include definitions.units
'';
};
vacu.textChecks.units-config = ''
# `units --check` returns success (exit code 0) regardless of success >:(
# example output:
# $ result/bin/units --check
# Currency exchange rates from exchangerate-api.com (USD base) on 2024-11-14
# Consumer price index data from US BLS, 2024-02-18
# 7247 units, 125 prefixes, 134 nonlinear units
#
output="$(${lib.getExe config.vacu.units.finalPackage} --check)"
printf '%s' "$output"
filteredLines="$(printf '%s' "$output" \
| grep -v '^\s*$' \
| grep -v 'Currency exchange rates from' \
| grep -v 'Consumer price index data from' \
| grep -vE '[0-9]+ units, [0-9]+ prefixes, [0-9]+ nonlinear units' || true
)"
if [[ -n "$filteredLines" ]]; then
exit 1
fi
touch "$out"
'';
}
{
vacu.units.lines = lib.concatStringsSep "\n" (
lib.mapAttrsToList (name: value: "+${name} ${value}") config.vacu.units.extraUnits
);
}
];
}