poetry2nix: 1.7.1 -> 1.8.0
This commit is contained in:
parent
4ad2e1c92e
commit
36debc367e
@ -1,4 +1,4 @@
|
||||
{ pkgs ? import <nixpkgs> {}
|
||||
{ pkgs ? import <nixpkgs> { }
|
||||
, lib ? pkgs.lib
|
||||
, version
|
||||
}:
|
||||
@ -33,8 +33,8 @@ pkgs.stdenv.mkDerivation {
|
||||
mv poetry2nix $out/bin
|
||||
|
||||
wrapProgram $out/bin/poetry2nix --prefix PATH ":" ${lib.makeBinPath [
|
||||
pkgs.nix-prefetch-git
|
||||
]}
|
||||
pkgs.nix-prefetch-git
|
||||
]}
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
@ -1,22 +1,20 @@
|
||||
{ pkgs ? import <nixpkgs> {}
|
||||
{ pkgs ? import <nixpkgs> { }
|
||||
, lib ? pkgs.lib
|
||||
, poetry ? null
|
||||
, poetryLib ? import ./lib.nix { inherit lib pkgs; }
|
||||
}:
|
||||
let
|
||||
inherit (poetryLib) isCompatible readTOML;
|
||||
inherit (poetryLib) isCompatible readTOML moduleName;
|
||||
|
||||
# Poetry2nix version
|
||||
version = "1.7.1";
|
||||
version = "1.8.0";
|
||||
|
||||
/* The default list of poetry2nix override overlays */
|
||||
defaultPoetryOverrides = (import ./overrides.nix { inherit pkgs lib; });
|
||||
|
||||
mkEvalPep508 = import ./pep508.nix {
|
||||
inherit lib poetryLib;
|
||||
stdenv = pkgs.stdenv;
|
||||
};
|
||||
|
||||
getFunctorFn = fn: if builtins.typeOf fn == "set" then fn.__functor else fn;
|
||||
|
||||
# Map SPDX identifiers to license names
|
||||
@ -34,95 +32,99 @@ let
|
||||
, overrides ? [ defaultPoetryOverrides ]
|
||||
, python ? pkgs.python3
|
||||
, pwd ? projectDir
|
||||
, preferWheels ? false
|
||||
}@attrs:
|
||||
let
|
||||
poetryPkg = poetry.override { inherit python; };
|
||||
let
|
||||
poetryPkg = poetry.override { inherit python; };
|
||||
pyProject = readTOML pyproject;
|
||||
poetryLock = readTOML poetrylock;
|
||||
lockFiles =
|
||||
let
|
||||
lockfiles = lib.getAttrFromPath [ "metadata" "files" ] poetryLock;
|
||||
in
|
||||
lib.listToAttrs (lib.mapAttrsToList (n: v: { name = moduleName n; value = v; }) lockfiles);
|
||||
specialAttrs = [
|
||||
"overrides"
|
||||
"poetrylock"
|
||||
"projectDir"
|
||||
"pwd"
|
||||
"preferWheels"
|
||||
];
|
||||
passedAttrs = builtins.removeAttrs attrs specialAttrs;
|
||||
evalPep508 = mkEvalPep508 python;
|
||||
|
||||
pyProject = readTOML pyproject;
|
||||
poetryLock = readTOML poetrylock;
|
||||
lockFiles = lib.getAttrFromPath [ "metadata" "files" ] poetryLock;
|
||||
|
||||
specialAttrs = [
|
||||
"overrides"
|
||||
"poetrylock"
|
||||
"projectDir"
|
||||
"pwd"
|
||||
];
|
||||
passedAttrs = builtins.removeAttrs attrs specialAttrs;
|
||||
|
||||
evalPep508 = mkEvalPep508 python;
|
||||
|
||||
# Filter packages by their PEP508 markers & pyproject interpreter version
|
||||
partitions = let
|
||||
# Filter packages by their PEP508 markers & pyproject interpreter version
|
||||
partitions =
|
||||
let
|
||||
supportsPythonVersion = pkgMeta: if pkgMeta ? marker then (evalPep508 pkgMeta.marker) else true;
|
||||
in
|
||||
lib.partition supportsPythonVersion poetryLock.package;
|
||||
lib.partition supportsPythonVersion poetryLock.package;
|
||||
compatible = partitions.right;
|
||||
incompatible = partitions.wrong;
|
||||
|
||||
compatible = partitions.right;
|
||||
incompatible = partitions.wrong;
|
||||
|
||||
# Create an overriden version of pythonPackages
|
||||
#
|
||||
# We need to avoid mixing multiple versions of pythonPackages in the same
|
||||
# closure as python can only ever have one version of a dependency
|
||||
baseOverlay = self: super:
|
||||
let
|
||||
getDep = depName: self.${depName};
|
||||
|
||||
lockPkgs = builtins.listToAttrs (
|
||||
builtins.map (
|
||||
pkgMeta: rec {
|
||||
name = pkgMeta.name;
|
||||
value = self.mkPoetryDep (
|
||||
pkgMeta // {
|
||||
inherit pwd;
|
||||
source = pkgMeta.source or null;
|
||||
files = lockFiles.${name};
|
||||
pythonPackages = self;
|
||||
sourceSpec = pyProject.tool.poetry.dependencies.${name} or pyProject.tool.poetry.dev-dependencies.${name};
|
||||
}
|
||||
);
|
||||
}
|
||||
) compatible
|
||||
# Create an overriden version of pythonPackages
|
||||
#
|
||||
# We need to avoid mixing multiple versions of pythonPackages in the same
|
||||
# closure as python can only ever have one version of a dependency
|
||||
baseOverlay = self: super:
|
||||
let
|
||||
getDep = depName: self.${depName};
|
||||
lockPkgs = builtins.listToAttrs
|
||||
(
|
||||
builtins.map
|
||||
(
|
||||
pkgMeta: rec {
|
||||
name = moduleName pkgMeta.name;
|
||||
value = self.mkPoetryDep
|
||||
(
|
||||
pkgMeta // {
|
||||
inherit pwd preferWheels;
|
||||
source = pkgMeta.source or null;
|
||||
files = lockFiles.${name};
|
||||
pythonPackages = self;
|
||||
sourceSpec = pyProject.tool.poetry.dependencies.${name} or pyProject.tool.poetry.dev-dependencies.${name};
|
||||
}
|
||||
);
|
||||
}
|
||||
) compatible
|
||||
);
|
||||
in
|
||||
lockPkgs;
|
||||
overlays = builtins.map getFunctorFn (
|
||||
in
|
||||
lockPkgs;
|
||||
overlays = builtins.map getFunctorFn
|
||||
(
|
||||
[
|
||||
(
|
||||
self: super:
|
||||
let
|
||||
hooks = self.callPackage ./hooks {};
|
||||
hooks = self.callPackage ./hooks { };
|
||||
in
|
||||
{
|
||||
mkPoetryDep = self.callPackage ./mk-poetry-dep.nix {
|
||||
inherit pkgs lib python poetryLib;
|
||||
};
|
||||
poetry = poetryPkg;
|
||||
# The canonical name is setuptools-scm
|
||||
setuptools-scm = super.setuptools_scm;
|
||||
{
|
||||
mkPoetryDep = self.callPackage ./mk-poetry-dep.nix {
|
||||
inherit pkgs lib python poetryLib;
|
||||
};
|
||||
poetry = poetryPkg;
|
||||
# The canonical name is setuptools-scm
|
||||
setuptools-scm = super.setuptools_scm;
|
||||
|
||||
inherit (hooks) removePathDependenciesHook poetry2nixFixupHook;
|
||||
}
|
||||
inherit (hooks) pipBuildHook removePathDependenciesHook poetry2nixFixupHook;
|
||||
}
|
||||
)
|
||||
# Null out any filtered packages, we don't want python.pkgs from nixpkgs
|
||||
(self: super: builtins.listToAttrs (builtins.map (x: { name = x.name; value = null; }) incompatible))
|
||||
(self: super: builtins.listToAttrs (builtins.map (x: { name = moduleName x.name; value = null; }) incompatible))
|
||||
# Create poetry2nix layer
|
||||
baseOverlay
|
||||
] ++ # User provided overrides
|
||||
overrides
|
||||
);
|
||||
|
||||
packageOverrides = lib.foldr lib.composeExtensions (self: super: {}) overlays;
|
||||
|
||||
py = python.override { inherit packageOverrides; self = py; };
|
||||
in
|
||||
{
|
||||
python = py;
|
||||
poetryPackages = map (pkg: py.pkgs.${pkg.name}) compatible;
|
||||
poetryLock = poetryLock;
|
||||
inherit pyProject;
|
||||
};
|
||||
packageOverrides = lib.foldr lib.composeExtensions (self: super: { }) overlays;
|
||||
py = python.override { inherit packageOverrides; self = py; };
|
||||
in
|
||||
{
|
||||
python = py;
|
||||
poetryPackages = map (pkg: py.pkgs.${moduleName pkg.name}) compatible;
|
||||
poetryLock = poetryLock;
|
||||
inherit pyProject;
|
||||
};
|
||||
|
||||
/* Returns a package with a python interpreter and all packages specified in the poetry.lock lock file.
|
||||
|
||||
@ -136,15 +138,17 @@ let
|
||||
, overrides ? [ defaultPoetryOverrides ]
|
||||
, pwd ? projectDir
|
||||
, python ? pkgs.python3
|
||||
, preferWheels ? false
|
||||
}:
|
||||
let
|
||||
py = mkPoetryPackages (
|
||||
let
|
||||
py = mkPoetryPackages
|
||||
(
|
||||
{
|
||||
inherit pyproject poetrylock overrides python pwd;
|
||||
inherit pyproject poetrylock overrides python pwd preferWheels;
|
||||
}
|
||||
);
|
||||
in
|
||||
py.python.withPackages (_: py.poetryPackages);
|
||||
in
|
||||
py.python.withPackages (_: py.poetryPackages);
|
||||
|
||||
/* Creates a Python application from pyproject.toml and poetry.lock */
|
||||
mkPoetryApplication =
|
||||
@ -153,79 +157,79 @@ let
|
||||
, pyproject ? projectDir + "/pyproject.toml"
|
||||
, poetrylock ? projectDir + "/poetry.lock"
|
||||
, overrides ? [ defaultPoetryOverrides ]
|
||||
, meta ? {}
|
||||
, meta ? { }
|
||||
, python ? pkgs.python3
|
||||
, pwd ? projectDir
|
||||
, preferWheels ? false
|
||||
, ...
|
||||
}@attrs:
|
||||
let
|
||||
poetryPython = mkPoetryPackages {
|
||||
inherit pyproject poetrylock overrides python pwd;
|
||||
};
|
||||
py = poetryPython.python;
|
||||
let
|
||||
poetryPython = mkPoetryPackages {
|
||||
inherit pyproject poetrylock overrides python pwd preferWheels;
|
||||
};
|
||||
py = poetryPython.python;
|
||||
|
||||
inherit (poetryPython) pyProject;
|
||||
inherit (poetryPython) pyProject;
|
||||
specialAttrs = [
|
||||
"overrides"
|
||||
"poetrylock"
|
||||
"projectDir"
|
||||
"pwd"
|
||||
"pyproject"
|
||||
"preferWheels"
|
||||
];
|
||||
passedAttrs = builtins.removeAttrs attrs specialAttrs;
|
||||
|
||||
specialAttrs = [
|
||||
"overrides"
|
||||
"poetrylock"
|
||||
"projectDir"
|
||||
"pwd"
|
||||
"pyproject"
|
||||
];
|
||||
passedAttrs = builtins.removeAttrs attrs specialAttrs;
|
||||
# Get dependencies and filter out depending on interpreter version
|
||||
getDeps = depAttr:
|
||||
let
|
||||
compat = isCompatible (poetryLib.getPythonVersion py);
|
||||
deps = pyProject.tool.poetry.${depAttr} or { };
|
||||
depAttrs = builtins.map (d: lib.toLower d) (builtins.attrNames deps);
|
||||
in
|
||||
builtins.map
|
||||
(
|
||||
dep:
|
||||
let
|
||||
pkg = py.pkgs."${dep}";
|
||||
constraints = deps.${dep}.python or "";
|
||||
isCompat = compat constraints;
|
||||
in if isCompat then pkg else null
|
||||
) depAttrs;
|
||||
getInputs = attr: attrs.${attr} or [ ];
|
||||
mkInput = attr: extraInputs: getInputs attr ++ extraInputs;
|
||||
buildSystemPkgs = poetryLib.getBuildSystemPkgs {
|
||||
inherit pyProject;
|
||||
pythonPackages = py.pkgs;
|
||||
};
|
||||
in
|
||||
py.pkgs.buildPythonApplication
|
||||
(
|
||||
passedAttrs // {
|
||||
pname = moduleName pyProject.tool.poetry.name;
|
||||
version = pyProject.tool.poetry.version;
|
||||
|
||||
# Get dependencies and filter out depending on interpreter version
|
||||
getDeps = depAttr:
|
||||
let
|
||||
compat = isCompatible py.pythonVersion;
|
||||
deps = pyProject.tool.poetry.${depAttr} or {};
|
||||
depAttrs = builtins.map (d: lib.toLower d) (builtins.attrNames deps);
|
||||
in
|
||||
builtins.map (
|
||||
dep:
|
||||
let
|
||||
pkg = py.pkgs."${dep}";
|
||||
constraints = deps.${dep}.python or "";
|
||||
isCompat = compat constraints;
|
||||
in
|
||||
if isCompat then pkg else null
|
||||
) depAttrs;
|
||||
inherit src;
|
||||
|
||||
getInputs = attr: attrs.${attr} or [];
|
||||
mkInput = attr: extraInputs: getInputs attr ++ extraInputs;
|
||||
format = "pyproject";
|
||||
|
||||
buildSystemPkgs = poetryLib.getBuildSystemPkgs {
|
||||
inherit pyProject;
|
||||
pythonPackages = py.pkgs;
|
||||
};
|
||||
in
|
||||
py.pkgs.buildPythonApplication (
|
||||
passedAttrs // {
|
||||
pname = pyProject.tool.poetry.name;
|
||||
version = pyProject.tool.poetry.version;
|
||||
buildInputs = mkInput "buildInputs" buildSystemPkgs;
|
||||
propagatedBuildInputs = mkInput "propagatedBuildInputs" (getDeps "dependencies") ++ ([ py.pkgs.setuptools ]);
|
||||
nativeBuildInputs = mkInput "nativeBuildInputs" [ pkgs.yj py.pkgs.removePathDependenciesHook ];
|
||||
checkInputs = mkInput "checkInputs" (getDeps "dev-dependencies");
|
||||
|
||||
inherit src;
|
||||
passthru = {
|
||||
python = py;
|
||||
};
|
||||
|
||||
format = "pyproject";
|
||||
meta = meta // {
|
||||
inherit (pyProject.tool.poetry) description homepage;
|
||||
inherit (py.meta) platforms;
|
||||
license = getLicenseBySpdxId (pyProject.tool.poetry.license or "unknown");
|
||||
};
|
||||
|
||||
buildInputs = mkInput "buildInputs" buildSystemPkgs;
|
||||
propagatedBuildInputs = mkInput "propagatedBuildInputs" (getDeps "dependencies") ++ ([ py.pkgs.setuptools ]);
|
||||
nativeBuildInputs = mkInput "nativeBuildInputs" [ pkgs.yj py.pkgs.removePathDependenciesHook ];
|
||||
checkInputs = mkInput "checkInputs" (getDeps "dev-dependencies");
|
||||
|
||||
passthru = {
|
||||
python = py;
|
||||
};
|
||||
|
||||
meta = meta // {
|
||||
inherit (pyProject.tool.poetry) description homepage;
|
||||
inherit (py.meta) platforms;
|
||||
license = getLicenseBySpdxId (pyProject.tool.poetry.license or "unknown");
|
||||
};
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
/* Poetry2nix CLI used to supplement SHA-256 hashes for git dependencies */
|
||||
cli = import ./cli.nix { inherit pkgs lib version; };
|
||||
@ -247,7 +251,7 @@ in
|
||||
defaultSet = defaultPoetryOverrides self super;
|
||||
customSet = fn self super;
|
||||
in
|
||||
defaultSet // customSet;
|
||||
defaultSet // customSet;
|
||||
};
|
||||
|
||||
/*
|
||||
|
24
pkgs/development/tools/poetry2nix/poetry2nix/fetch-wheel.sh
Normal file
24
pkgs/development/tools/poetry2nix/poetry2nix/fetch-wheel.sh
Normal file
@ -0,0 +1,24 @@
|
||||
source $stdenv/setup
|
||||
set -euo pipefail
|
||||
|
||||
curl="curl \
|
||||
--location \
|
||||
--max-redirs 20 \
|
||||
--retry 2 \
|
||||
--disable-epsv \
|
||||
--cookie-jar cookies \
|
||||
--insecure \
|
||||
--speed-time 5 \
|
||||
-# \
|
||||
--fail \
|
||||
$curlOpts \
|
||||
$NIX_CURL_FLAGS"
|
||||
|
||||
echo "Trying to fetch wheel with predicted URL: $predictedURL"
|
||||
|
||||
$curl $predictedURL --output $out && exit 0
|
||||
|
||||
echo "Predicted URL '$predictedURL' failed, querying pypi.org"
|
||||
$curl "https://pypi.org/pypi/$pname/json" | jq -r ".releases.\"$version\"[] | select(.filename == \"$file\") | .url" > url
|
||||
url=$(cat url)
|
||||
$curl -k $url --output $out
|
@ -2,31 +2,48 @@
|
||||
, callPackage
|
||||
, makeSetupHook
|
||||
, yj
|
||||
, wheel
|
||||
, pip
|
||||
}:
|
||||
let
|
||||
pythonInterpreter = python.pythonForBuild.interpreter;
|
||||
pythonSitePackages = python.sitePackages;
|
||||
in
|
||||
{
|
||||
|
||||
removePathDependenciesHook = callPackage (
|
||||
{}:
|
||||
removePathDependenciesHook = callPackage
|
||||
(
|
||||
{}:
|
||||
makeSetupHook {
|
||||
name = "remove-path-dependencies.sh";
|
||||
deps = [];
|
||||
deps = [ ];
|
||||
substitutions = {
|
||||
inherit pythonInterpreter;
|
||||
yj = "${yj}/bin/yj";
|
||||
pyprojectPatchScript = "${./pyproject-without-path.py}";
|
||||
};
|
||||
} ./remove-path-dependencies.sh
|
||||
) {};
|
||||
) { };
|
||||
|
||||
poetry2nixFixupHook = callPackage (
|
||||
{}:
|
||||
pipBuildHook = callPackage
|
||||
(
|
||||
{ pip, wheel }:
|
||||
makeSetupHook {
|
||||
name = "pip-build-hook.sh";
|
||||
deps = [ pip wheel ];
|
||||
substitutions = {
|
||||
inherit pythonInterpreter pythonSitePackages;
|
||||
};
|
||||
} ./pip-build-hook.sh
|
||||
) { };
|
||||
|
||||
poetry2nixFixupHook = callPackage
|
||||
(
|
||||
{}:
|
||||
makeSetupHook {
|
||||
name = "fixup-hook.sh";
|
||||
deps = [];
|
||||
deps = [ ];
|
||||
} ./fixup-hook.sh
|
||||
) {};
|
||||
) { };
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,50 @@
|
||||
# Setup hook to use for pip projects
|
||||
echo "Sourcing pip-build-hook"
|
||||
|
||||
pipBuildPhase() {
|
||||
echo "Executing pipBuildPhase"
|
||||
runHook preBuild
|
||||
|
||||
# Prefer using setup.py to avoid build-system dependencies if we have a setup.py
|
||||
if [ -z "${dontPreferSetupPy-}" ]; then
|
||||
if test -e setup.py && test -e pyproject.toml; then
|
||||
echo "Removing pyproject.toml..."
|
||||
rm -f pyproject.toml
|
||||
fi
|
||||
fi
|
||||
|
||||
mkdir -p dist
|
||||
echo "Creating a wheel..."
|
||||
@pythonInterpreter@ -m pip wheel --no-index --no-deps --no-clean --no-build-isolation --wheel-dir dist .
|
||||
echo "Finished creating a wheel..."
|
||||
|
||||
runHook postBuild
|
||||
echo "Finished executing pipBuildPhase"
|
||||
}
|
||||
|
||||
pipShellHook() {
|
||||
echo "Executing pipShellHook"
|
||||
runHook preShellHook
|
||||
|
||||
# Long-term setup.py should be dropped.
|
||||
if [ -e pyproject.toml ]; then
|
||||
tmp_path=$(mktemp -d)
|
||||
export PATH="$tmp_path/bin:$PATH"
|
||||
export PYTHONPATH="$tmp_path/@pythonSitePackages@:$PYTHONPATH"
|
||||
mkdir -p "$tmp_path/@pythonSitePackages@"
|
||||
@pythonInterpreter@ -m pip install -e . --prefix "$tmp_path" >&2
|
||||
fi
|
||||
|
||||
runHook postShellHook
|
||||
echo "Finished executing pipShellHook"
|
||||
}
|
||||
|
||||
if [ -z "${dontUsePipBuild-}" ] && [ -z "${buildPhase-}" ]; then
|
||||
echo "Using pipBuildPhase"
|
||||
buildPhase=pipBuildPhase
|
||||
fi
|
||||
|
||||
if [ -z "${shellHook-}" ]; then
|
||||
echo "Using pipShellHook"
|
||||
shellHook=pipShellHook
|
||||
fi
|
@ -6,7 +6,14 @@ import sys
|
||||
|
||||
data = json.load(sys.stdin)
|
||||
|
||||
for dep in data['tool']['poetry']['dependencies'].values():
|
||||
|
||||
def get_deep(o, path):
|
||||
for p in path.split('.'):
|
||||
o = o.get(p, {})
|
||||
return o
|
||||
|
||||
|
||||
for dep in get_deep(data, 'tool.poetry.dependencies').values():
|
||||
if isinstance(dep, dict):
|
||||
try:
|
||||
del dep['path'];
|
||||
|
@ -8,6 +8,20 @@ let
|
||||
genList (i: if i == idx then value else (builtins.elemAt list i)) (length list)
|
||||
);
|
||||
|
||||
# Do some canonicalisation of module names
|
||||
moduleName = name: lib.toLower (lib.replaceStrings [ "_" "." ] [ "-" "-" ] name);
|
||||
|
||||
# Get a full semver pythonVersion from a python derivation
|
||||
getPythonVersion = python:
|
||||
let
|
||||
pyVer = lib.splitVersion python.pythonVersion ++ [ "0" ];
|
||||
ver = lib.splitVersion python.version;
|
||||
major = l: lib.elemAt l 0;
|
||||
minor = l: lib.elemAt l 1;
|
||||
joinVersion = v: lib.concatStringsSep "." v;
|
||||
in
|
||||
joinVersion ( if major pyVer == major ver && minor pyVer == minor ver then ver else pyVer);
|
||||
|
||||
# Compare a semver expression with a version
|
||||
isCompatible = version:
|
||||
let
|
||||
@ -18,41 +32,41 @@ let
|
||||
};
|
||||
splitRe = "(" + (builtins.concatStringsSep "|" (builtins.map (x: lib.replaceStrings [ "|" ] [ "\\|" ] x) (lib.attrNames operators))) + ")";
|
||||
in
|
||||
expr:
|
||||
expr:
|
||||
let
|
||||
tokens = builtins.filter (x: x != "") (builtins.split splitRe expr);
|
||||
combine = acc: v:
|
||||
let
|
||||
tokens = builtins.filter (x: x != "") (builtins.split splitRe expr);
|
||||
combine = acc: v:
|
||||
let
|
||||
isOperator = builtins.typeOf v == "list";
|
||||
operator = if isOperator then (builtins.elemAt v 0) else acc.operator;
|
||||
in
|
||||
if isOperator then (acc // { inherit operator; }) else {
|
||||
inherit operator;
|
||||
state = operators."${operator}" acc.state (satisfiesSemver version v);
|
||||
};
|
||||
initial = { operator = "&&"; state = true; };
|
||||
isOperator = builtins.typeOf v == "list";
|
||||
operator = if isOperator then (builtins.elemAt v 0) else acc.operator;
|
||||
in
|
||||
if expr == "" then true else (builtins.foldl' combine initial tokens).state;
|
||||
|
||||
if isOperator then (acc // { inherit operator; }) else {
|
||||
inherit operator;
|
||||
state = operators."${operator}" acc.state (satisfiesSemver version v);
|
||||
};
|
||||
initial = { operator = "&&"; state = true; };
|
||||
in if expr == "" then true else (builtins.foldl' combine initial tokens).state;
|
||||
fromTOML = builtins.fromTOML or
|
||||
(
|
||||
toml: builtins.fromJSON (
|
||||
builtins.readFile (
|
||||
pkgs.runCommand "from-toml"
|
||||
{
|
||||
inherit toml;
|
||||
allowSubstitutes = false;
|
||||
preferLocalBuild = true;
|
||||
}
|
||||
''
|
||||
${pkgs.remarshal}/bin/remarshal \
|
||||
-if toml \
|
||||
-i <(echo "$toml") \
|
||||
-of json \
|
||||
-o $out
|
||||
''
|
||||
toml: builtins.fromJSON
|
||||
(
|
||||
builtins.readFile
|
||||
(
|
||||
pkgs.runCommand "from-toml"
|
||||
{
|
||||
inherit toml;
|
||||
allowSubstitutes = false;
|
||||
preferLocalBuild = true;
|
||||
}
|
||||
''
|
||||
${pkgs.remarshal}/bin/remarshal \
|
||||
-if toml \
|
||||
-i <(echo "$toml") \
|
||||
-of json \
|
||||
-o $out
|
||||
''
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
readTOML = path: fromTOML (builtins.readFile path);
|
||||
|
||||
@ -63,10 +77,61 @@ let
|
||||
let
|
||||
ml = pkgs.pythonManylinuxPackages;
|
||||
in
|
||||
if lib.strings.hasInfix "manylinux1" f then { pkg = [ ml.manylinux1 ]; str = "1"; }
|
||||
else if lib.strings.hasInfix "manylinux2010" f then { pkg = [ ml.manylinux2010 ]; str = "2010"; }
|
||||
else if lib.strings.hasInfix "manylinux2014" f then { pkg = [ ml.manylinux2014 ]; str = "2014"; }
|
||||
else { pkg = []; str = null; };
|
||||
if lib.strings.hasInfix "manylinux1" f then { pkg = [ ml.manylinux1 ]; str = "1"; }
|
||||
else if lib.strings.hasInfix "manylinux2010" f then { pkg = [ ml.manylinux2010 ]; str = "2010"; }
|
||||
else if lib.strings.hasInfix "manylinux2014" f then { pkg = [ ml.manylinux2014 ]; str = "2014"; }
|
||||
else { pkg = [ ]; str = null; };
|
||||
|
||||
# Predict URL from the PyPI index.
|
||||
# Args:
|
||||
# pname: package name
|
||||
# file: filename including extension
|
||||
# hash: SRI hash
|
||||
# kind: Language implementation and version tag
|
||||
predictURLFromPypi = lib.makeOverridable
|
||||
(
|
||||
{ pname, file, hash, kind }:
|
||||
"https://files.pythonhosted.org/packages/${kind}/${lib.toLower (builtins.substring 0 1 file)}/${pname}/${file}"
|
||||
);
|
||||
|
||||
|
||||
# Fetch the wheels from the PyPI index.
|
||||
# We need to first get the proper URL to the wheel.
|
||||
# Args:
|
||||
# pname: package name
|
||||
# file: filename including extension
|
||||
# hash: SRI hash
|
||||
# kind: Language implementation and version tag
|
||||
fetchWheelFromPypi = lib.makeOverridable
|
||||
(
|
||||
{ pname, file, hash, kind, curlOpts ? "" }:
|
||||
let
|
||||
version = builtins.elemAt (builtins.split "-" file) 2;
|
||||
in
|
||||
(pkgs.stdenvNoCC.mkDerivation {
|
||||
name = file;
|
||||
nativeBuildInputs = [
|
||||
pkgs.curl
|
||||
pkgs.jq
|
||||
];
|
||||
isWheel = true;
|
||||
system = "builtin";
|
||||
|
||||
preferLocalBuild = true;
|
||||
impureEnvVars = lib.fetchers.proxyImpureEnvVars ++ [
|
||||
"NIX_CURL_FLAGS"
|
||||
];
|
||||
|
||||
predictedURL = predictURLFromPypi { inherit pname file hash kind; };
|
||||
inherit pname file version curlOpts;
|
||||
|
||||
builder = ./fetch-wheel.sh;
|
||||
|
||||
outputHashMode = "flat";
|
||||
outputHashAlgo = "sha256";
|
||||
outputHash = hash;
|
||||
})
|
||||
);
|
||||
|
||||
# Fetch the artifacts from the PyPI index. Since we get all
|
||||
# info we need from the lock file we don't use nixpkgs' fetchPyPi
|
||||
@ -78,25 +143,27 @@ let
|
||||
# file: filename including extension
|
||||
# hash: SRI hash
|
||||
# kind: Language implementation and version tag https://www.python.org/dev/peps/pep-0427/#file-name-convention
|
||||
fetchFromPypi = lib.makeOverridable (
|
||||
{ pname, file, hash, kind }:
|
||||
pkgs.fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/${kind}/${lib.toLower (builtins.substring 0 1 file)}/${pname}/${file}";
|
||||
inherit hash;
|
||||
}
|
||||
);
|
||||
|
||||
fetchFromPypi = lib.makeOverridable
|
||||
(
|
||||
{ pname, file, hash, kind }:
|
||||
if lib.strings.hasSuffix "whl" file then fetchWheelFromPypi { inherit pname file hash kind; }
|
||||
else
|
||||
pkgs.fetchurl {
|
||||
url = predictURLFromPypi { inherit pname file hash kind; };
|
||||
inherit hash;
|
||||
}
|
||||
);
|
||||
getBuildSystemPkgs =
|
||||
{ pythonPackages
|
||||
, pyProject
|
||||
}:
|
||||
let
|
||||
buildSystem = lib.getAttrFromPath [ "build-system" "build-backend" ] pyProject;
|
||||
drvAttr = builtins.elemAt (builtins.split "\\.|:" buildSystem) 0;
|
||||
in
|
||||
if buildSystem == "" then [] else (
|
||||
[ pythonPackages.${drvAttr} or (throw "unsupported build system ${buildSystem}") ]
|
||||
);
|
||||
let
|
||||
buildSystem = lib.attrByPath [ "build-system" "build-backend" ] "" pyProject;
|
||||
drvAttr = moduleName (builtins.elemAt (builtins.split "\\.|:" buildSystem) 0);
|
||||
in
|
||||
if buildSystem == "" then [ ] else (
|
||||
[ pythonPackages.${drvAttr} or (throw "unsupported build system ${buildSystem}") ]
|
||||
);
|
||||
|
||||
# Find gitignore files recursively in parent directory stopping with .git
|
||||
findGitIgnores = path:
|
||||
@ -105,9 +172,9 @@ let
|
||||
gitIgnore = path + "/.gitignore";
|
||||
isGitRoot = builtins.pathExists (path + "/.git");
|
||||
hasGitIgnore = builtins.pathExists gitIgnore;
|
||||
gitIgnores = if hasGitIgnore then [ gitIgnore ] else [];
|
||||
gitIgnores = if hasGitIgnore then [ gitIgnore ] else [ ];
|
||||
in
|
||||
lib.optionals (builtins.toString path != "/" && ! isGitRoot) (findGitIgnores parent) ++ gitIgnores;
|
||||
lib.optionals (builtins.toString path != "/" && ! isGitRoot) (findGitIgnores parent) ++ gitIgnores;
|
||||
|
||||
/*
|
||||
Provides a source filtering mechanism that:
|
||||
@ -124,22 +191,25 @@ let
|
||||
|| (type == "regular" && ! lib.strings.hasSuffix ".pyc" name)
|
||||
;
|
||||
in
|
||||
lib.cleanSourceWith {
|
||||
filter = lib.cleanSourceFilter;
|
||||
src = lib.cleanSourceWith {
|
||||
filter = pkgs.nix-gitignore.gitignoreFilterPure pycacheFilter gitIgnores src;
|
||||
inherit src;
|
||||
};
|
||||
lib.cleanSourceWith {
|
||||
filter = lib.cleanSourceFilter;
|
||||
src = lib.cleanSourceWith {
|
||||
filter = pkgs.nix-gitignore.gitignoreFilterPure pycacheFilter gitIgnores src;
|
||||
inherit src;
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
inherit
|
||||
fetchFromPypi
|
||||
fetchWheelFromPypi
|
||||
getManyLinuxDeps
|
||||
isCompatible
|
||||
readTOML
|
||||
getBuildSystemPkgs
|
||||
satisfiesSemver
|
||||
cleanPythonSources
|
||||
moduleName
|
||||
getPythonVersion
|
||||
;
|
||||
}
|
||||
|
@ -10,74 +10,68 @@
|
||||
, version
|
||||
, files
|
||||
, source
|
||||
, dependencies ? {}
|
||||
, dependencies ? { }
|
||||
, pythonPackages
|
||||
, python-versions
|
||||
, pwd
|
||||
, sourceSpec
|
||||
, supportedExtensions ? lib.importJSON ./extensions.json
|
||||
, preferWheels ? false
|
||||
, ...
|
||||
}:
|
||||
|
||||
pythonPackages.callPackage (
|
||||
{ preferWheel ? false
|
||||
, ...
|
||||
}@args:
|
||||
pythonPackages.callPackage
|
||||
(
|
||||
{ preferWheel ? preferWheels
|
||||
, ...
|
||||
}@args:
|
||||
let
|
||||
inherit (poetryLib) isCompatible getManyLinuxDeps fetchFromPypi;
|
||||
inherit (poetryLib) isCompatible getManyLinuxDeps fetchFromPypi moduleName;
|
||||
|
||||
inherit (import ./pep425.nix {
|
||||
inherit lib python;
|
||||
inherit (pkgs) stdenv;
|
||||
}) selectWheel
|
||||
;
|
||||
|
||||
fileCandidates = let
|
||||
supportedRegex = ("^.*?(" + builtins.concatStringsSep "|" supportedExtensions + ")");
|
||||
matchesVersion = fname: builtins.match ("^.*" + builtins.replaceStrings [ "." ] [ "\\." ] version + ".*$") fname != null;
|
||||
hasSupportedExtension = fname: builtins.match supportedRegex fname != null;
|
||||
isCompatibleEgg = fname: ! lib.strings.hasSuffix ".egg" fname || lib.strings.hasSuffix "py${python.pythonVersion}.egg" fname;
|
||||
in
|
||||
fileCandidates =
|
||||
let
|
||||
supportedRegex = ("^.*?(" + builtins.concatStringsSep "|" supportedExtensions + ")");
|
||||
matchesVersion = fname: builtins.match ("^.*" + builtins.replaceStrings [ "." ] [ "\\." ] version + ".*$") fname != null;
|
||||
hasSupportedExtension = fname: builtins.match supportedRegex fname != null;
|
||||
isCompatibleEgg = fname: ! lib.strings.hasSuffix ".egg" fname || lib.strings.hasSuffix "py${python.pythonVersion}.egg" fname;
|
||||
in
|
||||
builtins.filter (f: matchesVersion f.file && hasSupportedExtension f.file && isCompatibleEgg f.file) files;
|
||||
|
||||
toPath = s: pwd + "/${s}";
|
||||
|
||||
isSource = source != null;
|
||||
isGit = isSource && source.type == "git";
|
||||
isLocal = isSource && source.type == "directory";
|
||||
|
||||
localDepPath = toPath source.url;
|
||||
pyProject = poetryLib.readTOML (localDepPath + "/pyproject.toml");
|
||||
|
||||
buildSystemPkgs = poetryLib.getBuildSystemPkgs {
|
||||
inherit pythonPackages pyProject;
|
||||
};
|
||||
|
||||
fileInfo = let
|
||||
isBdist = f: lib.strings.hasSuffix "whl" f.file;
|
||||
isSdist = f: ! isBdist f && ! isEgg f;
|
||||
isEgg = f: lib.strings.hasSuffix ".egg" f.file;
|
||||
|
||||
binaryDist = selectWheel fileCandidates;
|
||||
sourceDist = builtins.filter isSdist fileCandidates;
|
||||
eggs = builtins.filter isEgg fileCandidates;
|
||||
|
||||
entries = (if preferWheel then binaryDist ++ sourceDist else sourceDist ++ binaryDist) ++ eggs;
|
||||
|
||||
lockFileEntry = builtins.head entries;
|
||||
|
||||
_isEgg = isEgg lockFileEntry;
|
||||
in
|
||||
fileInfo =
|
||||
let
|
||||
isBdist = f: lib.strings.hasSuffix "whl" f.file;
|
||||
isSdist = f: ! isBdist f && ! isEgg f;
|
||||
isEgg = f: lib.strings.hasSuffix ".egg" f.file;
|
||||
binaryDist = selectWheel fileCandidates;
|
||||
sourceDist = builtins.filter isSdist fileCandidates;
|
||||
eggs = builtins.filter isEgg fileCandidates;
|
||||
entries = ( if preferWheel then binaryDist ++ sourceDist else sourceDist ++ binaryDist) ++ eggs;
|
||||
lockFileEntry = builtins.head entries;
|
||||
_isEgg = isEgg lockFileEntry;
|
||||
in
|
||||
rec {
|
||||
inherit (lockFileEntry) file hash;
|
||||
name = file;
|
||||
format =
|
||||
if _isEgg then "egg"
|
||||
else if lib.strings.hasSuffix ".whl" name then "wheel"
|
||||
else "setuptools";
|
||||
else "pyproject";
|
||||
kind =
|
||||
if _isEgg then python.pythonVersion
|
||||
else if format == "setuptools" then "source"
|
||||
else if format == "pyproject" then "source"
|
||||
else (builtins.elemAt (lib.strings.splitString "-" name) 2);
|
||||
};
|
||||
|
||||
@ -88,63 +82,65 @@ pythonPackages.callPackage (
|
||||
"toml" # Toml is an extra for setuptools-scm
|
||||
];
|
||||
baseBuildInputs = lib.optional (! lib.elem name skipSetupToolsSCM) pythonPackages.setuptools-scm;
|
||||
|
||||
format = if isLocal then "pyproject" else if isGit then "setuptools" else fileInfo.format;
|
||||
format = if isLocal then "pyproject" else if isGit then "pyproject" else fileInfo.format;
|
||||
in
|
||||
buildPythonPackage {
|
||||
pname = moduleName name;
|
||||
version = version;
|
||||
|
||||
buildPythonPackage {
|
||||
pname = name;
|
||||
version = version;
|
||||
inherit format;
|
||||
|
||||
inherit format;
|
||||
doCheck = false; # We never get development deps
|
||||
|
||||
doCheck = false; # We never get development deps
|
||||
# Stripping pre-built wheels lead to `ELF load command address/offset not properly aligned`
|
||||
dontStrip = format == "wheel";
|
||||
|
||||
# Stripping pre-built wheels lead to `ELF load command address/offset not properly aligned`
|
||||
dontStrip = format == "wheel";
|
||||
nativeBuildInputs = [
|
||||
pythonPackages.poetry2nixFixupHook
|
||||
]
|
||||
++ lib.optional (!isSource && (getManyLinuxDeps fileInfo.name).str != null) autoPatchelfHook
|
||||
++ lib.optional (format == "pyproject") pythonPackages.removePathDependenciesHook
|
||||
;
|
||||
|
||||
nativeBuildInputs = [
|
||||
pythonPackages.poetry2nixFixupHook
|
||||
]
|
||||
++ lib.optional (!isSource && (getManyLinuxDeps fileInfo.name).str != null) autoPatchelfHook
|
||||
++ lib.optional (format == "pyproject") pythonPackages.removePathDependenciesHook
|
||||
;
|
||||
buildInputs = (
|
||||
baseBuildInputs
|
||||
++ lib.optional (!isSource) (getManyLinuxDeps fileInfo.name).pkg
|
||||
++ lib.optional isLocal buildSystemPkgs
|
||||
);
|
||||
|
||||
buildInputs = (
|
||||
baseBuildInputs
|
||||
++ lib.optional (!isSource) (getManyLinuxDeps fileInfo.name).pkg
|
||||
++ lib.optional isLocal buildSystemPkgs
|
||||
);
|
||||
|
||||
propagatedBuildInputs = let
|
||||
compat = isCompatible python.pythonVersion;
|
||||
deps = lib.filterAttrs (n: v: v) (
|
||||
lib.mapAttrs (
|
||||
n: v:
|
||||
let
|
||||
constraints = v.python or "";
|
||||
in
|
||||
compat constraints
|
||||
) dependencies
|
||||
);
|
||||
propagatedBuildInputs =
|
||||
let
|
||||
compat = isCompatible (poetryLib.getPythonVersion python);
|
||||
deps = lib.filterAttrs (n: v: v)
|
||||
(
|
||||
lib.mapAttrs
|
||||
(
|
||||
n: v:
|
||||
let
|
||||
constraints = v.python or "";
|
||||
in
|
||||
compat constraints
|
||||
) dependencies
|
||||
);
|
||||
depAttrs = lib.attrNames deps;
|
||||
in
|
||||
builtins.map (n: pythonPackages.${lib.toLower n}) depAttrs;
|
||||
builtins.map (n: pythonPackages.${moduleName n}) depAttrs;
|
||||
|
||||
meta = {
|
||||
broken = ! isCompatible python.pythonVersion python-versions;
|
||||
license = [];
|
||||
inherit (python.meta) platforms;
|
||||
};
|
||||
meta = {
|
||||
broken = ! isCompatible (poetryLib.getPythonVersion python) python-versions;
|
||||
license = [ ];
|
||||
inherit (python.meta) platforms;
|
||||
};
|
||||
|
||||
passthru = {
|
||||
inherit args;
|
||||
};
|
||||
passthru = {
|
||||
inherit args;
|
||||
};
|
||||
|
||||
# We need to retrieve kind from the interpreter and the filename of the package
|
||||
# Interpreters should declare what wheel types they're compatible with (python type + ABI)
|
||||
# Here we can then choose a file based on that info.
|
||||
src = if isGit then (
|
||||
# We need to retrieve kind from the interpreter and the filename of the package
|
||||
# Interpreters should declare what wheel types they're compatible with (python type + ABI)
|
||||
# Here we can then choose a file based on that info.
|
||||
src =
|
||||
if isGit then (
|
||||
builtins.fetchGit {
|
||||
inherit (source) url;
|
||||
rev = source.reference;
|
||||
@ -154,6 +150,5 @@ pythonPackages.callPackage (
|
||||
pname = name;
|
||||
inherit (fileInfo) file hash kind;
|
||||
};
|
||||
}
|
||||
|
||||
) {}
|
||||
}
|
||||
) { }
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,8 +12,7 @@ let
|
||||
major = builtins.elemAt ver 0;
|
||||
minor = builtins.elemAt ver 1;
|
||||
in
|
||||
"cp${major}${minor}";
|
||||
|
||||
"cp${major}${minor}";
|
||||
abiTag = "${pythonTag}m";
|
||||
|
||||
#
|
||||
@ -24,13 +23,13 @@ let
|
||||
entries = splitString "-" str;
|
||||
p = removeSuffix ".whl" (builtins.elemAt entries 4);
|
||||
in
|
||||
{
|
||||
pkgName = builtins.elemAt entries 0;
|
||||
pkgVer = builtins.elemAt entries 1;
|
||||
pyVer = builtins.elemAt entries 2;
|
||||
abi = builtins.elemAt entries 3;
|
||||
platform = p;
|
||||
};
|
||||
{
|
||||
pkgName = builtins.elemAt entries 0;
|
||||
pkgVer = builtins.elemAt entries 1;
|
||||
pyVer = builtins.elemAt entries 2;
|
||||
abi = builtins.elemAt entries 3;
|
||||
platform = p;
|
||||
};
|
||||
|
||||
#
|
||||
# Builds list of acceptable osx wheel files
|
||||
@ -42,9 +41,9 @@ let
|
||||
v = lib.lists.head versions;
|
||||
vs = lib.lists.tail versions;
|
||||
in
|
||||
if (builtins.length versions == 0)
|
||||
then []
|
||||
else (builtins.filter (x: hasInfix v x.file) candidates) ++ (findBestMatches vs candidates);
|
||||
if (builtins.length versions == 0)
|
||||
then [ ]
|
||||
else (builtins.filter (x: hasInfix v x.file) candidates) ++ (findBestMatches vs candidates);
|
||||
|
||||
# pyver = "cpXX"
|
||||
# x = "cpXX" | "py2" | "py3" | "py2.py3"
|
||||
@ -53,7 +52,7 @@ let
|
||||
normalize = y: ''cp${lib.strings.removePrefix "cp" (lib.strings.removePrefix "py" y)}'';
|
||||
isCompat = p: x: lib.strings.hasPrefix (normalize x) p;
|
||||
in
|
||||
lib.lists.any (isCompat pyver) (lib.strings.splitString "." x);
|
||||
lib.lists.any (isCompat pyver) (lib.strings.splitString "." x);
|
||||
|
||||
#
|
||||
# Selects the best matching wheel file from a list of files
|
||||
@ -61,42 +60,37 @@ let
|
||||
selectWheel = files:
|
||||
let
|
||||
filesWithoutSources = (builtins.filter (x: hasSuffix ".whl" x.file) files);
|
||||
|
||||
isPyAbiCompatible = pyabi: x: x == "none" || pyabi == x;
|
||||
|
||||
withPython = ver: abi: x: (isPyVersionCompatible ver x.pyVer) && (isPyAbiCompatible abi x.abi);
|
||||
|
||||
withPlatform = if isLinux
|
||||
then (
|
||||
x: x.platform == "manylinux1_${stdenv.platform.kernelArch}"
|
||||
|| x.platform == "manylinux2010_${stdenv.platform.kernelArch}"
|
||||
|| x.platform == "manylinux2014_${stdenv.platform.kernelArch}"
|
||||
|| x.platform == "any"
|
||||
)
|
||||
else (x: hasInfix "macosx" x.platform || x.platform == "any");
|
||||
|
||||
withPlatform =
|
||||
if isLinux
|
||||
then (
|
||||
x: x.platform == "manylinux1_${stdenv.platform.kernelArch}"
|
||||
|| x.platform == "manylinux2010_${stdenv.platform.kernelArch}"
|
||||
|| x.platform == "manylinux2014_${stdenv.platform.kernelArch}"
|
||||
|| x.platform == "any"
|
||||
)
|
||||
else (x: hasInfix "macosx" x.platform || x.platform == "any");
|
||||
filterWheel = x:
|
||||
let
|
||||
f = toWheelAttrs x.file;
|
||||
in
|
||||
(withPython pythonTag abiTag f) && (withPlatform f);
|
||||
|
||||
(withPython pythonTag abiTag f) && (withPlatform f);
|
||||
filtered = builtins.filter filterWheel filesWithoutSources;
|
||||
|
||||
choose = files:
|
||||
let
|
||||
osxMatches = [ "10_12" "10_11" "10_10" "10_9" "any" ];
|
||||
linuxMatches = [ "manylinux1_" "manylinux2010_" "manylinux2014_" "any" ];
|
||||
chooseLinux = x: lib.singleton (builtins.head (findBestMatches linuxMatches x));
|
||||
chooseOSX = x: lib.singleton (builtins.head (findBestMatches osxMatches x));
|
||||
chooseLinux = x: lib.take 1 (findBestMatches linuxMatches x);
|
||||
chooseOSX = x: lib.take 1 (findBestMatches osxMatches x);
|
||||
in
|
||||
if isLinux
|
||||
then chooseLinux files
|
||||
else chooseOSX files;
|
||||
if isLinux
|
||||
then chooseLinux files
|
||||
else chooseOSX files;
|
||||
in
|
||||
if (builtins.length filtered == 0)
|
||||
then []
|
||||
else choose (filtered);
|
||||
if (builtins.length filtered == 0)
|
||||
then [ ]
|
||||
else choose (filtered);
|
||||
in
|
||||
{
|
||||
inherit selectWheel toWheelAttrs isPyVersionCompatible;
|
||||
|
@ -7,7 +7,6 @@ let
|
||||
|
||||
# Strip leading/trailing whitespace from string
|
||||
stripStr = s: lib.elemAt (builtins.split "^ *" (lib.elemAt (builtins.split " *$" s) 0)) 2;
|
||||
|
||||
findSubExpressionsFun = acc: c: (
|
||||
if c == "(" then (
|
||||
let
|
||||
@ -15,23 +14,23 @@ let
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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; }
|
||||
);
|
||||
|
||||
@ -39,7 +38,7 @@ let
|
||||
findSubExpressions = expr:
|
||||
let
|
||||
acc = builtins.foldl' findSubExpressionsFun {
|
||||
exprs = [];
|
||||
exprs = [ ];
|
||||
expr = expr;
|
||||
pos = 0;
|
||||
openP = 0;
|
||||
@ -47,18 +46,16 @@ let
|
||||
startPos = 0;
|
||||
} (lib.stringToCharacters expr);
|
||||
tailExpr = (substr acc.exprPos acc.pos expr);
|
||||
tailExprs = if tailExpr != "" then [ tailExpr ] else [];
|
||||
tailExprs = if tailExpr != "" then [ tailExpr ] else [ ];
|
||||
in
|
||||
acc.exprs ++ tailExprs;
|
||||
|
||||
acc.exprs ++ tailExprs;
|
||||
parseExpressions = exprs:
|
||||
let
|
||||
splitCond = (
|
||||
s: builtins.map
|
||||
(x: stripStr (if builtins.typeOf x == "list" then (builtins.elemAt x 0) else x))
|
||||
(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 {
|
||||
@ -70,14 +67,12 @@ let
|
||||
value = expr;
|
||||
}
|
||||
);
|
||||
|
||||
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;
|
||||
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
|
||||
@ -94,9 +89,10 @@ let
|
||||
else throw "Unsupported platform"
|
||||
);
|
||||
platform_machine = stdenv.platform.kernelArch;
|
||||
platform_python_implementation = let
|
||||
impl = python.passthru.implementation;
|
||||
in
|
||||
platform_python_implementation =
|
||||
let
|
||||
impl = python.passthru.implementation;
|
||||
in
|
||||
(
|
||||
if impl == "cpython" then "CPython"
|
||||
else if impl == "pypy" then "PyPy"
|
||||
@ -115,34 +111,32 @@ let
|
||||
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;
|
||||
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:
|
||||
@ -165,32 +159,33 @@ let
|
||||
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
|
||||
);
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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:
|
||||
@ -217,18 +212,18 @@ let
|
||||
cond = "and";
|
||||
} v;
|
||||
in
|
||||
acc // {
|
||||
value = cond."${acc.cond}" acc.value ret.value;
|
||||
}
|
||||
acc // {
|
||||
value = cond."${acc.cond}" acc.value ret.value;
|
||||
}
|
||||
) else throw "Unsupported type"
|
||||
);
|
||||
in
|
||||
(
|
||||
builtins.foldl' reduceExpressionsFun {
|
||||
value = true;
|
||||
cond = "and";
|
||||
} exprs
|
||||
).value;
|
||||
(
|
||||
builtins.foldl' reduceExpressionsFun {
|
||||
value = true;
|
||||
cond = "and";
|
||||
} exprs
|
||||
).value;
|
||||
in
|
||||
e: builtins.foldl' (acc: v: v acc) e [
|
||||
findSubExpressions
|
||||
|
@ -1,28 +1,28 @@
|
||||
{ lib, ireplace }:
|
||||
let
|
||||
inherit (builtins) elemAt match;
|
||||
|
||||
operators = let
|
||||
matchWildCard = s: match "([^\*])(\.[\*])" s;
|
||||
mkComparison = ret: version: v: builtins.compareVersions version v == ret;
|
||||
mkIdxComparison = idx: version: v:
|
||||
let
|
||||
ver = builtins.splitVersion v;
|
||||
minor = builtins.toString (lib.toInt (elemAt ver idx) + 1);
|
||||
upper = builtins.concatStringsSep "." (ireplace idx minor ver);
|
||||
in
|
||||
operators =
|
||||
let
|
||||
matchWildCard = s: match "([^\*])(\.[\*])" s;
|
||||
mkComparison = ret: version: v: builtins.compareVersions version v == ret;
|
||||
mkIdxComparison = idx: version: v:
|
||||
let
|
||||
ver = builtins.splitVersion v;
|
||||
minor = builtins.toString (lib.toInt (elemAt ver idx) + 1);
|
||||
upper = builtins.concatStringsSep "." (ireplace idx minor ver);
|
||||
in
|
||||
operators.">=" version v && operators."<" version upper;
|
||||
dropWildcardPrecision = f: version: constraint:
|
||||
let
|
||||
m = matchWildCard constraint;
|
||||
hasWildcard = m != null;
|
||||
c = if hasWildcard then (elemAt m 0) else constraint;
|
||||
v =
|
||||
if hasWildcard then (builtins.substring 0 (builtins.stringLength c) version)
|
||||
else version;
|
||||
in
|
||||
dropWildcardPrecision = f: version: constraint:
|
||||
let
|
||||
m = matchWildCard constraint;
|
||||
hasWildcard = m != null;
|
||||
c = if hasWildcard then (elemAt m 0) else constraint;
|
||||
v =
|
||||
if hasWildcard then (builtins.substring 0 (builtins.stringLength c) version)
|
||||
else version;
|
||||
in
|
||||
f v c;
|
||||
in
|
||||
in
|
||||
{
|
||||
# Prefix operators
|
||||
"==" = dropWildcardPrecision (mkComparison 0);
|
||||
@ -39,24 +39,23 @@ let
|
||||
# Prune constraint
|
||||
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
|
||||
);
|
||||
upper = builtins.toString
|
||||
(
|
||||
(lib.toInt (builtins.elemAt pruned (builtins.length pruned - 1))) + 1
|
||||
);
|
||||
upperConstraint = builtins.concatStringsSep "." (ireplace (builtins.length pruned - 1) upper pruned);
|
||||
in
|
||||
operators.">=" v c && operators."<" v upperConstraint;
|
||||
operators.">=" v c && operators."<" v upperConstraint;
|
||||
# Infix operators
|
||||
"-" = version: v: operators.">=" version v.vl && operators."<=" version v.vu;
|
||||
# Arbitrary equality clause, just run simple comparison
|
||||
"===" = v: c: v == c;
|
||||
#
|
||||
};
|
||||
|
||||
re = {
|
||||
operators = "([=><!~\^]+)";
|
||||
version = "([0-9\.\*x]+)";
|
||||
};
|
||||
|
||||
parseConstraint = constraint:
|
||||
let
|
||||
constraintStr = builtins.replaceStrings [ " " ] [ "" ] constraint;
|
||||
@ -65,26 +64,24 @@ let
|
||||
# There is also an infix operator to match ranges
|
||||
mIn = match "${re.version} *(-) *${re.version}" constraintStr;
|
||||
in
|
||||
(
|
||||
if mPre != null then {
|
||||
op = elemAt mPre 0;
|
||||
v = elemAt mPre 1;
|
||||
}
|
||||
# Infix operators are range matches
|
||||
else if mIn != null then {
|
||||
op = elemAt mIn 1;
|
||||
v = {
|
||||
vl = (elemAt mIn 0);
|
||||
vu = (elemAt mIn 2);
|
||||
};
|
||||
}
|
||||
else throw "Constraint \"${constraintStr}\" could not be parsed"
|
||||
);
|
||||
|
||||
(
|
||||
if mPre != null then {
|
||||
op = elemAt mPre 0;
|
||||
v = elemAt mPre 1;
|
||||
}
|
||||
# Infix operators are range matches
|
||||
else if mIn != null then {
|
||||
op = elemAt mIn 1;
|
||||
v = {
|
||||
vl = (elemAt mIn 0);
|
||||
vu = (elemAt mIn 2);
|
||||
};
|
||||
}
|
||||
else throw "Constraint \"${constraintStr}\" could not be parsed"
|
||||
);
|
||||
satisfiesSemver = version: constraint:
|
||||
let
|
||||
inherit (parseConstraint constraint) op v;
|
||||
in
|
||||
if constraint == "*" then true else operators."${op}" version v;
|
||||
in if constraint == "*" then true else operators."${op}" version v;
|
||||
in
|
||||
{ inherit satisfiesSemver; }
|
||||
|
@ -14,7 +14,7 @@ curl -L -s https://github.com/nix-community/poetry2nix/archive/master.tar.gz | t
|
||||
mv poetry2nix-master/* .
|
||||
|
||||
mkdir build
|
||||
cp *.nix *.json *.py build/
|
||||
cp *.* build/
|
||||
cp -r hooks bin build/
|
||||
rm build/shell.nix build/generate.py build/overlay.nix build/flake.nix
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user