Print 'Waiting for another process to install x, y, z' in distributed builds (#28535)

Co-authored-by: Massimiliano Culpo <massimiliano.culpo@gmail.com>
This commit is contained in:
Harmen Stoppels 2022-01-26 10:42:08 +01:00 committed by GitHub
parent 5300cbbb2e
commit e3d62b2f7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -648,6 +648,49 @@ def set(self, text):
sys.stdout.flush()
class TermStatusLine(object):
"""
This class is used in distributed builds to inform the user that other packages are
being installed by another process.
"""
def __init__(self, enabled):
self.enabled = enabled
self.pkg_set = set()
self.pkg_list = []
def add(self, pkg_id):
"""
Add a package to the waiting list, and if it is new, update the status line.
"""
if not self.enabled or pkg_id in self.pkg_set:
return
self.pkg_set.add(pkg_id)
self.pkg_list.append(pkg_id)
tty.msg(colorize('@*{Waiting for} @*g{%s}' % pkg_id))
sys.stdout.flush()
def clear(self):
"""
Clear the status line.
"""
if not self.enabled:
return
lines = len(self.pkg_list)
if lines == 0:
return
self.pkg_set.clear()
self.pkg_list.clear()
# Move the cursor to the beginning of the first "Waiting for" message and clear
# everything after it.
sys.stdout.write('\x1b[%sF\x1b[J' % lines)
sys.stdout.flush()
class PackageInstaller(object):
'''
Class for managing the install process for a Spack instance based on a
@ -1500,6 +1543,10 @@ def install(self):
term_title = TermTitle(len(self.build_pq))
# Only enable the terminal status line when we're in a tty without debug info
# enabled, so that the output does not get cluttered.
term_status = TermStatusLine(enabled=sys.stdout.isatty() and not tty.is_debug())
while self.build_pq:
term_title.next_pkg()
@ -1523,6 +1570,7 @@ def install(self):
# all subsequent tasks will have non-zero priorities or may be
# dependencies of this task.
if task.priority != 0:
term_status.clear()
tty.error('Detected uninstalled dependencies for {0}: {1}'
.format(pkg_id, task.uninstalled_deps))
left = [dep_id for dep_id in task.uninstalled_deps if
@ -1545,12 +1593,14 @@ def install(self):
# some package likely depends on it.
if not task.explicit:
if _handle_external_and_upstream(pkg, False):
term_status.clear()
self._flag_installed(pkg, task.dependents)
continue
# Flag a failed spec. Do not need an (install) prefix lock since
# assume using a separate (failed) prefix lock file.
if pkg_id in self.failed or spack.store.db.prefix_failed(spec):
term_status.clear()
tty.warn('{0} failed to install'.format(pkg_id))
self._update_failed(task)
@ -1569,6 +1619,7 @@ def install(self):
# determined the spec has already been installed (though the
# other process may be hung).
term_title.set('Acquiring lock for {0}'.format(pkg.name))
term_status.add(pkg_id)
ltype, lock = self._ensure_locked('write', pkg)
if lock is None:
# Attempt to get a read lock instead. If this fails then
@ -1583,6 +1634,8 @@ def install(self):
self._requeue_task(task)
continue
term_status.clear()
# Take a timestamp with the overwrite argument to allow checking
# whether another process has already overridden the package.
if task.request.overwrite and task.explicit: