|
1 | 1 | # Copyright 2016-2019 Dirk Thomas |
2 | | -# Copyright 2019 Rover Robotics |
| 2 | +# Copyright 2019 Rover Robotics via Dan Rose |
3 | 3 | # Licensed under the Apache License, Version 2.0 |
4 | 4 |
|
5 | 5 | import multiprocessing |
6 | 6 | import os |
| 7 | +from traceback import format_exc |
7 | 8 | from typing import Optional |
8 | 9 | import warnings |
9 | 10 |
|
|
12 | 13 | from colcon_core.package_identification \ |
13 | 14 | import PackageIdentificationExtensionPoint |
14 | 15 | from colcon_core.plugin_system import satisfies_version |
| 16 | +from colcon_core.run_setup_py import run_setup_py |
15 | 17 | from distlib.util import parse_requirement |
16 | 18 | from distlib.version import NormalizedVersion |
17 | 19 |
|
| 20 | +_process_pool = multiprocessing.Pool() |
| 21 | + |
18 | 22 |
|
19 | 23 | class PythonPackageIdentification(PackageIdentificationExtensionPoint): |
20 | 24 | """Identify Python packages with `setup.py` and opt. `setup.cfg` files.""" |
@@ -104,65 +108,20 @@ def get_setup_result(setup_py, *, env: Optional[dict]): |
104 | 108 | if env is not None: |
105 | 109 | env_copy.update(env) |
106 | 110 |
|
107 | | - conn_recv, conn_send = multiprocessing.Pipe(duplex=False) |
108 | | - with conn_send: |
109 | | - p = multiprocessing.Process( |
110 | | - target=_get_setup_result_target, |
111 | | - args=(os.path.abspath(str(setup_py)), env_copy, conn_send), |
112 | | - ) |
113 | | - p.start() |
114 | | - p.join() |
115 | | - with conn_recv: |
116 | | - result_or_exception_string = conn_recv.recv() |
117 | | - |
118 | | - if isinstance(result_or_exception_string, dict): |
119 | | - return result_or_exception_string |
120 | | - raise RuntimeError( |
121 | | - 'Failure when trying to run setup script {}:\n{}' |
122 | | - .format(setup_py, result_or_exception_string)) |
123 | | - |
124 | | - |
125 | | -def _get_setup_result_target(setup_py: str, env: dict, conn_send): |
126 | | - """ |
127 | | - Run setup.py in a modified environment. |
128 | | -
|
129 | | - Helper function for get_setup_metadata. The resulting dict or error |
130 | | - will be sent via conn_send instead of returned or thrown. |
131 | | -
|
132 | | - :param setup_py: Absolute path to a setup.py script |
133 | | - :param env: Environment variables to set before running setup.py |
134 | | - :param conn_send: Connection to send the result as either a dict or an |
135 | | - error string |
136 | | - """ |
137 | | - import distutils.core |
138 | | - import traceback |
139 | 111 | try: |
140 | | - # need to be in setup.py's parent dir to detect any setup.cfg |
141 | | - os.chdir(os.path.dirname(setup_py)) |
142 | | - |
143 | | - os.environ.clear() |
144 | | - os.environ.update(env) |
145 | | - |
146 | | - result = distutils.core.run_setup( |
147 | | - str(setup_py), ('--dry-run',), stop_after='config') |
148 | | - |
149 | | - # could just return all attrs in result.__dict__, but we take this |
150 | | - # opportunity to filter a few things that don't need to be there |
151 | | - conn_send.send({ |
152 | | - attr: value for attr, value in result.__dict__.items() |
153 | | - if ( |
154 | | - # These *seem* useful but always have the value 0. |
155 | | - # Look for their values in the 'metadata' object instead. |
156 | | - attr not in result.display_option_names |
157 | | - # Getter methods |
158 | | - and not callable(value) |
159 | | - # Private properties |
160 | | - and not attr.startswith('_') |
161 | | - # Objects that are generally not picklable |
162 | | - and attr not in ('cmdclass', 'distclass', 'ext_modules') |
163 | | - )}) |
164 | | - except BaseException: |
165 | | - conn_send.send(traceback.format_exc()) |
| 112 | + return _process_pool.apply( |
| 113 | + run_setup_py, |
| 114 | + kwds={ |
| 115 | + 'cwd': os.path.abspath(str(setup_py.parent)), |
| 116 | + 'env': env_copy, |
| 117 | + 'script_args': ('--dry-run',), |
| 118 | + 'stop_after': 'config' |
| 119 | + } |
| 120 | + ) |
| 121 | + except Exception as e: |
| 122 | + raise RuntimeError( |
| 123 | + 'Failure when trying to run setup script {}: {}' |
| 124 | + .format(setup_py, format_exc())) from e |
166 | 125 |
|
167 | 126 |
|
168 | 127 | def create_dependency_descriptor(requirement_string): |
|
0 commit comments