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:
parent
5300cbbb2e
commit
e3d62b2f7b
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user