|
|
|
@ -1,5 +1,4 @@ |
|
|
|
|
{ lib, stdenv, poetryLib }: python: |
|
|
|
|
|
|
|
|
|
let |
|
|
|
|
inherit (poetryLib) ireplace; |
|
|
|
|
|
|
|
|
@ -37,195 +36,199 @@ let |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
# Make a tree out of expression groups (parens) |
|
|
|
|
findSubExpressions = expr: let |
|
|
|
|
acc = builtins.foldl' findSubExpressionsFun { |
|
|
|
|
exprs = []; |
|
|
|
|
expr = expr; |
|
|
|
|
pos = 0; |
|
|
|
|
openP = 0; |
|
|
|
|
exprPos = 0; |
|
|
|
|
startPos = 0; |
|
|
|
|
} (lib.stringToCharacters expr); |
|
|
|
|
tailExpr = (substr acc.exprPos acc.pos expr); |
|
|
|
|
tailExprs = if tailExpr != "" then [ tailExpr ] else []; |
|
|
|
|
in |
|
|
|
|
acc.exprs ++ tailExprs; |
|
|
|
|
|
|
|
|
|
parseExpressions = exprs: let |
|
|
|
|
splitCond = ( |
|
|
|
|
s: builtins.map |
|
|
|
|
(x: stripStr (if builtins.typeOf x == "list" then (builtins.elemAt x 0) else x)) |
|
|
|
|
(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; |
|
|
|
|
} |
|
|
|
|
); |
|
|
|
|
findSubExpressions = expr: |
|
|
|
|
let |
|
|
|
|
acc = builtins.foldl' findSubExpressionsFun { |
|
|
|
|
exprs = []; |
|
|
|
|
expr = expr; |
|
|
|
|
pos = 0; |
|
|
|
|
openP = 0; |
|
|
|
|
exprPos = 0; |
|
|
|
|
startPos = 0; |
|
|
|
|
} (lib.stringToCharacters expr); |
|
|
|
|
tailExpr = (substr acc.exprPos acc.pos expr); |
|
|
|
|
tailExprs = if tailExpr != "" then [ tailExpr ] else []; |
|
|
|
|
in |
|
|
|
|
acc.exprs ++ tailExprs; |
|
|
|
|
|
|
|
|
|
parseExpressions = exprs: |
|
|
|
|
let |
|
|
|
|
splitCond = ( |
|
|
|
|
s: builtins.map |
|
|
|
|
(x: stripStr (if builtins.typeOf x == "list" then (builtins.elemAt x 0) else x)) |
|
|
|
|
(builtins.split " (and|or) " (s + " ")) |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
parse = expr: builtins.filter (x: x != null) (builtins.map mapfn (splitCond expr)); |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
in |
|
|
|
|
builtins.foldl' ( |
|
|
|
|
acc: v: acc ++ ( |
|
|
|
|
if builtins.typeOf v == "string" then parse v else [ (parseExpressions v) ] |
|
|
|
|
) |
|
|
|
|
) [] exprs; |
|
|
|
|
parse = expr: builtins.filter (x: x != null) (builtins.map mapfn (splitCond expr)); |
|
|
|
|
in |
|
|
|
|
builtins.foldl' ( |
|
|
|
|
acc: v: acc ++ ( |
|
|
|
|
if builtins.typeOf v == "string" then parse v else [ (parseExpressions v) ] |
|
|
|
|
) |
|
|
|
|
) [] exprs; |
|
|
|
|
|
|
|
|
|
# Transform individual expressions to structured expressions |
|
|
|
|
# This function also performs variable substitution, replacing environment markers with their explicit values |
|
|
|
|
transformExpressions = exprs: let |
|
|
|
|
variables = { |
|
|
|
|
os_name = ( |
|
|
|
|
if python.pname == "jython" then "java" |
|
|
|
|
else "posix" |
|
|
|
|
); |
|
|
|
|
sys_platform = ( |
|
|
|
|
if stdenv.isLinux then "linux" |
|
|
|
|
else if stdenv.isDarwin then "darwin" |
|
|
|
|
else throw "Unsupported platform" |
|
|
|
|
); |
|
|
|
|
platform_machine = stdenv.platform.kernelArch; |
|
|
|
|
platform_python_implementation = let |
|
|
|
|
impl = python.passthru.implementation; |
|
|
|
|
in |
|
|
|
|
( |
|
|
|
|
if impl == "cpython" then "CPython" |
|
|
|
|
else if impl == "pypy" then "PyPy" |
|
|
|
|
else throw "Unsupported implementation ${impl}" |
|
|
|
|
transformExpressions = exprs: |
|
|
|
|
let |
|
|
|
|
variables = { |
|
|
|
|
os_name = ( |
|
|
|
|
if python.pname == "jython" then "java" |
|
|
|
|
else "posix" |
|
|
|
|
); |
|
|
|
|
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; |
|
|
|
|
extra = ""; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
if builtins.typeOf exprs == "set" then ( |
|
|
|
|
if exprs.type == "expr" then ( |
|
|
|
|
let |
|
|
|
|
mVal = ''[a-zA-Z0-9\'"_\. ]+''; |
|
|
|
|
mOp = "in|[!=<>]+"; |
|
|
|
|
e = stripStr exprs.value; |
|
|
|
|
m = builtins.map stripStr (builtins.match ''^(${mVal}) *(${mOp}) *(${mVal})$'' e); |
|
|
|
|
sys_platform = ( |
|
|
|
|
if stdenv.isLinux then "linux" |
|
|
|
|
else if stdenv.isDarwin then "darwin" |
|
|
|
|
else throw "Unsupported platform" |
|
|
|
|
); |
|
|
|
|
platform_machine = stdenv.platform.kernelArch; |
|
|
|
|
platform_python_implementation = let |
|
|
|
|
impl = python.passthru.implementation; |
|
|
|
|
in |
|
|
|
|
{ |
|
|
|
|
type = "expr"; |
|
|
|
|
value = { |
|
|
|
|
op = builtins.elemAt m 1; |
|
|
|
|
values = [ |
|
|
|
|
(processVar (builtins.elemAt m 0)) |
|
|
|
|
(processVar (builtins.elemAt m 2)) |
|
|
|
|
]; |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
) else exprs |
|
|
|
|
) else builtins.map transformExpressions exprs; |
|
|
|
|
( |
|
|
|
|
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; |
|
|
|
|
extra = ""; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
if builtins.typeOf exprs == "set" then ( |
|
|
|
|
if exprs.type == "expr" then ( |
|
|
|
|
let |
|
|
|
|
mVal = ''[a-zA-Z0-9\'"_\. ]+''; |
|
|
|
|
mOp = "in|[!=<>]+"; |
|
|
|
|
e = stripStr exprs.value; |
|
|
|
|
m = builtins.map stripStr (builtins.match ''^(${mVal}) *(${mOp}) *(${mVal})$'' e); |
|
|
|
|
in |
|
|
|
|
{ |
|
|
|
|
type = "expr"; |
|
|
|
|
value = { |
|
|
|
|
op = builtins.elemAt m 1; |
|
|
|
|
values = [ |
|
|
|
|
(processVar (builtins.elemAt m 0)) |
|
|
|
|
(processVar (builtins.elemAt m 2)) |
|
|
|
|
]; |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
) else exprs |
|
|
|
|
) else builtins.map transformExpressions exprs; |
|
|
|
|
|
|
|
|
|
# Recursively eval all expressions |
|
|
|
|
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 = { |
|
|
|
|
"<=" = x: y: (unmarshal x) <= (unmarshal y); |
|
|
|
|
"<" = x: y: (unmarshal x) < (unmarshal y); |
|
|
|
|
"!=" = x: y: x != y; |
|
|
|
|
"==" = x: y: x == y; |
|
|
|
|
">=" = x: y: (unmarshal x) >= (unmarshal y); |
|
|
|
|
">" = x: y: (unmarshal x) > (unmarshal y); |
|
|
|
|
"~=" = v: c: let |
|
|
|
|
parts = builtins.splitVersion c; |
|
|
|
|
pruned = lib.take ((builtins.length parts) - 1) parts; |
|
|
|
|
upper = builtins.toString ( |
|
|
|
|
(lib.toInt (builtins.elemAt pruned (builtins.length pruned - 1))) + 1 |
|
|
|
|
); |
|
|
|
|
upperConstraint = builtins.concatStringsSep "." (ireplace (builtins.length pruned - 1) upper pruned); |
|
|
|
|
in |
|
|
|
|
op.">=" v c && op."<" v upperConstraint; |
|
|
|
|
"===" = x: y: x == y; |
|
|
|
|
"in" = x: y: let |
|
|
|
|
values = builtins.filter (x: builtins.typeOf x == "string") (builtins.split " " (unmarshal y)); |
|
|
|
|
in |
|
|
|
|
builtins.elem (unmarshal x) values; |
|
|
|
|
}; |
|
|
|
|
in |
|
|
|
|
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; |
|
|
|
|
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 = { |
|
|
|
|
"<=" = x: y: (unmarshal x) <= (unmarshal y); |
|
|
|
|
"<" = x: y: (unmarshal x) < (unmarshal y); |
|
|
|
|
"!=" = x: y: x != y; |
|
|
|
|
"==" = x: y: x == y; |
|
|
|
|
">=" = x: y: (unmarshal x) >= (unmarshal y); |
|
|
|
|
">" = x: y: (unmarshal x) > (unmarshal y); |
|
|
|
|
"~=" = v: c: |
|
|
|
|
let |
|
|
|
|
parts = builtins.splitVersion c; |
|
|
|
|
pruned = lib.take ((builtins.length parts) - 1) parts; |
|
|
|
|
upper = builtins.toString ( |
|
|
|
|
(lib.toInt (builtins.elemAt pruned (builtins.length pruned - 1))) + 1 |
|
|
|
|
); |
|
|
|
|
upperConstraint = builtins.concatStringsSep "." (ireplace (builtins.length pruned - 1) upper pruned); |
|
|
|
|
in |
|
|
|
|
op.">=" v c && op."<" v upperConstraint; |
|
|
|
|
"===" = x: y: x == y; |
|
|
|
|
"in" = x: y: |
|
|
|
|
let |
|
|
|
|
values = builtins.filter (x: builtins.typeOf x == "string") (builtins.split " " (unmarshal y)); |
|
|
|
|
in |
|
|
|
|
builtins.elem (unmarshal x) values; |
|
|
|
|
}; |
|
|
|
|
in |
|
|
|
|
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; |
|
|
|
|
|
|
|
|
|
# Now that we have performed an eval all that's left to do is to concat the graph into a single bool |
|
|
|
|
reduceExpressions = exprs: let |
|
|
|
|
cond = { |
|
|
|
|
"and" = x: y: x && y; |
|
|
|
|
"or" = x: y: x || y; |
|
|
|
|
}; |
|
|
|
|
reduceExpressionsFun = acc: v: ( |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
reduceExpressions = exprs: |
|
|
|
|
let |
|
|
|
|
cond = { |
|
|
|
|
"and" = x: y: x && y; |
|
|
|
|
"or" = x: y: x || y; |
|
|
|
|
}; |
|
|
|
|
reduceExpressionsFun = acc: v: ( |
|
|
|
|
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 |
|
|
|
|
acc // { |
|
|
|
|
value = cond."${acc.cond}" acc.value ret.value; |
|
|
|
|
} |
|
|
|
|
) else throw "Unsupported type" |
|
|
|
|
) else if builtins.typeOf v == "list" then ( |
|
|
|
|
let |
|
|
|
|
ret = builtins.foldl' reduceExpressionsFun { |
|
|
|
|
value = true; |
|
|
|
|
cond = "and"; |
|
|
|
|
} v; |
|
|
|
|
in |
|
|
|
|
acc // { |
|
|
|
|
value = cond."${acc.cond}" acc.value ret.value; |
|
|
|
|
} |
|
|
|
|
) else throw "Unsupported type" |
|
|
|
|
); |
|
|
|
|
in |
|
|
|
|
( |
|
|
|
|
builtins.foldl' reduceExpressionsFun { |
|
|
|
|
value = true; |
|
|
|
|
cond = "and"; |
|
|
|
|
} exprs |
|
|
|
|
).value; |
|
|
|
|
|
|
|
|
|
); |
|
|
|
|
in |
|
|
|
|
( |
|
|
|
|
builtins.foldl' reduceExpressionsFun { |
|
|
|
|
value = true; |
|
|
|
|
cond = "and"; |
|
|
|
|
} exprs |
|
|
|
|
).value; |
|
|
|
|
in |
|
|
|
|
e: builtins.foldl' (acc: v: v acc) e [ |
|
|
|
|
findSubExpressions |
|
|
|
|