feat: big messy refactoring

- normalize package names to match PEP-503
- don't assume build dependencies on setuptools{,-scm}
- automatically generate overrides for setuptools{,-scm}
- pull known build systems directly from nixpkgs
- fix a bunch of mostly unrelated warnings

Co-authored-by: Phillip Cloud <417981+cpcloud@users.noreply.github.com>
This commit is contained in:
K900 2022-09-29 20:39:37 +03:00
parent 8be90b6f00
commit 33db1f30d0
15 changed files with 16639 additions and 665 deletions

View file

@ -7,7 +7,7 @@ let
# Poetry2nix version # Poetry2nix version
version = "1.31.0"; version = "1.31.0";
inherit (poetryLib) isCompatible readTOML moduleName underscorify; inherit (poetryLib) isCompatible readTOML normalizePackageName normalizePackageSet;
# Map SPDX identifiers to license names # Map SPDX identifiers to license names
spdxLicenses = lib.listToAttrs (lib.filter (pair: pair.name != null) (builtins.map (v: { name = if lib.hasAttr "spdxId" v then v.spdxId else null; value = v; }) (lib.attrValues lib.licenses))); spdxLicenses = lib.listToAttrs (lib.filter (pair: pair.name != null) (builtins.map (v: { name = if lib.hasAttr "spdxId" v then v.spdxId else null; value = v; }) (lib.attrValues lib.licenses)));
@ -17,6 +17,10 @@ let
# Experimental withPlugins functionality # Experimental withPlugins functionality
toPluginAble = (import ./plugins.nix { inherit pkgs lib; }).toPluginAble; toPluginAble = (import ./plugins.nix { inherit pkgs lib; }).toPluginAble;
# List of known build systems that are passed through from nixpkgs unmodified
knownBuildSystems = builtins.fromJSON (builtins.readFile ./known-build-systems.json);
nixpkgsBuildSystems = lib.subtractLists [ "poetry" "poetry-core" ] knownBuildSystems;
mkInputAttrs = mkInputAttrs =
{ py { py
, pyProject , pyProject
@ -38,7 +42,7 @@ let
( (
dep: dep:
let let
pkg = py.pkgs."${moduleName dep}"; pkg = py.pkgs."${normalizePackageName dep}";
constraints = depSet.${dep}.python or ""; constraints = depSet.${dep}.python or "";
isCompat = compat constraints; isCompat = compat constraints;
in in
@ -59,7 +63,6 @@ let
buildInputs = mkInput "buildInputs" (if includeBuildSystem then buildSystemPkgs else [ ]); buildInputs = mkInput "buildInputs" (if includeBuildSystem then buildSystemPkgs else [ ]);
propagatedBuildInputs = mkInput "propagatedBuildInputs" ( propagatedBuildInputs = mkInput "propagatedBuildInputs" (
(getDeps pyProject.tool.poetry."dependencies" or { }) (getDeps pyProject.tool.poetry."dependencies" or { })
++ ([ py.pkgs.setuptools ])
++ ( ++ (
# >=poetry-1.2.0 dependency groups # >=poetry-1.2.0 dependency groups
if pyProject.tool.poetry.group or { } != { } if pyProject.tool.poetry.group or { } != { }
@ -128,7 +131,7 @@ lib.makeScope pkgs.newScope (self: {
, editablePackageSources ? { } , editablePackageSources ? { }
, pyProject ? readTOML pyproject , pyProject ? readTOML pyproject
, groups ? [ ] , groups ? [ ]
}@attrs: }:
let let
/* The default list of poetry2nix override overlays */ /* The default list of poetry2nix override overlays */
mkEvalPep508 = import ./pep508.nix { mkEvalPep508 = import ./pep508.nix {
@ -157,15 +160,7 @@ lib.makeScope pkgs.newScope (self: {
let let
lockfiles = lib.getAttrFromPath [ "metadata" "files" ] poetryLock; lockfiles = lib.getAttrFromPath [ "metadata" "files" ] poetryLock;
in in
lib.listToAttrs (lib.mapAttrsToList (n: v: { name = moduleName n; value = v; }) lockfiles); lib.listToAttrs (lib.mapAttrsToList (n: v: { name = normalizePackageName n; value = v; }) lockfiles);
specialAttrs = [
"overrides"
"poetrylock"
"projectDir"
"pwd"
"preferWheels"
];
passedAttrs = builtins.removeAttrs attrs specialAttrs;
evalPep508 = mkEvalPep508 python; evalPep508 = mkEvalPep508 python;
# Filter packages by their PEP508 markers & pyproject interpreter version # Filter packages by their PEP508 markers & pyproject interpreter version
@ -183,12 +178,15 @@ lib.makeScope pkgs.newScope (self: {
# closure as python can only ever have one version of a dependency # closure as python can only ever have one version of a dependency
baseOverlay = self: super: baseOverlay = self: super:
let let
getDep = depName: self.${depName};
lockPkgs = builtins.listToAttrs ( lockPkgs = builtins.listToAttrs (
builtins.map builtins.map
( (
pkgMeta: rec { pkgMeta:
name = moduleName pkgMeta.name; if builtins.elem pkgMeta.name nixpkgsBuildSystems then {
name = pkgMeta.name;
value = super."${pkgMeta.name}";
} else rec {
name = normalizePackageName pkgMeta.name;
value = self.mkPoetryDep ( value = self.mkPoetryDep (
pkgMeta // { pkgMeta // {
inherit pwd preferWheels; inherit pwd preferWheels;
@ -196,17 +194,16 @@ lib.makeScope pkgs.newScope (self: {
files = lockFiles.${name}; files = lockFiles.${name};
pythonPackages = self; pythonPackages = self;
# Packages can be specified with underscores in pyproject.toml; check for sourceSpec =
# both possibilities. let
sourceSpec = with pyProject.tool.poetry; ( normalizedName = normalizePackageName pkgMeta.name;
dependencies.${pkgMeta.name} or in
dependencies.${underscorify pkgMeta.name} or with pyProject.tool.poetry; (
dev-dependencies.${pkgMeta.name} or (normalizePackageSet dependencies).${normalizedName}
dev-dependencies.${underscorify pkgMeta.name} or or (normalizePackageSet dev-dependencies).${normalizedName}
group.dev.dependencies.${underscorify pkgMeta.name} or # Poetry 1.2.0+ or (normalizePackageSet group.dev.dependencies).${normalizedName} # Poetry 1.2.0+
{ } or { }
);
);
} }
); );
} }
@ -255,7 +252,7 @@ lib.makeScope pkgs.newScope (self: {
super) super)
# Null out any filtered packages, we don't want python.pkgs from nixpkgs # Null out any filtered packages, we don't want python.pkgs from nixpkgs
(self: super: builtins.listToAttrs (builtins.map (x: { name = moduleName x.name; value = null; }) incompatible)) (self: super: builtins.listToAttrs (builtins.map (x: { name = normalizePackageName x.name; value = null; }) incompatible))
# Create poetry2nix layer # Create poetry2nix layer
baseOverlay baseOverlay
@ -303,7 +300,7 @@ lib.makeScope pkgs.newScope (self: {
, groups ? [ "dev" ] , groups ? [ "dev" ]
}: }:
let let
inherit (lib) elem hasAttr; inherit (lib) hasAttr;
pyProject = readTOML pyproject; pyProject = readTOML pyproject;
@ -395,7 +392,7 @@ lib.makeScope pkgs.newScope (self: {
py.pkgs.removeGitDependenciesHook py.pkgs.removeGitDependenciesHook
]; ];
} // { } // {
pname = moduleName pyProject.tool.poetry.name; pname = normalizePackageName pyProject.tool.poetry.name;
version = pyProject.tool.poetry.version; version = pyProject.tool.poetry.version;
inherit src; inherit src;
@ -477,7 +474,7 @@ lib.makeScope pkgs.newScope (self: {
Can be overriden by calling defaultPoetryOverrides.overrideOverlay which takes an overlay function Can be overriden by calling defaultPoetryOverrides.overrideOverlay which takes an overlay function
*/ */
defaultPoetryOverrides = self.mkDefaultPoetryOverrides (import ./overrides { inherit pkgs lib; }); defaultPoetryOverrides = self.mkDefaultPoetryOverrides (import ./overrides { inherit pkgs lib poetryLib; });
/* /*
Convenience functions for specifying overlays with or without the poerty2nix default overrides Convenience functions for specifying overlays with or without the poerty2nix default overrides

View file

@ -6,7 +6,7 @@
, editablePackageSources , editablePackageSources
}: }:
let let
name = poetryLib.moduleName pyProject.tool.poetry.name; name = poetryLib.normalizePackageName pyProject.tool.poetry.name;
# Just enough standard PKG-INFO fields for an editable installation # Just enough standard PKG-INFO fields for an editable installation
pkgInfoFields = { pkgInfoFields = {

12
known-build-systems.json Normal file
View file

@ -0,0 +1,12 @@
[
"poetry",
"poetry-core",
"flit",
"flit-core",
"pbr",
"flitBuildHook",
"cython",
"hatchling",
"setuptools",
"setuptools-scm"
]

18
lib.nix
View file

@ -8,12 +8,16 @@ let
genList (i: if i == idx then value else (builtins.elemAt list i)) (length list) genList (i: if i == idx then value else (builtins.elemAt list i)) (length list)
); );
# Do some canonicalisation of module names # Normalize package names as per PEP 503
moduleName = name: lib.toLower (lib.replaceStrings [ "_" "." ] [ "-" "-" ] name); normalizePackageName = name:
let
parts = builtins.split "[-_.]+" name;
partsWithoutSeparator = builtins.filter (x: builtins.typeOf x == "string") parts;
in
lib.strings.toLower (lib.strings.concatStringsSep "-" partsWithoutSeparator);
# For some reason, poetry replaces underscores with dashes in module # Normalize an entire attrset of packages
# names, this has to be reversed sometimes normalizePackageSet = lib.attrsets.mapAttrs' (name: value: lib.attrsets.nameValuePair (normalizePackageName name) value);
underscorify = name: (lib.replaceStrings [ "-" ] [ "_" ] name);
# Get a full semver pythonVersion from a python derivation # Get a full semver pythonVersion from a python derivation
getPythonVersion = python: getPythonVersion = python:
@ -237,8 +241,8 @@ in
getBuildSystemPkgs getBuildSystemPkgs
satisfiesSemver satisfiesSemver
cleanPythonSources cleanPythonSources
moduleName normalizePackageName
underscorify normalizePackageSet
getPythonVersion getPythonVersion
getTargetMachine getTargetMachine
; ;

View file

@ -26,7 +26,7 @@ pythonPackages.callPackage
}@args: }@args:
let let
inherit (python) stdenv; inherit (python) stdenv;
inherit (poetryLib) isCompatible getManyLinuxDeps fetchFromLegacy fetchFromPypi moduleName; inherit (poetryLib) isCompatible getManyLinuxDeps fetchFromLegacy fetchFromPypi normalizePackageName;
inherit (import ./pep425.nix { inherit (import ./pep425.nix {
inherit lib poetryLib python stdenv; inherit lib poetryLib python stdenv;
@ -88,23 +88,10 @@ pythonPackages.callPackage
else (builtins.elemAt (lib.strings.splitString "-" name) 2); else (builtins.elemAt (lib.strings.splitString "-" name) 2);
}; };
# Prevent infinite recursion
skipSetupToolsSCM = [
"setuptools_scm"
"setuptools-scm"
"toml" # Toml is an extra for setuptools-scm
"tomli" # tomli is an extra for later versions of setuptools-scm
"flit-core"
"packaging"
"six"
"pyparsing"
"typing-extensions"
];
baseBuildInputs = lib.optional (! lib.elem name skipSetupToolsSCM) pythonPackages.setuptools-scm;
format = if isDirectory || isGit || isUrl then "pyproject" else fileInfo.format; format = if isDirectory || isGit || isUrl then "pyproject" else fileInfo.format;
in in
buildPythonPackage { buildPythonPackage {
pname = moduleName name; pname = normalizePackageName name;
version = version; version = version;
inherit format; inherit format;
@ -124,10 +111,9 @@ pythonPackages.callPackage
]; ];
buildInputs = ( buildInputs = (
baseBuildInputs lib.optional (!isSource) (getManyLinuxDeps fileInfo.name).pkg
++ lib.optional (stdenv.buildPlatform != stdenv.hostPlatform) pythonPackages.setuptools
++ lib.optional (!isSource) (getManyLinuxDeps fileInfo.name).pkg
++ lib.optional isDirectory buildSystemPkgs ++ lib.optional isDirectory buildSystemPkgs
++ lib.optional (stdenv.buildPlatform != stdenv.hostPlatform) pythonPackages.setuptools
); );
propagatedBuildInputs = propagatedBuildInputs =
@ -149,7 +135,7 @@ pythonPackages.callPackage
); );
depAttrs = lib.attrNames deps; depAttrs = lib.attrNames deps;
in in
builtins.map (n: pythonPackages.${moduleName n}) depAttrs; builtins.map (n: pythonPackages.${normalizePackageName n}) depAttrs;
meta = { meta = {
broken = ! isCompatible (poetryLib.getPythonVersion python) python-versions; broken = ! isCompatible (poetryLib.getPythonVersion python) python-versions;

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,7 @@
{ pkgs ? import <nixpkgs> { } { pkgs ? import <nixpkgs> { }
, lib ? pkgs.lib , lib ? pkgs.lib
, stdenv ? pkgs.stdenv , stdenv ? pkgs.stdenv
, poetryLib
}: }:
let let
@ -38,6 +39,7 @@ let
# Flit only works on Python3 # Flit only works on Python3
if (attr == "flit-core" || attr == "flit" || attr == "hatchling") && !self.isPy3k then drv if (attr == "flit-core" || attr == "flit" || attr == "hatchling") && !self.isPy3k then drv
else if drv == null then null else if drv == null then null
else if drv ? overridePythonAttrs == false then drv
else else
drv.overridePythonAttrs ( drv.overridePythonAttrs (
old: old:
@ -57,6 +59,8 @@ let
in in
lib.composeManyExtensions [ lib.composeManyExtensions [
# normalize all the names
(self: super: poetryLib.normalizePackageSet super)
# NixOps # NixOps
(self: super: (self: super:
@ -81,22 +85,11 @@ lib.composeManyExtensions [
systems) systems)
buildSystems) buildSystems)
# Build systems with conditionals
(self: super: {
platformdirs =
if lib.versionAtLeast super.platformdirs.version "2.5.2"
then addBuildSystem { inherit self; drv = super.platformdirs; attr = "hatchling"; extraAttrs = [ "hatch-vcs" ]; }
else super.platformdirs;
})
# Build fixes # Build fixes
(self: super: (self: super:
let let
inherit (self.python) stdenv; inherit (self.python) stdenv;
inherit (pkgs.buildPackages) pkg-config; inherit (pkgs.buildPackages) pkg-config;
inherit (pkgs) buildPackages;
pyBuildPackages = self.python.pythonForBuild.pkgs; pyBuildPackages = self.python.pythonForBuild.pkgs;
selectQt5 = version: selectQt5 = version:
@ -109,7 +102,7 @@ lib.composeManyExtensions [
{ {
automat = super.automat.overridePythonAttrs ( automat = super.automat.overridePythonAttrs (
old: rec { old: {
propagatedBuildInputs = (old.propagatedBuildInputs or [ ]) ++ [ self.m2r ]; propagatedBuildInputs = (old.propagatedBuildInputs or [ ]) ++ [ self.m2r ];
} }
); );
@ -153,7 +146,7 @@ lib.composeManyExtensions [
); );
argcomplete = super.argcomplete.overridePythonAttrs ( argcomplete = super.argcomplete.overridePythonAttrs (
old: rec { old: {
buildInputs = (old.buildInputs or [ ]) ++ [ self.importlib-metadata ]; buildInputs = (old.buildInputs or [ ]) ++ [ self.importlib-metadata ];
} }
); );
@ -165,7 +158,7 @@ lib.composeManyExtensions [
); );
astroid = super.astroid.overridePythonAttrs ( astroid = super.astroid.overridePythonAttrs (
old: rec { old: {
buildInputs = (old.buildInputs or [ ]) ++ [ self.pytest-runner ]; buildInputs = (old.buildInputs or [ ]) ++ [ self.pytest-runner ];
} }
); );
@ -657,6 +650,11 @@ lib.composeManyExtensions [
outputs = [ "out" "dev" ]; outputs = [ "out" "dev" ];
}); });
gunicorn = super.gunicorn.overridePythonAttrs (old: {
# actually needs setuptools as a runtime dependency
propagatedBuildInputs = (old.buildInputs or [ ]) ++ [ self.setuptools ];
});
h3 = super.h3.overridePythonAttrs ( h3 = super.h3.overridePythonAttrs (
old: { old: {
preBuild = (old.preBuild or "") + '' preBuild = (old.preBuild or "") + ''
@ -877,7 +875,7 @@ lib.composeManyExtensions [
else super.jsonschema; else super.jsonschema;
jupyter = super.jupyter.overridePythonAttrs ( jupyter = super.jupyter.overridePythonAttrs (
old: rec { old: {
# jupyter is a meta-package. Everything relevant comes from the # jupyter is a meta-package. Everything relevant comes from the
# dependencies. It does however have a jupyter.py file that conflicts # dependencies. It does however have a jupyter.py file that conflicts
# with jupyter-core so this meta solves this conflict. # with jupyter-core so this meta solves this conflict.
@ -890,7 +888,7 @@ lib.composeManyExtensions [
}); });
jupyterlab-widgets = super.jupyterlab-widgets.overridePythonAttrs ( jupyterlab-widgets = super.jupyterlab-widgets.overridePythonAttrs (
old: rec { old: {
buildInputs = (old.buildInputs or [ ]) ++ [ self.jupyter-packaging ]; buildInputs = (old.buildInputs or [ ]) ++ [ self.jupyter-packaging ];
} }
); );
@ -1131,11 +1129,11 @@ lib.composeManyExtensions [
excludes = [ "pyproject.toml" ]; excludes = [ "pyproject.toml" ];
}) })
]; ];
buildInputs = (old.buildInputs or [ ]) ++ [ self.setuptools-scm-git-archive ]; buildInputs = (old.buildInputs or [ ]) ++ [ self.setuptools self.setuptools-scm self.setuptools-scm-git-archive ];
} }
)) else )) else
super.molecule.overridePythonAttrs (old: { super.molecule.overridePythonAttrs (old: {
buildInputs = (old.buildInputs or [ ]) ++ [ self.setuptools-scm-git-archive ]; buildInputs = (old.buildInputs or [ ]) ++ [ self.setuptools self.setuptools-scm self.setuptools-scm-git-archive ];
}); });
mpi4py = super.mpi4py.overridePythonAttrs ( mpi4py = super.mpi4py.overridePythonAttrs (
@ -1300,7 +1298,7 @@ lib.composeManyExtensions [
); );
openexr = super.openexr.overridePythonAttrs ( openexr = super.openexr.overridePythonAttrs (
old: rec { old: {
buildInputs = (old.buildInputs or [ ]) ++ [ pkgs.openexr pkgs.ilmbase ]; buildInputs = (old.buildInputs or [ ]) ++ [ pkgs.openexr pkgs.ilmbase ];
NIX_CFLAGS_COMPILE = [ "-I${pkgs.openexr.dev}/include/OpenEXR" "-I${pkgs.ilmbase.dev}/include/OpenEXR" ]; NIX_CFLAGS_COMPILE = [ "-I${pkgs.openexr.dev}/include/OpenEXR" "-I${pkgs.ilmbase.dev}/include/OpenEXR" ];
} }
@ -1385,7 +1383,7 @@ lib.composeManyExtensions [
}); });
parsel = super.parsel.overridePythonAttrs ( parsel = super.parsel.overridePythonAttrs (
old: rec { old: {
nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ self.pytest-runner ]; nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ self.pytest-runner ];
} }
); );
@ -1934,7 +1932,7 @@ lib.composeManyExtensions [
); );
rockset = super.rockset.overridePythonAttrs ( rockset = super.rockset.overridePythonAttrs (
old: rec { old: {
postPatch = '' postPatch = ''
cp ./setup_rockset.py ./setup.py cp ./setup_rockset.py ./setup.py
''; '';

View file

@ -121,5 +121,6 @@ builtins.removeAttrs
# Once this is available in 19.09 and unstable we can re-enable the manylinux test # Once this is available in 19.09 and unstable we can re-enable the manylinux test
manylinux = callTest ./manylinux { }; manylinux = callTest ./manylinux { };
shapely = callTest ./shapely { }; shapely = callTest ./shapely { };
setuptools = callTest ./setuptools { };
} }
skipTests skipTests

View file

@ -327,7 +327,7 @@ python-versions = "*"
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.6" python-versions = "^3.6"
content-hash = "5a83192fb095e50ac54daf8b7d6c63abf824fdd5d87458b93bfe88b0e201c0c6" content-hash = "29715f340ec421fd9e3d4ec49f4363e9129714832fb17282c8b8dba9b3833db7"
[metadata.files] [metadata.files]
boto3-stubs = [ boto3-stubs = [

View file

@ -6,7 +6,7 @@ authors = ["Your Name <you@example.com>"]
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.6" python = "^3.6"
setuptools-scm = { version = "^3.4", extras = ["toml"] } setuptools-scm = { version = ">=3.4", extras = ["toml"] }
# Extra with dash in the name should work # Extra with dash in the name should work
boto3-stubs = {extras = ["cognito-idp"], version = "^1.17.82"} boto3-stubs = {extras = ["cognito-idp"], version = "^1.17.82"}

View file

@ -0,0 +1,8 @@
{ lib, poetry2nix, python3 }:
poetry2nix.mkPoetryApplication {
python = python3;
pyproject = ./pyproject.toml;
poetrylock = ./poetry.lock;
src = lib.cleanSource ./.;
}

23
tests/setuptools/poetry.lock generated Normal file
View file

@ -0,0 +1,23 @@
[[package]]
name = "setuptools"
version = "65.4.1"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
category = "main"
optional = false
python-versions = ">=3.7"
[package.extras]
docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mock", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
[metadata]
lock-version = "1.1"
python-versions = "^3.10"
content-hash = "bbc2fde99c9aade70aa71c355e2067e25e7d3993814d132cf6a9d8acbb3f251e"
[metadata.files]
setuptools = [
{file = "setuptools-65.4.1-py3-none-any.whl", hash = "sha256:1b6bdc6161661409c5f21508763dc63ab20a9ac2f8ba20029aaaa7fdb9118012"},
{file = "setuptools-65.4.1.tar.gz", hash = "sha256:3050e338e5871e70c72983072fe34f6032ae1cdeeeb67338199c2f74e083a80e"},
]

View file

@ -0,0 +1,13 @@
[tool.poetry]
name = "setuptools_test"
version = "0.1.0"
description = ""
authors = ["Your Name <you@example.com>"]
[tool.poetry.dependencies]
python = "^3.10"
setuptools = "*"
[build-system]
requires = ["poetry-core>=1.1"]
build-backend = "poetry.core.masonry.api"

View file

@ -2,11 +2,13 @@
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
from itertools import chain from itertools import chain
from posix import cpu_count from posix import cpu_count
import re
from typing import ( from typing import (
Dict, Dict,
List, List,
Set, Set,
) )
from pathlib import Path
import subprocess import subprocess
import pynixutil import pynixutil
import tempfile import tempfile
@ -21,16 +23,8 @@ import sys
# All known PEP-517 (or otherwise) build systems # All known PEP-517 (or otherwise) build systems
BUILD_SYSTEMS = [ with (Path(__file__).parent.parent / "known-build-systems.json").open() as _fd:
"poetry", BUILD_SYSTEMS = json.load(_fd)
"poetry-core",
"flit",
"flit-core",
"pbr",
"flitBuildHook",
"cython",
"hatchling",
]
# Skip these attributes as they have more complex conditions manually # Skip these attributes as they have more complex conditions manually
@ -40,10 +34,16 @@ SKIP_ATTRS = {
"packaging", "packaging",
"poetry", "poetry",
"flitBuildHook", "flitBuildHook",
"jsonschema",
"platformdirs", "platformdirs",
"traitlets",
} }
def normalize(name):
return re.sub(r"[-_.]+", "-", name).lower()
def find_known_systems() -> Dict[str, str]: def find_known_systems() -> Dict[str, str]:
"""Create a map from attribute to drvPath for known build systems""" """Create a map from attribute to drvPath for known build systems"""
@ -130,15 +130,31 @@ def get_build_systems(known_systems) -> Dict[str, List[str]]:
return {attr: systems for attr, systems in build_systems.items() if systems} return {attr: systems for attr, systems in build_systems.items() if systems}
BLOCKLIST = {"poetry", "poetry-core"}
def merge_systems(s):
simple = {i for i in s if isinstance(i, str)}
complex = [i for i in s if isinstance(i, dict)]
complex_names = {i["buildSystem"] for i in complex}
new_simple = simple - complex_names
return complex + sorted(list(new_simple))
def merge(prev_content, new_content): def merge(prev_content, new_content):
content = {} content = {}
for attr, systems in chain(prev_content.items(), new_content.items()): for attr, systems in chain(prev_content.items(), new_content.items()):
s = content.setdefault(attr, set()) attr = normalize(attr)
s = content.setdefault(attr, [])
for system in systems: for system in systems:
s.add(system) s.append(system)
# Return with sorted data # Return with sorted data
return {attr: sorted(content[attr]) for attr in sorted(content.keys())} return {
attr: merge_systems(content[attr])
for attr in sorted(content.keys())
if attr not in BLOCKLIST
}
def main(): def main():