summary refs log tree commit diff
path: root/pkgs/development/tools/poetry2nix/poetry2nix/pep425.nix
blob: cda4e8c78d4d5a3397f5aa78866d48a749ce0e72 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
{ lib, stdenv, python, isLinux ? stdenv.isLinux }:
let
  inherit (lib.strings) hasSuffix hasInfix splitString removeSuffix;

  # The 'cpxy" as determined by `python.version`
  #
  # e.g "2.7.17" -> "cp27"
  #     "3.5.9"  -> "cp35"
  pythonTag =
    let
      ver = builtins.splitVersion python.version;
      major = builtins.elemAt ver 0;
      minor = builtins.elemAt ver 1;
    in
      "cp${major}${minor}";

  abiTag = "${pythonTag}m";

  #
  # Parses wheel file returning an attribute set
  #
  toWheelAttrs = str:
    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;
      };

  #
  # Builds list of acceptable osx wheel files
  #
  # <versions>   accepted versions in descending order of preference
  # <candidates> list of wheel files to select from
  findBestMatches = versions: candidates:
    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);

  # pyver = "cpXX"
  # x     = "cpXX" | "py2" | "py3" | "py2.py3"
  isPyVersionCompatible = pyver: x:
    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);

  #
  # Selects the best matching wheel file from a list of files
  #
  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");

      filterWheel = x:
        let
          f = toWheelAttrs x.file;
        in
          (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));
        in
          if isLinux
          then chooseLinux files
          else chooseOSX files;
    in
      if (builtins.length filtered == 0)
      then []
      else choose (filtered);
in
{
  inherit selectWheel toWheelAttrs isPyVersionCompatible;
}