Better docs and typing for _setup_pkg_and_run
(#46709)
There was a bit of mystery surrounding the arguments for `_setup_pkg_and_run`. It passes two file descriptors for handling the `gmake`'s job server in child processes, but they are unsed in the method. It turns out that there are good reasons to do this -- depending on the multiprocessing backend, these file descriptors may be closed in the child if they're not passed directly to it. - [x] Document all args to `_setup_pkg_and_run`. - [x] Document all arguments to `_setup_pkg_and_run`. - [x] Add type hints for `_setup_pkg_and_run`. - [x] Refactor exception handling in `_setup_pkg_and_run` so it's easier to add type hints. `exc_info()` was problematic because it *can* return `None` (just not in the context where it's used). `mypy` was too dumb to notice this. Signed-off-by: Todd Gamblin <tgamblin@llnl.gov>
This commit is contained in:
parent
a52ec2a9cc
commit
3c2a682876
@ -44,7 +44,7 @@
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from enum import Flag, auto
|
from enum import Flag, auto
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
from typing import Dict, List, Optional, Set, Tuple
|
from typing import Callable, Dict, List, Optional, Set, Tuple
|
||||||
|
|
||||||
import archspec.cpu
|
import archspec.cpu
|
||||||
|
|
||||||
@ -1168,8 +1168,51 @@ def get_cmake_prefix_path(pkg):
|
|||||||
|
|
||||||
|
|
||||||
def _setup_pkg_and_run(
|
def _setup_pkg_and_run(
|
||||||
serialized_pkg, function, kwargs, write_pipe, input_multiprocess_fd, jsfd1, jsfd2
|
serialized_pkg: "spack.subprocess_context.PackageInstallContext",
|
||||||
|
function: Callable,
|
||||||
|
kwargs: Dict,
|
||||||
|
write_pipe: multiprocessing.connection.Connection,
|
||||||
|
input_multiprocess_fd: Optional[MultiProcessFd],
|
||||||
|
jsfd1: Optional[MultiProcessFd],
|
||||||
|
jsfd2: Optional[MultiProcessFd],
|
||||||
):
|
):
|
||||||
|
"""Main entry point in the child process for Spack builds.
|
||||||
|
|
||||||
|
``_setup_pkg_and_run`` is called by the child process created in
|
||||||
|
``start_build_process()``, and its main job is to run ``function()`` on behalf of
|
||||||
|
some Spack installation (see :ref:`spack.installer.PackageInstaller._install_task`).
|
||||||
|
|
||||||
|
The child process is passed a ``write_pipe``, on which it's expected to send one of
|
||||||
|
the following:
|
||||||
|
|
||||||
|
* ``StopPhase``: error raised by a build process indicating it's stopping at a
|
||||||
|
particular build phase.
|
||||||
|
|
||||||
|
* ``BaseException``: any exception raised by a child build process, which will be
|
||||||
|
wrapped in ``ChildError`` (which adds a bunch of debug info and log context) and
|
||||||
|
raised in the parent.
|
||||||
|
|
||||||
|
* The return value of ``function()``, which can be anything (except an exception).
|
||||||
|
This is returned to the caller.
|
||||||
|
|
||||||
|
Note: ``jsfd1`` and ``jsfd2`` are passed solely to ensure that the child process
|
||||||
|
does not close these file descriptors. Some ``multiprocessing`` backends will close
|
||||||
|
them automatically in the child if they are not passed at process creation time.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
serialized_pkg: Spack package install context object (serialized form of the
|
||||||
|
package that we'll build in the child process).
|
||||||
|
function: function to call in the child process; serialized_pkg is passed to
|
||||||
|
this as the first argument.
|
||||||
|
kwargs: additional keyword arguments to pass to ``function()``.
|
||||||
|
write_pipe: multiprocessing ``Connection`` to the parent process, to which the
|
||||||
|
child *must* send a result (or an error) back to parent on.
|
||||||
|
input_multiprocess_fd: stdin from the parent (not passed currently on Windows)
|
||||||
|
jsfd1: gmake Jobserver file descriptor 1.
|
||||||
|
jsfd2: gmake Jobserver file descriptor 2.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
context: str = kwargs.get("context", "build")
|
context: str = kwargs.get("context", "build")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -1195,13 +1238,14 @@ def _setup_pkg_and_run(
|
|||||||
# Do not create a full ChildError from this, it's not an error
|
# Do not create a full ChildError from this, it's not an error
|
||||||
# it's a control statement.
|
# it's a control statement.
|
||||||
write_pipe.send(e)
|
write_pipe.send(e)
|
||||||
except BaseException:
|
except BaseException as e:
|
||||||
# catch ANYTHING that goes wrong in the child process
|
# catch ANYTHING that goes wrong in the child process
|
||||||
exc_type, exc, tb = sys.exc_info()
|
|
||||||
|
|
||||||
# Need to unwind the traceback in the child because traceback
|
# Need to unwind the traceback in the child because traceback
|
||||||
# objects can't be sent to the parent.
|
# objects can't be sent to the parent.
|
||||||
tb_string = traceback.format_exc()
|
exc_type = type(e)
|
||||||
|
tb = e.__traceback__
|
||||||
|
tb_string = traceback.format_exception(exc_type, e, tb)
|
||||||
|
|
||||||
# build up some context from the offending package so we can
|
# build up some context from the offending package so we can
|
||||||
# show that, too.
|
# show that, too.
|
||||||
@ -1218,8 +1262,8 @@ def _setup_pkg_and_run(
|
|||||||
elif context == "test":
|
elif context == "test":
|
||||||
logfile = os.path.join(pkg.test_suite.stage, pkg.test_suite.test_log_name(pkg.spec))
|
logfile = os.path.join(pkg.test_suite.stage, pkg.test_suite.test_log_name(pkg.spec))
|
||||||
|
|
||||||
error_msg = str(exc)
|
error_msg = str(e)
|
||||||
if isinstance(exc, (spack.multimethod.NoSuchMethodError, AttributeError)):
|
if isinstance(e, (spack.multimethod.NoSuchMethodError, AttributeError)):
|
||||||
process = "test the installation" if context == "test" else "build from sources"
|
process = "test the installation" if context == "test" else "build from sources"
|
||||||
error_msg = (
|
error_msg = (
|
||||||
"The '{}' package cannot find an attribute while trying to {}. "
|
"The '{}' package cannot find an attribute while trying to {}. "
|
||||||
@ -1229,7 +1273,7 @@ def _setup_pkg_and_run(
|
|||||||
"More information at https://spack.readthedocs.io/en/latest/packaging_guide.html#installation-procedure"
|
"More information at https://spack.readthedocs.io/en/latest/packaging_guide.html#installation-procedure"
|
||||||
).format(pkg.name, process, context)
|
).format(pkg.name, process, context)
|
||||||
error_msg = colorize("@*R{{{}}}".format(error_msg))
|
error_msg = colorize("@*R{{{}}}".format(error_msg))
|
||||||
error_msg = "{}\n\n{}".format(str(exc), error_msg)
|
error_msg = "{}\n\n{}".format(str(e), error_msg)
|
||||||
|
|
||||||
# make a pickleable exception to send to parent.
|
# make a pickleable exception to send to parent.
|
||||||
msg = "%s: %s" % (exc_type.__name__, error_msg)
|
msg = "%s: %s" % (exc_type.__name__, error_msg)
|
||||||
|
Loading…
Reference in New Issue
Block a user