1
1
from __future__ import annotations
2
2
3
3
import pathlib
4
+ import sys
4
5
from typing import TYPE_CHECKING
5
6
6
- import distlib . scripts
7
- from distlib . wheel import Wheel
7
+ from installer . exceptions import InvalidWheelSource
8
+ from installer . sources import WheelFile as _WheelFile
8
9
from pip ._vendor .pkg_resources import EggInfoDistribution
9
10
10
11
from pdm import termui
11
12
from pdm .models import pip_shims
12
13
from pdm .models .requirements import parse_requirement
14
+ from pdm .utils import cached_property
13
15
14
16
if TYPE_CHECKING :
15
17
from pip ._vendor .pkg_resources import Distribution
@@ -30,6 +32,23 @@ def format_dist(dist: Distribution) -> str:
30
32
return formatter .format (version = termui .yellow (dist .version ), path = path )
31
33
32
34
35
+ class WheelFile (_WheelFile ):
36
+ @cached_property
37
+ def dist_info_dir (self ) -> str :
38
+ namelist = self ._zipfile .namelist ()
39
+ try :
40
+ return next (
41
+ name .split ("/" )[0 ]
42
+ for name in namelist
43
+ if name .split ("/" )[0 ].endswith (".dist-info" )
44
+ )
45
+ except StopIteration : # pragma: no cover
46
+ canonical_name = super ().dist_info_dir
47
+ raise InvalidWheelSource (
48
+ f"The wheel doesn't contain metadata { canonical_name !r} "
49
+ )
50
+
51
+
33
52
class Installer : # pragma: no cover
34
53
"""The installer that performs the installation and uninstallation actions."""
35
54
@@ -44,17 +63,27 @@ def install(self, candidate: Candidate) -> None:
44
63
self .install_editable (candidate .ireq )
45
64
else :
46
65
built = candidate .build ()
47
- self .install_wheel (Wheel ( built ) )
66
+ self .install_wheel (built )
48
67
49
- def install_wheel (self , wheel : Wheel ) -> None :
50
- paths = self .environment .get_paths ()
51
- maker = distlib .scripts .ScriptMaker (None , None )
52
- maker .variants = set (("" ,))
53
- enquoted_executable = distlib .scripts .enquote_executable (
54
- self .environment .interpreter .executable
68
+ def install_wheel (self , wheel : str ) -> None :
69
+ from installer import __version__ , install
70
+ from installer .destinations import SchemeDictionaryDestination
71
+
72
+ destination = SchemeDictionaryDestination (
73
+ self .environment .get_paths (),
74
+ interpreter = self .environment .interpreter .executable ,
75
+ script_kind = self ._get_kind (),
55
76
)
56
- maker .executable = enquoted_executable
57
- wheel .install (paths , maker )
77
+
78
+ with WheelFile .open (wheel ) as source :
79
+ install (
80
+ source = source ,
81
+ destination = destination ,
82
+ # Additional metadata that is generated by the installation tool.
83
+ additional_metadata = {
84
+ "INSTALLER" : f"installer { __version__ } " .encode (),
85
+ },
86
+ )
58
87
59
88
def install_editable (self , ireq : pip_shims .InstallRequirement ) -> None :
60
89
from pdm .builders import EditableBuilder
@@ -83,3 +112,13 @@ def uninstall(self, dist: Distribution) -> None:
83
112
pathset = ireq .uninstall (auto_confirm = self .auto_confirm )
84
113
if pathset :
85
114
pathset .commit ()
115
+
116
+ def _get_kind (self ) -> str :
117
+ if sys .platform != "win32" :
118
+ return "posix"
119
+ is_32bit = self .environment .interpreter .is_32bit
120
+ # TODO: support win arm64
121
+ if is_32bit :
122
+ return "win-ia32"
123
+ else :
124
+ return "win-amd64"
0 commit comments