diff --git a/default.nix b/default.nix index 22c1748..ca4cb98 100644 --- a/default.nix +++ b/default.nix @@ -244,7 +244,7 @@ lib.makeScope pkgs.newScope (self: { super) ( - self: super: + self: _super: { mkPoetryDep = self.callPackage ./mk-poetry-dep.nix { inherit lib python poetryLib pep508Env pyVersion; diff --git a/mk-poetry-dep.nix b/mk-poetry-dep.nix index c58370f..62f0067 100644 --- a/mk-poetry-dep.nix +++ b/mk-poetry-dep.nix @@ -30,7 +30,7 @@ let wheelFiles = builtins.filter (fileEntry: pypa.isWheelFileName fileEntry.file) files; # Group wheel files by their file name wheelFilesByFileName = lib.listToAttrs (map (fileEntry: lib.nameValuePair fileEntry.file fileEntry) wheelFiles); - selectedWheels = pypa.selectWheels python (map (fileEntry: pypa.parseWheelFileName fileEntry.file) wheelFiles); + selectedWheels = pypa.selectWheels python.stdenv.targetPlatform python (map (fileEntry: pypa.parseWheelFileName fileEntry.file) wheelFiles); in map (wheel: wheelFilesByFileName.${wheel.filename}) selectedWheels); in @@ -102,10 +102,6 @@ pythonPackages.callPackage if _isEgg then "egg" else if lib.strings.hasSuffix ".whl" name then "wheel" else "pyproject"; - kind = - if _isEgg then python.pythonVersion - else if format == "pyproject" then "source" - else (builtins.elemAt (lib.strings.splitString "-" name) 2); }; format = if isWheelUrl then "wheel" else if isDirectory || isGit || isUrl then "pyproject" else fileInfo.format; @@ -234,7 +230,7 @@ pythonPackages.callPackage else pyproject-nix.fetchers.fetchFromPypi { pname = name; - inherit (fileInfo) file hash kind; + inherit (fileInfo) file hash; inherit version; }; in diff --git a/vendor/pyproject.nix/default.nix b/vendor/pyproject.nix/default.nix index 99f6f25..e226206 100644 --- a/vendor/pyproject.nix/default.nix +++ b/vendor/pyproject.nix/default.nix @@ -1,5 +1,5 @@ { pkgs, lib }: { lib = import ./lib { inherit lib; }; - fetchers = import ./fetchers { inherit pkgs lib; }; + fetchers = pkgs.callPackage ./fetchers { }; } diff --git a/vendor/pyproject.nix/fetchers/default.nix b/vendor/pyproject.nix/fetchers/default.nix index 1665a2e..c31724a 100644 --- a/vendor/pyproject.nix/fetchers/default.nix +++ b/vendor/pyproject.nix/fetchers/default.nix @@ -1,11 +1,16 @@ -{ pkgs +{ curl +, jq , lib -, +, python3 +, runCommand +, stdenvNoCC }: let - inherit (builtins) substring filter head nixPath; + inherit (builtins) substring filter head nixPath elemAt; inherit (lib) toLower; + pyproject = import ../lib { inherit lib; }; + # Predict URL from the PyPI index. # Args: # pname: package name @@ -18,10 +23,16 @@ let pname , # filename including extension file - , # Language implementation and version tag - kind - , - }: "https://files.pythonhosted.org/packages/${kind}/${toLower (substring 0 1 file)}/${pname}/${file}"; + }: + let + matchedWheel = pyproject.pypa.matchWheelFileName file; + matchedEgg = pyproject.pypa.matchEggFileName file; + kind = + if matchedWheel != null then "wheel" + else if matchedEgg != null then elemAt matchedEgg 2 + else "source"; + in + "https://files.pythonhosted.org/packages/${kind}/${toLower (substring 0 1 file)}/${pname}/${file}"; in lib.mapAttrs (_: func: lib.makeOverridable func) { /* @@ -42,20 +53,18 @@ lib.mapAttrs (_: func: lib.makeOverridable func) { version , # SRI hash hash - , # Language implementation and version tag - kind , # Options to pass to `curl` curlOpts ? "" , }: let - predictedURL = predictURLFromPypi { inherit pname file kind; }; + predictedURL = predictURLFromPypi { inherit pname file; }; in - pkgs.stdenvNoCC.mkDerivation { + stdenvNoCC.mkDerivation { name = file; nativeBuildInputs = [ - pkgs.buildPackages.curl - pkgs.buildPackages.jq + curl + jq ]; isWheel = lib.strings.hasSuffix "whl" file; system = "builtin"; @@ -106,9 +115,9 @@ lib.mapAttrs (_: func: lib.makeOverridable func) { then (head pathParts).path else ""; in - pkgs.runCommand file + runCommand file { - nativeBuildInputs = [ pkgs.buildPackages.python3 ]; + nativeBuildInputs = [ python3 ]; impureEnvVars = lib.fetchers.proxyImpureEnvVars; outputHashMode = "flat"; outputHashAlgo = "sha256"; diff --git a/vendor/pyproject.nix/lib/pep440.nix b/vendor/pyproject.nix/lib/pep440.nix index 3057ce4..59b6958 100644 --- a/vendor/pyproject.nix/lib/pep440.nix +++ b/vendor/pyproject.nix/lib/pep440.nix @@ -1,7 +1,8 @@ { lib, ... }: let - inherit (builtins) split filter match length elemAt head tail foldl' fromJSON typeOf; + inherit (builtins) split filter match length elemAt head foldl' fromJSON typeOf; inherit (lib) fix isString toInt toLower sublist; + inherit (import ./util.nix { inherit lib; }) splitComma; filterNull = filter (x: x != null); filterEmpty = filter (x: length x > 0); @@ -54,19 +55,19 @@ let parseLocal = parseReleaseSuffix "\\+"; # Compare the release fields from the parsed version - compareRelease = ra: rb: + compareRelease = offset: ra: rb: let - x = head ra; - y = head rb; + x = elemAt ra offset; + y = elemAt rb offset; in - if length ra == 0 || length rb == 0 then 0 else + if length ra == offset || length rb == offset then 0 else ( if x == "*" || y == "*" then 0 # Wildcards are always considered equal else ( if x > y then 1 else if x < y then -1 - else compareRelease (tail ra) (tail rb) + else compareRelease (offset + 1) ra rb ) ); @@ -160,6 +161,42 @@ fix (self: { } ); + /* Parse a list of version conditionals separated by commas. + + Type: parseVersionConds :: string -> [AttrSet] + + Example: + # parseVersionConds ">=3.0.0rc1,<=4.0" + [ + { + op = ">="; + version = { + dev = null; + epoch = 0; + local = null; + post = null; + pre = { + type = "rc"; + value = 1; + }; + release = [ 3 0 0 ]; + }; + } + { + op = "<="; + version = { + dev = null; + epoch = 0; + local = null; + post = null; + pre = null; + release = [ 4 0 ]; + }; + } + ] + */ + parseVersionConds = conds: map self.parseVersionCond (splitComma conds); + /* Compare two versions as parsed by `parseVersion` according to PEP-440. Returns: @@ -180,7 +217,7 @@ fix (self: { # is valid and we need to consider them all. # Compare release field - (compareRelease a.release b.release) + (compareRelease 0 a.release b.release) # Compare pre release ( diff --git a/vendor/pyproject.nix/lib/pep508.nix b/vendor/pyproject.nix/lib/pep508.nix index 40f75a1..ada16ba 100644 --- a/vendor/pyproject.nix/lib/pep508.nix +++ b/vendor/pyproject.nix/lib/pep508.nix @@ -350,7 +350,7 @@ fix (self: m2 = match "([a-zA-Z0-9_\\.-]+)(.*)" tokens.packageSegment; # The version conditions as a list of strings - conditions = map pep440.parseVersionCond (splitComma (if m1 != null then elemAt m1 2 else elemAt m2 1)); + conditions = pep440.parseVersionConds (if m1 != null then elemAt m1 2 else elemAt m2 1); # Extras as a list of strings # diff --git a/vendor/pyproject.nix/lib/pep600.nix b/vendor/pyproject.nix/lib/pep600.nix index 6a8d506..bfd299c 100644 --- a/vendor/pyproject.nix/lib/pep600.nix +++ b/vendor/pyproject.nix/lib/pep600.nix @@ -31,13 +31,19 @@ fix (self: { /* Check if a manylinux tag is compatible with a given stdenv. - Type: manyLinuxTagCompatible :: AttrSet -> string -> bool + Type: manyLinuxTagCompatible :: AttrSet -> derivation -> string -> bool Example: - # manyLinuxTagCompatible pkgs.stdenv "manylinux_2_5_x86_64" + # manyLinuxTagCompatible pkgs.stdenv.targetPlatform pkgs.stdenv.cc.libc "manylinux_2_5_x86_64" true */ - manyLinuxTagCompatible = stdenv: tag: + manyLinuxTagCompatible = + # Platform attrset (`lib.systems.elaborate "x86_64-linux"`) + platform: + # Libc derivation + libc: + # Platform tag string + tag: let tag' = self.legacyAliases.${tag} or tag; m = match "manylinux_([0-9]+)_([0-9]+)_(.*)" tag'; @@ -45,14 +51,15 @@ fix (self: { tagMajor = mAt 0; tagMinor = mAt 1; tagArch = mAt 2; - sysVersion' = elemAt (splitVersion stdenv.cc.libc.version); + sysVersion' = elemAt (splitVersion libc.version); sysMajor = sysVersion' 0; sysMinor = sysVersion' 1; in if m == null then throw "'${tag'}' is not a valid manylinux tag." - else if stdenv.cc.libc.pname != "glibc" then false + else if platform.libc != "glibc" then false + else if libc.pname != "glibc" then false else if compareVersions "${sysMajor}.${sysMinor}" "${tagMajor}.${tagMinor}" < 0 then false - else if pep599.manyLinuxTargetMachines.${tagArch} != stdenv.targetPlatform.parsed.cpu.name then false + else if pep599.manyLinuxTargetMachines.${tagArch} != platform.parsed.cpu.name then false else true; }) diff --git a/vendor/pyproject.nix/lib/pep621.nix b/vendor/pyproject.nix/lib/pep621.nix index 13de814..dfa078c 100644 --- a/vendor/pyproject.nix/lib/pep621.nix +++ b/vendor/pyproject.nix/lib/pep621.nix @@ -46,7 +46,7 @@ fix (self: { # parseRequiresPython (lib.importTOML ./pyproject.toml) [ ] # List of conditions as returned by `lib.pep440.parseVersionCond` */ - parseRequiresPython = pyproject: map pep440.parseVersionCond (filter isString (split "," (pyproject.project.requires-python or ""))); + parseRequiresPython = pyproject: pep440.parseVersionConds (pyproject.project.requires-python or ""); /* Takes a dependency structure as returned by `lib.pep621.parseDependencies` and transforms it into a structure with it's package names. diff --git a/vendor/pyproject.nix/lib/pep656.nix b/vendor/pyproject.nix/lib/pep656.nix index 80b2336..4888dd6 100644 --- a/vendor/pyproject.nix/lib/pep656.nix +++ b/vendor/pyproject.nix/lib/pep656.nix @@ -7,27 +7,34 @@ in { /* Check if a musllinux tag is compatible with a given stdenv. - Type: muslLinuxTagCompatible :: AttrSet -> string -> bool + Type: muslLinuxTagCompatible :: AttrSet -> derivation -> string -> bool Example: - # muslLinuxTagCompatible pkgs.stdenv "musllinux_1_1_x86_64" + # muslLinuxTagCompatible pkgs.stdenv.targetPlatform pkgs.stdenv.cc.libc "musllinux_1_1_x86_64" true */ - muslLinuxTagCompatible = stdenv: tag: + muslLinuxTagCompatible = + # Platform attrset (`lib.systems.elaborate "x86_64-linux"`) + platform: + # Libc derivation + libc: + # Platform tag string + tag: let m = match "musllinux_([0-9]+)_([0-9]+)_(.*)" tag; mAt = elemAt m; tagMajor = mAt 0; tagMinor = mAt 1; tagArch = mAt 2; - sysVersion' = elemAt (splitVersion stdenv.cc.libc.version); + sysVersion' = elemAt (splitVersion libc.version); sysMajor = sysVersion' 0; sysMinor = sysVersion' 1; in if m == null then throw "'${tag}' is not a valid musllinux tag." - else if stdenv.cc.libc.pname != "musl" then false + else if platform.libc != "musl" then false + else if libc.pname != "musl" then false else if compareVersions "${sysMajor}.${sysMinor}" "${tagMajor}.${tagMinor}" < 0 then false - else if pep599.manyLinuxTargetMachines.${tagArch} != stdenv.targetPlatform.parsed.cpu.name then false + else if pep599.manyLinuxTargetMachines.${tagArch} != platform.parsed.cpu.name then false else true; } diff --git a/vendor/pyproject.nix/lib/pypa.nix b/vendor/pyproject.nix/lib/pypa.nix index 96e372e..204d1c7 100644 --- a/vendor/pyproject.nix/lib/pypa.nix +++ b/vendor/pyproject.nix/lib/pypa.nix @@ -6,6 +6,9 @@ let matchWheelFileName = match "([^-]+)-([^-]+)(-([[:digit:]][^-]*))?-([^-]+)-([^-]+)-(.+).whl"; + # PEP-625 only specifies .tar.gz as valid extension but .zip is also fairly widespread. + matchSdistFileName = match "([^-]+)-(.+)(\.tar\.gz|\.zip)"; + # Tag normalization documented in # https://packaging.python.org/en/latest/specifications/platform-compatibility-tags/#details normalizedImpls = { @@ -92,6 +95,39 @@ lib.fix (self: { rest = mAt 2; }; + /* Check whether string is a sdist file or not. + + Type: isSdistFileName :: string -> bool + + Example: + # isSdistFileName "cryptography-41.0.1.tar.gz" + true + */ + isSdistFileName = + # The filename string + name: matchSdistFileName name != null; + + + /* Regex match a wheel file name, returning a list of match groups. Returns null if no match. + + Type: matchWheelFileName :: string -> [ string ] + */ + matchWheelFileName = name: + let + m = match "([^-]+)-([^-]+)(-([[:digit:]][^-]*))?-([^-]+)-([^-]+)-(.+).whl" name; + in + if m != null then filter isString m else null; + + /* Regex match an egg file name, returning a list of match groups. Returns null if no match. + + Type: matchEggFileName :: string -> [ string ] + */ + matchEggFileName = name: + let + m = match "([^-]+)-([^-]+)-(.+)\\.egg" name; + in + if m != null then filter isString m else null; + /* Check whether string is a wheel file or not. Type: isWheelFileName :: string -> bool @@ -100,7 +136,9 @@ lib.fix (self: { # isWheelFileName "cryptography-41.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" true */ - isWheelFileName = name: matchWheelFileName name != null; + isWheelFileName = + # The filename string + name: matchWheelFileName name != null; /* Parse PEP-427 wheel file names. @@ -179,23 +217,22 @@ lib.fix (self: { /* Check whether a platform tag is compatible with this python interpreter. - Type: isPlatformTagCompatible :: derivation -> string -> bool + Type: isPlatformTagCompatible :: AttrSet -> derivation -> string -> bool Example: # isPlatformTagCompatible pkgs.python3 "manylinux2014_x86_64" true */ isPlatformTagCompatible = - # Python interpreter derivation - python: + # Platform attrset (`lib.systems.elaborate "x86_64-linux"`) + platform: + # Libc derivation + libc: # Python tag platformTag: - let - platform = python.stdenv.targetPlatform; - in if platformTag == "any" then true - else if hasPrefix "manylinux" platformTag then pep600.manyLinuxTagCompatible python.stdenv platformTag - else if hasPrefix "musllinux" platformTag then pep656.muslLinuxTagCompatible python.stdenv platformTag + else if hasPrefix "manylinux" platformTag then pep600.manyLinuxTagCompatible platform libc platformTag + else if hasPrefix "musllinux" platformTag then pep656.muslLinuxTagCompatible platform libc platformTag else if hasPrefix "macosx" platformTag then ( let @@ -245,7 +282,7 @@ lib.fix (self: { Type: isPythonTagCompatible :: derivation -> AttrSet -> bool Example: - # isPlatformTagCompatible pkgs.python3 (pypa.parsePythonTag "py3") + # isPythonTagCompatible pkgs.python3 (pypa.parsePythonTag "py3") true */ isPythonTagCompatible = @@ -277,6 +314,10 @@ lib.fix (self: { true */ isWheelFileCompatible = + # Platform attrset (`lib.systems.elaborate "x86_64-linux"`) + platform: + # Libc derivation + libc: # Python interpreter derivation python: # The parsed wheel filename @@ -286,7 +327,7 @@ lib.fix (self: { && lib.any (self.isPythonTagCompatible python) file.languageTags && - lib.any (self.isPlatformTagCompatible python) file.platformTags + lib.any (self.isPlatformTagCompatible platform libc) file.platformTags ); /* Select compatible wheels from a list and return them in priority order. @@ -298,6 +339,8 @@ lib.fix (self: { [ (pypa.parseWheelFileName "Pillow-9.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl") ] */ selectWheels = + # Platform attrset (`lib.systems.elaborate "x86_64-linux"`) + platform: # Python interpreter derivation python: # List of files as parsed by parseWheelFileName @@ -317,7 +360,7 @@ lib.fix (self: { in { bestLanguageTag = head (sort (x: y: x > y) languageTags'); - compatible = abiCompatible && length languageTags > 0 && lib.any (self.isPlatformTagCompatible python) file.platformTags; + compatible = abiCompatible && length languageTags > 0 && lib.any (self.isPlatformTagCompatible platform python.stdenv.cc.libc) file.platformTags; inherit file; }) files;