mirror of
https://github.com/vale981/poetry2nix
synced 2025-03-05 09:11:39 -05:00
181 lines
5.7 KiB
Nix
181 lines
5.7 KiB
Nix
{
|
|
pkgs ? import <nixpkgs> { },
|
|
lib ? pkgs.lib,
|
|
python ? pkgs.python3,
|
|
}:
|
|
|
|
let
|
|
|
|
importTOML = path: builtins.fromTOML (builtins.readFile path);
|
|
|
|
getAttrDefault = attribute: set: default:
|
|
if builtins.hasAttr attribute set
|
|
then builtins.getAttr attribute set
|
|
else default;
|
|
|
|
satisfiesSemver = (import ./semver.nix {inherit lib;}).satisfies;
|
|
|
|
# Check Python version is compatible with package
|
|
isCompatible = pythonVersions: let
|
|
operators = {
|
|
"||" = cond1: cond2: cond1 || cond2;
|
|
"," = cond1: cond2: cond1 && cond2; # , means &&
|
|
};
|
|
tokens = builtins.split "(,|\\|\\|)" pythonVersions;
|
|
in (builtins.foldl' (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 python.version v);
|
|
})
|
|
{
|
|
operator = ",";
|
|
state = true;
|
|
}
|
|
tokens).state;
|
|
|
|
extensions = pkgs.lib.importJSON ./extensions.json;
|
|
getExtension = filename: builtins.elemAt
|
|
(builtins.filter (ext: builtins.match "^.*\.${ext}" filename != null) extensions)
|
|
0;
|
|
supportedRe = ("^.*?(" + builtins.concatStringsSep "|" extensions + ")");
|
|
fileSupported = fname: builtins.match supportedRe fname != null;
|
|
|
|
defaultPoetryOverrides = import ./overrides.nix { inherit pkgs; };
|
|
|
|
isBdist = f: builtins.match "^.*?whl$" f.file != null;
|
|
isSdist = f: ! isBdist f;
|
|
|
|
mkPoetryPackage = {
|
|
src,
|
|
pyproject ? src + "/pyproject.toml",
|
|
poetrylock ? src + "/poetry.lock",
|
|
overrides ? defaultPoetryOverrides,
|
|
meta ? {},
|
|
...
|
|
}@attrs: let
|
|
pyProject = importTOML pyproject;
|
|
poetryLock = importTOML poetrylock;
|
|
|
|
files = getAttrDefault "files" (getAttrDefault "metadata" poetryLock {}) {};
|
|
|
|
specialAttrs = [ "pyproject" "poetrylock" "overrides" ];
|
|
passedAttrs = builtins.removeAttrs attrs specialAttrs;
|
|
|
|
# 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
|
|
py = let
|
|
packageOverrides = self: super: let
|
|
mkPoetryDep = pkgMeta: let
|
|
pkgFiles = let
|
|
all = getAttrDefault pkgMeta.name files [];
|
|
in builtins.filter (f: fileSupported f.file) all;
|
|
|
|
files_sdist = builtins.filter isSdist pkgFiles;
|
|
files_bdist = builtins.filter isBdist pkgFiles;
|
|
files_supported = files_sdist ++ files_bdist;
|
|
# Grab the first dist, we dont care about which one
|
|
file = assert builtins.length files_supported >= 1; builtins.elemAt files_supported 0;
|
|
|
|
format =
|
|
if isBdist file
|
|
then "wheel"
|
|
else "setuptools";
|
|
|
|
in self.buildPythonPackage {
|
|
pname = pkgMeta.name;
|
|
version = pkgMeta.version;
|
|
|
|
doCheck = false; # We never get development deps
|
|
|
|
inherit format;
|
|
|
|
propagatedBuildInputs = let
|
|
depAttrs = getAttrDefault "dependencies" pkgMeta {};
|
|
# Some dependencies like django gets the attribute name django
|
|
# but dependencies try to access Django
|
|
dependencies = builtins.map (d: lib.toLower d) (builtins.attrNames depAttrs);
|
|
in builtins.map (dep: self."${dep}") dependencies;
|
|
|
|
meta = {
|
|
broken = ! isCompatible pkgMeta.python-versions;
|
|
};
|
|
|
|
src =
|
|
if format == "wheel"
|
|
then self.fetchPypi {
|
|
pname = pkgMeta.name;
|
|
version = pkgMeta.version;
|
|
sha256 = file.hash;
|
|
format = "wheel";
|
|
}
|
|
else self.fetchPypi {
|
|
pname = pkgMeta.name;
|
|
version = pkgMeta.version;
|
|
sha256 = file.hash;
|
|
extension = getExtension file.file;
|
|
};
|
|
|
|
};
|
|
|
|
lockPkgs = builtins.map (pkgMeta: {
|
|
name = pkgMeta.name;
|
|
value = let
|
|
drv = mkPoetryDep pkgMeta;
|
|
override = getAttrDefault pkgMeta.name overrides (_: _: drv: drv);
|
|
in override self super drv;
|
|
}) poetryLock.package;
|
|
|
|
in {
|
|
# TODO: Figure out why install check fails with overridden version
|
|
pytest_xdist = super.pytest_xdist.overrideAttrs(old: {
|
|
doInstallCheck = false;
|
|
});
|
|
} // builtins.listToAttrs lockPkgs // {
|
|
# Temporary hacks (Missing support for markers)
|
|
enum34 = null;
|
|
functools32 = null;
|
|
typing = null;
|
|
futures = null;
|
|
};
|
|
in python.override { inherit packageOverrides; self = py; };
|
|
pythonPackages = py.pkgs;
|
|
|
|
getDeps = depAttr: let
|
|
deps = builtins.getAttr depAttr pyProject.tool.poetry;
|
|
depAttrs = builtins.attrNames deps;
|
|
in builtins.map (dep: pythonPackages."${dep}") depAttrs;
|
|
|
|
getInputs = attr: getAttrDefault attr attrs [];
|
|
mkInput = attr: extraInputs: getInputs attr ++ extraInputs;
|
|
|
|
in pythonPackages.buildPythonApplication (passedAttrs // {
|
|
pname = pyProject.tool.poetry.name;
|
|
version = pyProject.tool.poetry.version;
|
|
|
|
format = "pyproject";
|
|
|
|
# TODO: Only conditionally include poetry based on build-system
|
|
# buildInputs = mkInput "buildInputs" ([ pythonPackages.poetry ]);
|
|
buildInputs = mkInput "buildInputs" ([ pythonPackages.setuptools ]);
|
|
|
|
propagatedBuildInputs = mkInput "propagatedBuildInputs" (getDeps "dependencies");
|
|
checkInputs = mkInput "checkInputs" (getDeps "dev-dependencies");
|
|
|
|
passthru = {
|
|
inherit pythonPackages;
|
|
};
|
|
|
|
meta = meta // {
|
|
inherit (pyProject.tool.poetry) description;
|
|
licenses = [ pyProject.tool.poetry.license ];
|
|
};
|
|
|
|
});
|
|
|
|
in {
|
|
inherit mkPoetryPackage defaultPoetryOverrides;
|
|
}
|