11# Copyright 2016-2018 Dirk Thomas
22# Licensed under the Apache License, Version 2.0
33
4- import asyncio
54from distutils .sysconfig import get_python_lib
65import os
76from pathlib import Path
8- import re
97import shutil
108import sys
119from sys import executable
2321
2422logger = colcon_logger .getChild (__name__ )
2523
26- _easy_install_pth_lock = None
27-
28-
29- class _EasyInstallPthLockAsyncContext :
30- """
31- A context manager to access the easy-install.pth file exclusively.
32-
33- The locking is only necessary when using --merge-install.
34- """
35-
36- def __init__ (self , pkg , args ):
37- self ._pkg_name = pkg .name
38- self ._merge_install = args .merge_install
39-
40- async def __aenter__ (self ):
41- global _easy_install_pth_lock
42- # since the command modifies the easy-install.pth file
43- # the invocation for multiple Python packages needs to happen
44- # sequentially when using --merge-install
45- if self ._merge_install and _easy_install_pth_lock is None :
46- try :
47- # only available as of Python 3.7
48- loop = asyncio .get_running_loop ()
49- except AttributeError :
50- loop = asyncio .get_event_loop ()
51- _easy_install_pth_lock = asyncio .Lock (loop = loop )
52-
53- if _easy_install_pth_lock :
54- logger .debug (
55- "Acquiring lock for package '{self._pkg_name}' to access "
56- 'easy_install.pth' .format_map (locals ()))
57- await _easy_install_pth_lock .acquire ()
58- logger .debug (
59- "Acquired lock for package '{self._pkg_name}' to access "
60- 'easy_install.pth' .format_map (locals ()))
61-
62- async def __aexit__ (self , * _ ):
63- global _easy_install_pth_lock
64- if _easy_install_pth_lock :
65- logger .debug (
66- "Releasing lock for package '{self._pkg_name}' to access "
67- 'easy_install.pth' .format_map (locals ()))
68- _easy_install_pth_lock .release ()
69-
7024
7125class PythonBuildTask (TaskExtensionPoint ):
7226 """Build Python packages."""
@@ -133,25 +87,26 @@ async def build(self, *, additional_hooks=None): # noqa: D102
13387
13488 # invoke `setup.py develop` step in build space
13589 # to avoid placing any files in the source space
90+
91+ # --editable causes this to skip creating/editing the
92+ # easy-install.pth file
13693 cmd = [
13794 executable , 'setup.py' ,
13895 'develop' , '--prefix' , args .install_base ,
96+ '--editable' ,
97+ '--build-directory' , os .path .join (args .build_base , 'build' ),
13998 '--no-deps' ,
14099 ]
141100 if setup_py_data .get ('data_files' , []):
142101 cmd += ['install_data' , '--install-dir' , args .install_base ]
143102 self ._append_install_layout (args , cmd )
144- async with _EasyInstallPthLockAsyncContext (pkg , args ):
145- rc = await check_call (
146- self .context , cmd , cwd = args .build_base , env = env )
103+ rc = await check_call (
104+ self .context , cmd , cwd = args .build_base , env = env )
147105 if rc and rc .returncode :
148106 return rc .returncode
149107
150108 # explicitly add the build directory to the PYTHONPATH
151109 # to maintain the desired order
152- # otherwise the path from the easy-install.pth (which is the build
153- # directory) will be added to the PYTHONPATH implicitly
154- # but behind potentially other directories from the PYTHONPATH
155110 if additional_hooks is None :
156111 additional_hooks = []
157112 additional_hooks += create_environment_hook (
@@ -171,11 +126,11 @@ async def _undo_develop(self, pkg, args, env):
171126 cmd = [
172127 executable , 'setup.py' ,
173128 'develop' , '--prefix' , args .install_base ,
174- '--uninstall' ,
129+ '--uninstall' , '--editable' ,
130+ '--build-directory' , os .path .join (args .build_base , 'build' )
175131 ]
176- async with _EasyInstallPthLockAsyncContext (pkg , args ):
177- rc = await check_call (
178- self .context , cmd , cwd = args .build_base , env = env )
132+ rc = await check_call (
133+ self .context , cmd , cwd = args .build_base , env = env )
179134 if rc :
180135 return rc
181136
@@ -224,26 +179,6 @@ def _undo_install(self, pkg, args, setup_py_data, python_lib):
224179 pass
225180 os .remove (install_log )
226181
227- # remove entry from easy-install.pth file
228- easy_install = os .path .join (
229- args .install_base , self ._get_python_lib (args ),
230- 'easy-install.pth' )
231- if not os .path .exists (easy_install ):
232- return
233-
234- with open (easy_install , 'r' ) as h :
235- content = h .read ()
236- pattern = r'^\./%s-\d.+\.egg\n' % re .escape (pkg .name )
237- matches = re .findall (pattern , content , re .MULTILINE )
238- if not matches :
239- return
240-
241- assert len (matches ) == 1 , \
242- "Multiple matching entries in '%s'" % easy_install
243- content = content .replace (matches [0 ], '' )
244- with open (easy_install , 'w' ) as h :
245- h .write (content )
246-
247182 def _symlinks_in_build (self , args , setup_py_data ):
248183 items = ['setup.py' ]
249184 # add setup.cfg if available
0 commit comments