11import os
22import platform
33import re
4- import shlex
54import shutil
65import subprocess
76import sys
87import tempfile
98from pathlib import Path
10- from typing import Any , Dict , List , NamedTuple , Optional , Sequence , Set , Tuple , cast
9+ from typing import Any , Dict , List , NamedTuple , Sequence , Set , Tuple , cast
1110
1211from .architecture import Architecture
1312from .environment import ParsedEnvironment
1817 BuildFrontend ,
1918 BuildSelector ,
2019 NonPlatformWheelError ,
20+ call ,
2121 download ,
2222 get_build_verbosity_extra_flags ,
2323 get_pip_version ,
2424 install_certifi_script ,
2525 prepare_command ,
2626 read_python_configs ,
27+ shell ,
2728 unwrap ,
2829)
2930
3031
31- def call (
32- args : Sequence [PathOrStr ],
33- env : Optional [Dict [str , str ]] = None ,
34- cwd : Optional [str ] = None ,
35- shell : bool = False ,
36- ) -> None :
37- # print the command executing for the logs
38- if shell :
39- print (f"+ { args } " )
40- else :
41- print ("+ " + " " .join (shlex .quote (str (a )) for a in args ))
42-
43- subprocess .run (args , env = env , cwd = cwd , shell = shell , check = True )
44-
45-
4632def get_macos_version () -> Tuple [int , int ]:
4733 """
4834 Returns the macOS major/minor version, as a tuple, e.g. (10, 15) or (11, 0)
@@ -58,13 +44,7 @@ def get_macos_version() -> Tuple[int, int]:
5844
5945
6046def get_macos_sdks () -> List [str ]:
61- output = subprocess .run (
62- ["xcodebuild" , "-showsdks" ],
63- universal_newlines = True ,
64- check = True ,
65- stdout = subprocess .PIPE ,
66- ).stdout
67-
47+ output = call ("xcodebuild" , "-showsdks" , capture_stdout = True )
6848 return [m .group (1 ) for m in re .finditer (r"-sdk (macosx\S+)" , output )]
6949
7050
@@ -114,9 +94,7 @@ def make_symlinks(installation_bin_path: Path, python_executable: str, pip_execu
11494
11595
11696def install_cpython (version : str , url : str ) -> Path :
117- installed_system_packages = subprocess .run (
118- ["pkgutil" , "--pkgs" ], universal_newlines = True , check = True , stdout = subprocess .PIPE
119- ).stdout .splitlines ()
97+ installed_system_packages = call ("pkgutil" , "--pkgs" , capture_stdout = True ).splitlines ()
12098
12199 # if this version of python isn't installed, get it from python.org and install
122100 python_package_identifier = f"org.python.Python.PythonFramework-{ version } "
@@ -127,10 +105,10 @@ def install_cpython(version: str, url: str) -> Path:
127105 # download the pkg
128106 download (url , Path ("/tmp/Python.pkg" ))
129107 # install
130- call ([ "sudo" , "installer" , "-pkg" , "/tmp/Python.pkg" , "-target" , "/" ] )
108+ call ("sudo" , "installer" , "-pkg" , "/tmp/Python.pkg" , "-target" , "/" )
131109 env = os .environ .copy ()
132110 env ["PIP_DISABLE_PIP_VERSION_CHECK" ] = "1"
133- call ([ str (installation_bin_path / python_executable ), str (install_certifi_script )] , env = env )
111+ call (str (installation_bin_path / python_executable ), str (install_certifi_script ), env = env )
134112
135113 pip_executable = "pip3"
136114 make_symlinks (installation_bin_path , python_executable , pip_executable )
@@ -147,7 +125,7 @@ def install_pypy(version: str, url: str) -> Path:
147125 if not installation_path .exists ():
148126 downloaded_tar_bz2 = Path ("/tmp" ) / pypy_tar_bz2
149127 download (url , downloaded_tar_bz2 )
150- call ([ "tar" , "-C" , "/tmp" , "-xf" , downloaded_tar_bz2 ] )
128+ call ("tar" , "-C" , "/tmp" , "-xf" , downloaded_tar_bz2 )
151129
152130 installation_bin_path = installation_path / "bin"
153131 python_executable = "pypy3"
@@ -203,20 +181,18 @@ def setup_python(
203181 requires_reinstall = not (installation_bin_path / "pip" ).exists ()
204182 if requires_reinstall :
205183 # maybe pip isn't installed at all. ensurepip resolves that.
206- call ([ "python" , "-m" , "ensurepip" ] , env = env , cwd = "/tmp" )
184+ call ("python" , "-m" , "ensurepip" , env = env , cwd = "/tmp" )
207185
208186 # upgrade pip to the version matching our constraints
209187 # if necessary, reinstall it to ensure that it's available on PATH as 'pip'
210188 call (
211- [
212- "python" ,
213- "-m" ,
214- "pip" ,
215- "install" ,
216- "--force-reinstall" if requires_reinstall else "--upgrade" ,
217- "pip" ,
218- * dependency_constraint_flags ,
219- ],
189+ "python" ,
190+ "-m" ,
191+ "pip" ,
192+ "install" ,
193+ "--force-reinstall" if requires_reinstall else "--upgrade" ,
194+ "pip" ,
195+ * dependency_constraint_flags ,
220196 env = env ,
221197 cwd = "/tmp" ,
222198 )
@@ -226,11 +202,9 @@ def setup_python(
226202
227203 # check what pip version we're on
228204 assert (installation_bin_path / "pip" ).exists ()
229- call (["which" , "pip" ], env = env )
230- call (["pip" , "--version" ], env = env )
231- which_pip = subprocess .run (
232- ["which" , "pip" ], env = env , universal_newlines = True , check = True , stdout = subprocess .PIPE
233- ).stdout .strip ()
205+ call ("which" , "pip" , env = env )
206+ call ("pip" , "--version" , env = env )
207+ which_pip = call ("which" , "pip" , env = env , capture_stdout = True ).strip ()
234208 if which_pip != "/tmp/cibw_bin/pip" :
235209 print (
236210 "cibuildwheel: pip available on PATH doesn't match our installed instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert pip above it." ,
@@ -239,11 +213,9 @@ def setup_python(
239213 sys .exit (1 )
240214
241215 # check what Python version we're on
242- call (["which" , "python" ], env = env )
243- call (["python" , "--version" ], env = env )
244- which_python = subprocess .run (
245- ["which" , "python" ], env = env , universal_newlines = True , check = True , stdout = subprocess .PIPE
246- ).stdout .strip ()
216+ call ("which" , "python" , env = env )
217+ call ("python" , "--version" , env = env )
218+ which_python = call ("which" , "python" , env = env , capture_stdout = True ).strip ()
247219 if which_python != "/tmp/cibw_bin/python" :
248220 print (
249221 "cibuildwheel: python available on PATH doesn't match our installed instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert python above it." ,
@@ -298,27 +270,23 @@ def setup_python(
298270 log .step ("Installing build tools..." )
299271 if build_frontend == "pip" :
300272 call (
301- [
302- "pip" ,
303- "install" ,
304- "--upgrade" ,
305- "setuptools" ,
306- "wheel" ,
307- "delocate" ,
308- * dependency_constraint_flags ,
309- ],
273+ "pip" ,
274+ "install" ,
275+ "--upgrade" ,
276+ "setuptools" ,
277+ "wheel" ,
278+ "delocate" ,
279+ * dependency_constraint_flags ,
310280 env = env ,
311281 )
312282 elif build_frontend == "build" :
313283 call (
314- [
315- "pip" ,
316- "install" ,
317- "--upgrade" ,
318- "delocate" ,
319- "build[virtualenv]" ,
320- * dependency_constraint_flags ,
321- ],
284+ "pip" ,
285+ "install" ,
286+ "--upgrade" ,
287+ "delocate" ,
288+ "build[virtualenv]" ,
289+ * dependency_constraint_flags ,
322290 env = env ,
323291 )
324292 else :
@@ -347,7 +315,7 @@ def build(options: Options) -> None:
347315 before_all_prepared = prepare_command (
348316 before_all_options .before_all , project = "." , package = before_all_options .package_dir
349317 )
350- call ([ before_all_prepared ], shell = True , env = env )
318+ shell ( before_all_prepared , env = env )
351319
352320 for config in python_configurations :
353321 build_options = options .build_options (config .identifier )
@@ -375,7 +343,7 @@ def build(options: Options) -> None:
375343 before_build_prepared = prepare_command (
376344 build_options .before_build , project = "." , package = build_options .package_dir
377345 )
378- call (before_build_prepared , env = env , shell = True )
346+ shell (before_build_prepared , env = env )
379347
380348 log .step ("Building wheel..." )
381349 if built_wheel_dir .exists ():
@@ -388,16 +356,14 @@ def build(options: Options) -> None:
388356 # Path.resolve() is needed. Without it pip wheel may try to fetch package from pypi.org
389357 # see https://github.com/pypa/cibuildwheel/pull/369
390358 call (
391- [
392- "python" ,
393- "-m" ,
394- "pip" ,
395- "wheel" ,
396- build_options .package_dir .resolve (),
397- f"--wheel-dir={ built_wheel_dir } " ,
398- "--no-deps" ,
399- * verbosity_flags ,
400- ],
359+ "python" ,
360+ "-m" ,
361+ "pip" ,
362+ "wheel" ,
363+ build_options .package_dir .resolve (),
364+ f"--wheel-dir={ built_wheel_dir } " ,
365+ "--no-deps" ,
366+ * verbosity_flags ,
401367 env = env ,
402368 )
403369 elif build_options .build_frontend == "build" :
@@ -410,15 +376,13 @@ def build(options: Options) -> None:
410376 build_env ["PIP_CONSTRAINT" ] = constraint_path .as_uri ()
411377 build_env ["VIRTUALENV_PIP" ] = get_pip_version (env )
412378 call (
413- [
414- "python" ,
415- "-m" ,
416- "build" ,
417- build_options .package_dir ,
418- "--wheel" ,
419- f"--outdir={ built_wheel_dir } " ,
420- f"--config-setting={ config_setting } " ,
421- ],
379+ "python" ,
380+ "-m" ,
381+ "build" ,
382+ build_options .package_dir ,
383+ "--wheel" ,
384+ f"--outdir={ built_wheel_dir } " ,
385+ f"--config-setting={ config_setting } " ,
422386 env = build_env ,
423387 )
424388 else :
@@ -449,7 +413,7 @@ def build(options: Options) -> None:
449413 dest_dir = repaired_wheel_dir ,
450414 delocate_archs = delocate_archs ,
451415 )
452- call (repair_command_prepared , env = env , shell = True )
416+ shell (repair_command_prepared , env = env )
453417 else :
454418 shutil .move (str (built_wheel ), repaired_wheel_dir )
455419
@@ -514,7 +478,7 @@ def build(options: Options) -> None:
514478
515479 # set up a virtual environment to install and test from, to make sure
516480 # there are no dependencies that were pulled in at build time.
517- call ([ "pip" , "install" , "virtualenv" , * dependency_constraint_flags ] , env = env )
481+ call ("pip" , "install" , "virtualenv" , * dependency_constraint_flags , env = env )
518482 venv_dir = Path (tempfile .mkdtemp ())
519483
520484 arch_prefix = []
@@ -528,18 +492,16 @@ def build(options: Options) -> None:
528492 )
529493
530494 # define a custom 'call' function that adds the arch prefix each time
531- def call_with_arch (args : Sequence [ PathOrStr ] , ** kwargs : Any ) -> None :
532- if isinstance ( args , str ):
533- args = " " . join ( arch_prefix ) + " " + args
534- else :
535- args = [ * arch_prefix , * args ]
536- call ( args , ** kwargs )
495+ def call_with_arch (* args : PathOrStr , ** kwargs : Any ) -> None :
496+ call ( * arch_prefix , * args , ** kwargs )
497+
498+ def shell_with_arch ( command : str , ** kwargs : Any ) -> None :
499+ command = " " . join ( arch_prefix ) + " " + command
500+ shell ( command , ** kwargs )
537501
538502 # Use --no-download to ensure determinism by using seed libraries
539503 # built into virtualenv
540- call_with_arch (
541- ["python" , "-m" , "virtualenv" , "--no-download" , venv_dir ], env = env
542- )
504+ call_with_arch ("python" , "-m" , "virtualenv" , "--no-download" , venv_dir , env = env )
543505
544506 virtualenv_env = env .copy ()
545507 virtualenv_env ["PATH" ] = os .pathsep .join (
@@ -550,26 +512,28 @@ def call_with_arch(args: Sequence[PathOrStr], **kwargs: Any) -> None:
550512 )
551513
552514 # check that we are using the Python from the virtual environment
553- call_with_arch ([ "which" , "python" ] , env = virtualenv_env )
515+ call_with_arch ("which" , "python" , env = virtualenv_env )
554516
555517 if build_options .before_test :
556518 before_test_prepared = prepare_command (
557519 build_options .before_test ,
558520 project = "." ,
559521 package = build_options .package_dir ,
560522 )
561- call_with_arch (before_test_prepared , env = virtualenv_env , shell = True )
523+ shell_with_arch (before_test_prepared , env = virtualenv_env )
562524
563525 # install the wheel
564526 call_with_arch (
565- ["pip" , "install" , f"{ repaired_wheel } { build_options .test_extras } " ],
527+ "pip" ,
528+ "install" ,
529+ f"{ repaired_wheel } { build_options .test_extras } " ,
566530 env = virtualenv_env ,
567531 )
568532
569533 # test the wheel
570534 if build_options .test_requires :
571535 call_with_arch (
572- [ "pip" , "install" ] + build_options .test_requires , env = virtualenv_env
536+ "pip" , "install" , * build_options .test_requires , env = virtualenv_env
573537 )
574538
575539 # run the tests from $HOME, with an absolute path in the command
@@ -580,11 +544,8 @@ def call_with_arch(args: Sequence[PathOrStr], **kwargs: Any) -> None:
580544 project = Path ("." ).resolve (),
581545 package = build_options .package_dir .resolve (),
582546 )
583- call_with_arch (
584- test_command_prepared ,
585- cwd = os .environ ["HOME" ],
586- env = virtualenv_env ,
587- shell = True ,
547+ shell_with_arch (
548+ test_command_prepared , cwd = os .environ ["HOME" ], env = virtualenv_env
588549 )
589550
590551 # clean up
0 commit comments