1
1
from __future__ import annotations
2
2
3
- import os
4
3
import tempfile
5
4
6
- from contextlib import redirect_stdout
7
- from io import StringIO
8
5
from pathlib import Path
9
6
from typing import TYPE_CHECKING
10
7
11
8
from build import BuildBackendException
12
- from build import ProjectBuilder
13
- from build .env import IsolatedEnv as BaseIsolatedEnv
14
9
from poetry .core .utils .helpers import temporary_directory
15
- from pyproject_hooks import quiet_subprocess_runner # type: ignore[import-untyped]
16
10
17
11
from poetry .utils ._compat import decode
18
- from poetry .utils .env import ephemeral_environment
19
12
from poetry .utils .helpers import extractall
13
+ from poetry .utils .pep517_build import PEP517BuildError
14
+ from poetry .utils .pep517_build import pep517_builder
20
15
21
16
22
17
if TYPE_CHECKING :
23
- from collections .abc import Collection
24
-
25
18
from poetry .repositories import RepositoryPool
26
19
from poetry .utils .cache import ArtifactCache
27
20
from poetry .utils .env import Env
30
23
class ChefError (Exception ): ...
31
24
32
25
33
- class ChefBuildError (ChefError ): ...
34
-
35
-
36
- class ChefInstallError (ChefError ):
37
- def __init__ (self , requirements : Collection [str ], output : str , error : str ) -> None :
38
- message = "\n \n " .join (
39
- (
40
- f"Failed to install { ', ' .join (requirements )} ." ,
41
- f"Output:\n { output } " ,
42
- f"Error:\n { error } " ,
43
- )
44
- )
45
- super ().__init__ (message )
46
- self ._requirements = requirements
47
-
48
- @property
49
- def requirements (self ) -> Collection [str ]:
50
- return self ._requirements
51
-
52
-
53
- class IsolatedEnv (BaseIsolatedEnv ):
54
- def __init__ (self , env : Env , pool : RepositoryPool ) -> None :
55
- self ._env = env
56
- self ._pool = pool
57
-
58
- @property
59
- def python_executable (self ) -> str :
60
- return str (self ._env .python )
61
-
62
- def make_extra_environ (self ) -> dict [str , str ]:
63
- path = os .environ .get ("PATH" )
64
- scripts_dir = str (self ._env ._bin_dir )
65
- return {
66
- "PATH" : (
67
- os .pathsep .join ([scripts_dir , path ])
68
- if path is not None
69
- else scripts_dir
70
- )
71
- }
72
-
73
- def install (self , requirements : Collection [str ]) -> None :
74
- from cleo .io .buffered_io import BufferedIO
75
- from poetry .core .packages .dependency import Dependency
76
- from poetry .core .packages .project_package import ProjectPackage
77
-
78
- from poetry .config .config import Config
79
- from poetry .installation .installer import Installer
80
- from poetry .packages .locker import Locker
81
- from poetry .repositories .installed_repository import InstalledRepository
82
-
83
- # We build Poetry dependencies from the requirements
84
- package = ProjectPackage ("__root__" , "0.0.0" )
85
- package .python_versions = "." .join (str (v ) for v in self ._env .version_info [:3 ])
86
- for requirement in requirements :
87
- dependency = Dependency .create_from_pep_508 (requirement )
88
- package .add_dependency (dependency )
89
-
90
- io = BufferedIO ()
91
- installer = Installer (
92
- io ,
93
- self ._env ,
94
- package ,
95
- Locker (self ._env .path .joinpath ("poetry.lock" ), {}),
96
- self ._pool ,
97
- Config .create (),
98
- InstalledRepository .load (self ._env ),
99
- )
100
- installer .update (True )
101
- if installer .run () != 0 :
102
- raise ChefInstallError (requirements , io .fetch_output (), io .fetch_error ())
103
-
104
-
105
26
class Chef :
106
27
def __init__ (
107
28
self , artifact_cache : ArtifactCache , env : Env , pool : RepositoryPool
@@ -127,46 +48,36 @@ def _prepare(
127
48
) -> Path :
128
49
from subprocess import CalledProcessError
129
50
130
- with ephemeral_environment (
131
- self ._env .python ,
132
- flags = {"no-pip" : True , "no-setuptools" : True , "no-wheel" : True },
133
- ) as venv :
134
- env = IsolatedEnv (venv , self ._pool )
135
- builder = ProjectBuilder .from_isolated_env (
136
- env , directory , runner = quiet_subprocess_runner
137
- )
138
- env .install (builder .build_system_requires )
139
-
140
- stdout = StringIO ()
141
- error : Exception | None = None
142
- try :
143
- with redirect_stdout (stdout ):
144
- dist_format = "wheel" if not editable else "editable"
145
- env .install (
146
- builder .build_system_requires
147
- | builder .get_requires_for_build (dist_format )
148
- )
149
- path = Path (
150
- builder .build (
151
- dist_format ,
152
- destination .as_posix (),
153
- )
51
+ distribution = "wheel" if not editable else "editable"
52
+ error : Exception | None = None
53
+
54
+ try :
55
+ with pep517_builder (
56
+ source = directory ,
57
+ distribution = distribution ,
58
+ python_executable = self ._env .python ,
59
+ pool = self ._pool ,
60
+ ) as builder :
61
+ return Path (
62
+ builder .build (
63
+ distribution ,
64
+ destination .as_posix (),
154
65
)
155
- except BuildBackendException as e :
156
- message_parts = [str (e )]
157
- if isinstance (e .exception , CalledProcessError ):
158
- text = e .exception .stderr or e .exception .stdout
159
- if text is not None :
160
- message_parts .append (decode (text ))
161
- else :
162
- message_parts .append (str (e .exception ))
66
+ )
67
+ except BuildBackendException as e :
68
+ message_parts = [str (e )]
163
69
164
- error = ChefBuildError ("\n \n " .join (message_parts ))
70
+ if isinstance (e .exception , CalledProcessError ):
71
+ text = e .exception .stderr or e .exception .stdout
72
+ if text is not None :
73
+ message_parts .append (decode (text ))
74
+ else :
75
+ message_parts .append (str (e .exception ))
165
76
166
- if error is not None :
167
- raise error from None
77
+ error = PEP517BuildError ("\n \n " .join (message_parts ))
168
78
169
- return path
79
+ if error is not None :
80
+ raise error from None
170
81
171
82
def _prepare_sdist (self , archive : Path , destination : Path | None = None ) -> Path :
172
83
from poetry .core .packages .utils .link import Link
0 commit comments