2020-01-09 12:42:56 +00:00
|
|
|
{ lib, stdenv, poetryLib }: python:
|
2019-11-16 12:57:43 +00:00
|
|
|
let
|
2022-01-19 03:56:47 +12:00
|
|
|
inherit (poetryLib) ireplace;
|
|
|
|
|
|
|
|
targetMachine = poetryLib.getTargetMachine stdenv;
|
2019-11-16 12:57:43 +00:00
|
|
|
|
|
|
|
# Like builtins.substring but with stop being offset instead of length
|
|
|
|
substr = start: stop: s: builtins.substring start (stop - start) s;
|
|
|
|
|
|
|
|
# Strip leading/trailing whitespace from string
|
2020-01-01 14:29:27 +00:00
|
|
|
stripStr = s: lib.elemAt (builtins.split "^ *" (lib.elemAt (builtins.split " *$" s) 0)) 2;
|
2019-11-16 12:57:43 +00:00
|
|
|
findSubExpressionsFun = acc: c: (
|
2020-10-01 19:08:57 +02:00
|
|
|
if c == "(" then
|
|
|
|
(
|
|
|
|
let
|
|
|
|
posNew = acc.pos + 1;
|
|
|
|
isOpen = acc.openP == 0;
|
|
|
|
startPos = if isOpen then posNew else acc.startPos;
|
|
|
|
in
|
|
|
|
acc // {
|
|
|
|
inherit startPos;
|
|
|
|
exprs = acc.exprs ++ [ (substr acc.exprPos (acc.pos - 1) acc.expr) ];
|
|
|
|
pos = posNew;
|
|
|
|
openP = acc.openP + 1;
|
|
|
|
}
|
|
|
|
) else if c == ")" then
|
|
|
|
(
|
|
|
|
let
|
|
|
|
openP = acc.openP - 1;
|
|
|
|
exprs = findSubExpressions (substr acc.startPos acc.pos acc.expr);
|
|
|
|
in
|
|
|
|
acc // {
|
|
|
|
inherit openP;
|
|
|
|
pos = acc.pos + 1;
|
|
|
|
exprs = if openP == 0 then acc.exprs ++ [ exprs ] else acc.exprs;
|
|
|
|
exprPos = if openP == 0 then acc.pos + 1 else acc.exprPos;
|
|
|
|
}
|
|
|
|
) else acc // { pos = acc.pos + 1; }
|
2019-11-16 12:57:43 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
# Make a tree out of expression groups (parens)
|
2020-10-01 19:07:27 +02:00
|
|
|
findSubExpressions = expr':
|
2020-03-14 23:13:51 +00:00
|
|
|
let
|
2020-10-01 19:07:27 +02:00
|
|
|
expr = " " + expr';
|
2020-05-19 21:06:02 +01:00
|
|
|
acc = builtins.foldl'
|
|
|
|
findSubExpressionsFun
|
|
|
|
{
|
|
|
|
exprs = [ ];
|
|
|
|
expr = expr;
|
|
|
|
pos = 0;
|
|
|
|
openP = 0;
|
|
|
|
exprPos = 0;
|
|
|
|
startPos = 0;
|
|
|
|
}
|
|
|
|
(lib.stringToCharacters expr);
|
2020-03-14 23:13:51 +00:00
|
|
|
tailExpr = (substr acc.exprPos acc.pos expr);
|
2020-04-29 14:12:59 +01:00
|
|
|
tailExprs = if tailExpr != "" then [ tailExpr ] else [ ];
|
2020-03-14 23:13:51 +00:00
|
|
|
in
|
2020-04-29 14:12:59 +01:00
|
|
|
acc.exprs ++ tailExprs;
|
2020-03-14 23:13:51 +00:00
|
|
|
parseExpressions = exprs:
|
|
|
|
let
|
|
|
|
splitCond = (
|
|
|
|
s: builtins.map
|
2020-05-19 21:06:02 +01:00
|
|
|
(x: stripStr (if builtins.typeOf x == "list" then (builtins.elemAt x 0) else x))
|
2020-03-14 23:13:51 +00:00
|
|
|
(builtins.split " (and|or) " (s + " "))
|
|
|
|
);
|
|
|
|
mapfn = expr: (
|
|
|
|
if (builtins.match "^ ?$" expr != null) then null # Filter empty
|
|
|
|
else if (builtins.elem expr [ "and" "or" ]) then {
|
|
|
|
type = "bool";
|
|
|
|
value = expr;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
type = "expr";
|
|
|
|
value = expr;
|
|
|
|
}
|
|
|
|
);
|
|
|
|
parse = expr: builtins.filter (x: x != null) (builtins.map mapfn (splitCond expr));
|
|
|
|
in
|
2020-04-29 14:12:59 +01:00
|
|
|
builtins.foldl'
|
|
|
|
(
|
2020-05-19 21:06:02 +01:00
|
|
|
acc: v: acc ++ (if builtins.typeOf v == "string" then parse v else [ (parseExpressions v) ])
|
|
|
|
) [ ]
|
|
|
|
exprs;
|
2019-11-16 12:57:43 +00:00
|
|
|
|
|
|
|
# Transform individual expressions to structured expressions
|
|
|
|
# This function also performs variable substitution, replacing environment markers with their explicit values
|
2020-03-14 23:13:51 +00:00
|
|
|
transformExpressions = exprs:
|
|
|
|
let
|
|
|
|
variables = {
|
|
|
|
os_name = (
|
|
|
|
if python.pname == "jython" then "java"
|
|
|
|
else "posix"
|
2020-01-22 18:32:39 +00:00
|
|
|
);
|
2020-03-14 23:13:51 +00:00
|
|
|
sys_platform = (
|
|
|
|
if stdenv.isLinux then "linux"
|
|
|
|
else if stdenv.isDarwin then "darwin"
|
|
|
|
else throw "Unsupported platform"
|
|
|
|
);
|
2021-01-26 14:29:24 +03:00
|
|
|
platform_machine = targetMachine;
|
2020-04-29 14:12:59 +01:00
|
|
|
platform_python_implementation =
|
|
|
|
let
|
|
|
|
impl = python.passthru.implementation;
|
|
|
|
in
|
2020-03-14 23:13:51 +00:00
|
|
|
(
|
|
|
|
if impl == "cpython" then "CPython"
|
|
|
|
else if impl == "pypy" then "PyPy"
|
|
|
|
else throw "Unsupported implementation ${impl}"
|
|
|
|
);
|
|
|
|
platform_release = ""; # Field not reproducible
|
|
|
|
platform_system = (
|
|
|
|
if stdenv.isLinux then "Linux"
|
|
|
|
else if stdenv.isDarwin then "Darwin"
|
|
|
|
else throw "Unsupported platform"
|
|
|
|
);
|
|
|
|
platform_version = ""; # Field not reproducible
|
|
|
|
python_version = python.passthru.pythonVersion;
|
|
|
|
python_full_version = python.version;
|
|
|
|
implementation_name = python.implementation;
|
|
|
|
implementation_version = python.version;
|
2020-10-01 16:29:03 +02:00
|
|
|
# extra = "";
|
2020-03-14 23:13:51 +00:00
|
|
|
};
|
|
|
|
substituteVar = value: if builtins.hasAttr value variables then (builtins.toJSON variables."${value}") else value;
|
|
|
|
processVar = value: builtins.foldl' (acc: v: v acc) value [
|
|
|
|
stripStr
|
|
|
|
substituteVar
|
|
|
|
];
|
|
|
|
in
|
2020-10-01 19:08:57 +02:00
|
|
|
if builtins.typeOf exprs == "set" then
|
|
|
|
(
|
|
|
|
if exprs.type == "expr" then
|
|
|
|
(
|
|
|
|
let
|
2021-05-27 10:56:33 +02:00
|
|
|
mVal = ''[a-zA-Z0-9\'"_\. \-]+'';
|
2020-10-01 19:08:57 +02:00
|
|
|
mOp = "in|[!=<>]+";
|
|
|
|
e = stripStr exprs.value;
|
2021-07-02 04:14:25 -05:00
|
|
|
m' = builtins.match ''^(${mVal}) +(${mOp}) *(${mVal})$'' e;
|
|
|
|
m = builtins.map stripStr (if m' != null then m' else builtins.match ''^(${mVal}) +(${mOp}) *(${mVal})$'' e);
|
2020-10-01 19:08:57 +02:00
|
|
|
m0 = processVar (builtins.elemAt m 0);
|
|
|
|
m2 = processVar (builtins.elemAt m 2);
|
|
|
|
in
|
|
|
|
{
|
|
|
|
type = "expr";
|
|
|
|
value = {
|
|
|
|
# HACK: We don't know extra at eval time, so we assume the expression is always true
|
|
|
|
op = if m0 == "extra" then "true" else builtins.elemAt m 1;
|
|
|
|
values = [ m0 m2 ];
|
|
|
|
};
|
|
|
|
}
|
|
|
|
) else exprs
|
|
|
|
) else builtins.map transformExpressions exprs;
|
2019-11-16 12:57:43 +00:00
|
|
|
|
|
|
|
# Recursively eval all expressions
|
2020-03-14 23:13:51 +00:00
|
|
|
evalExpressions = exprs:
|
|
|
|
let
|
|
|
|
unmarshal = v: (
|
|
|
|
# TODO: Handle single quoted values
|
|
|
|
if v == "True" then true
|
|
|
|
else if v == "False" then false
|
|
|
|
else builtins.fromJSON v
|
|
|
|
);
|
|
|
|
hasElem = needle: haystack: builtins.elem needle (builtins.filter (x: builtins.typeOf x == "string") (builtins.split " " haystack));
|
|
|
|
op = {
|
2020-10-01 16:29:03 +02:00
|
|
|
"true" = x: y: true;
|
2021-09-16 17:16:59 -04:00
|
|
|
"<=" = x: y: op.">=" y x;
|
2021-09-16 16:59:38 -04:00
|
|
|
"<" = x: y: lib.versionOlder (unmarshal x) (unmarshal y);
|
2020-03-14 23:13:51 +00:00
|
|
|
"!=" = x: y: x != y;
|
|
|
|
"==" = x: y: x == y;
|
2021-09-16 16:59:38 -04:00
|
|
|
">=" = x: y: lib.versionAtLeast (unmarshal x) (unmarshal y);
|
2021-09-16 17:16:59 -04:00
|
|
|
">" = x: y: op."<" y x;
|
2020-03-14 23:13:51 +00:00
|
|
|
"~=" = v: c:
|
|
|
|
let
|
|
|
|
parts = builtins.splitVersion c;
|
|
|
|
pruned = lib.take ((builtins.length parts) - 1) parts;
|
2020-05-19 21:06:02 +01:00
|
|
|
upper = builtins.toString (
|
|
|
|
(lib.toInt (builtins.elemAt pruned (builtins.length pruned - 1))) + 1
|
|
|
|
);
|
2020-03-14 23:13:51 +00:00
|
|
|
upperConstraint = builtins.concatStringsSep "." (ireplace (builtins.length pruned - 1) upper pruned);
|
|
|
|
in
|
2020-04-29 14:12:59 +01:00
|
|
|
op.">=" v c && op."<" v upperConstraint;
|
2020-03-14 23:13:51 +00:00
|
|
|
"===" = x: y: x == y;
|
|
|
|
"in" = x: y:
|
|
|
|
let
|
|
|
|
values = builtins.filter (x: builtins.typeOf x == "string") (builtins.split " " (unmarshal y));
|
|
|
|
in
|
2020-04-29 14:12:59 +01:00
|
|
|
builtins.elem (unmarshal x) values;
|
2020-03-14 23:13:51 +00:00
|
|
|
};
|
|
|
|
in
|
2020-10-01 19:08:57 +02:00
|
|
|
if builtins.typeOf exprs == "set" then
|
|
|
|
(
|
|
|
|
if exprs.type == "expr" then
|
|
|
|
(
|
|
|
|
let
|
|
|
|
expr = exprs;
|
|
|
|
result = (op."${expr.value.op}") (builtins.elemAt expr.value.values 0) (builtins.elemAt expr.value.values 1);
|
|
|
|
in
|
|
|
|
{
|
|
|
|
type = "value";
|
|
|
|
value = result;
|
|
|
|
}
|
|
|
|
) else exprs
|
|
|
|
) else builtins.map evalExpressions exprs;
|
2019-11-16 12:57:43 +00:00
|
|
|
|
|
|
|
# Now that we have performed an eval all that's left to do is to concat the graph into a single bool
|
2020-03-14 23:13:51 +00:00
|
|
|
reduceExpressions = exprs:
|
|
|
|
let
|
|
|
|
cond = {
|
|
|
|
"and" = x: y: x && y;
|
|
|
|
"or" = x: y: x || y;
|
|
|
|
};
|
|
|
|
reduceExpressionsFun = acc: v: (
|
2020-10-01 19:08:57 +02:00
|
|
|
if builtins.typeOf v == "set" then
|
|
|
|
(
|
|
|
|
if v.type == "value" then
|
|
|
|
(
|
|
|
|
acc // {
|
|
|
|
value = cond."${acc.cond}" acc.value v.value;
|
|
|
|
}
|
|
|
|
) else if v.type == "bool" then
|
|
|
|
(
|
|
|
|
acc // {
|
|
|
|
cond = v.value;
|
|
|
|
}
|
|
|
|
) else throw "Unsupported type"
|
|
|
|
) else if builtins.typeOf v == "list" then
|
|
|
|
(
|
|
|
|
let
|
|
|
|
ret = builtins.foldl'
|
|
|
|
reduceExpressionsFun
|
|
|
|
{
|
|
|
|
value = true;
|
|
|
|
cond = "and";
|
|
|
|
}
|
|
|
|
v;
|
|
|
|
in
|
2020-03-14 23:13:51 +00:00
|
|
|
acc // {
|
2020-10-01 19:08:57 +02:00
|
|
|
value = cond."${acc.cond}" acc.value ret.value;
|
2020-03-14 23:13:51 +00:00
|
|
|
}
|
|
|
|
) else throw "Unsupported type"
|
|
|
|
);
|
|
|
|
in
|
2020-04-29 14:12:59 +01:00
|
|
|
(
|
2020-05-19 21:06:02 +01:00
|
|
|
builtins.foldl'
|
|
|
|
reduceExpressionsFun
|
|
|
|
{
|
|
|
|
value = true;
|
|
|
|
cond = "and";
|
|
|
|
}
|
|
|
|
exprs
|
2020-04-29 14:12:59 +01:00
|
|
|
).value;
|
2019-12-11 13:31:22 +01:00
|
|
|
in
|
|
|
|
e: builtins.foldl' (acc: v: v acc) e [
|
2019-11-16 12:57:43 +00:00
|
|
|
findSubExpressions
|
|
|
|
parseExpressions
|
|
|
|
transformExpressions
|
|
|
|
evalExpressions
|
|
|
|
reduceExpressions
|
|
|
|
]
|