def install()

in lib/ramble/spack/installer.py [0:0]


    def install(self):
        """
        Install the requested package(s) and or associated dependencies.

        Args:
            pkg (spack.package.Package): the package to be built and installed"""

        self._init_queue()
        fail_fast_err = 'Terminating after first install failure'
        single_explicit_spec = len(self.build_requests) == 1
        failed_explicits = []

        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:
            task = self._pop_task()
            if task is None:
                continue

            spack.hooks.on_install_start(task.request.pkg.spec)
            install_args = task.request.install_args
            keep_prefix = install_args.get('keep_prefix')

            pkg, pkg_id, spec = task.pkg, task.pkg_id, task.pkg.spec
            term_title.next_pkg(pkg)
            term_title.set('Processing {0}'.format(pkg.name))
            tty.debug('Processing {0}: task={1}'.format(pkg_id, task))
            # Ensure that the current spec has NO uninstalled dependencies,
            # which is assumed to be reflected directly in its priority.
            #
            # If the spec has uninstalled dependencies, then there must be
            # a bug in the code (e.g., priority queue or uninstalled
            # dependencies handling).  So terminate under the assumption that
            # 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
                        dep_id not in self.installed]
                if not left:
                    tty.warn('{0} does NOT actually have any uninstalled deps'
                             ' left'.format(pkg_id))
                dep_str = 'dependencies' if task.priority > 1 else 'dependency'

                # Hook to indicate task failure, but without an exception
                spack.hooks.on_install_failure(task.request.pkg.spec)

                raise InstallError(
                    'Cannot proceed with {0}: {1} uninstalled {2}: {3}'
                    .format(pkg_id, task.priority, dep_str,
                            ','.join(task.uninstalled_deps)))

            # Skip the installation if the spec is not being installed locally
            # (i.e., if external or upstream) BUT flag it as installed since
            # 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)

                # Mark that the package failed
                # TODO: this should also be for the task.pkg, but we don't
                # model transitive yet.
                spack.hooks.on_install_failure(task.request.pkg.spec)

                if self.fail_fast:
                    raise InstallError(fail_fast_err)

                continue

            # Attempt to get a write lock.  If we can't get the lock then
            # another process is likely (un)installing the spec or has
            # 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
                # another process has a write lock so must be (un)installing
                # the spec (or that process is hung).
                ltype, lock = self._ensure_locked('read', pkg)

            # Requeue the spec if we cannot get at least a read lock so we
            # can check the status presumably established by another process
            # -- failed, installed, or uninstalled -- on the next pass.
            if lock is None:
                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:
                task.request.overwrite_time = time.time()

            # Determine state of installation artifacts and adjust accordingly.
            term_title.set('Preparing {0}'.format(pkg.name))
            self._prepare_for_install(task)

            # Flag an already installed package
            if pkg_id in self.installed:
                # Downgrade to a read lock to preclude other processes from
                # uninstalling the package until we're done installing its
                # dependents.
                ltype, lock = self._ensure_locked('read', pkg)
                if lock is not None:
                    self._update_installed(task)
                    _print_installed_pkg(pkg.prefix)

                    # It's an already installed compiler, add it to the config
                    if task.compiler:
                        spack.compilers.add_compilers_to_config(
                            spack.compilers.find_compilers([pkg.spec.prefix]))

                else:
                    # At this point we've failed to get a write or a read
                    # lock, which means another process has taken a write
                    # lock between our releasing the write and acquiring the
                    # read.
                    #
                    # Requeue the task so we can re-check the status
                    # established by the other process -- failed, installed,
                    # or uninstalled -- on the next pass.
                    self.installed.remove(pkg_id)
                    self._requeue_task(task)
                continue

            # Having a read lock on an uninstalled pkg may mean another
            # process completed an uninstall of the software between the
            # time we failed to acquire the write lock and the time we
            # took the read lock.
            #
            # Requeue the task so we can check the status presumably
            # established by the other process -- failed, installed, or
            # uninstalled -- on the next pass.
            if ltype == 'read':
                lock.release_read()
                self._requeue_task(task)
                continue

            # Proceed with the installation since we have an exclusive write
            # lock on the package.
            term_title.set('Installing {0}'.format(pkg.name))
            try:
                action = self._install_action(task)

                if action == InstallAction.INSTALL:
                    self._install_task(task)
                elif action == InstallAction.OVERWRITE:
                    OverwriteInstall(self, spack.store.db, task).install()

                self._update_installed(task)

                # If we installed then we should keep the prefix
                stop_before_phase = getattr(pkg, 'stop_before_phase', None)
                last_phase = getattr(pkg, 'last_phase', None)
                keep_prefix = keep_prefix or \
                    (stop_before_phase is None and last_phase is None)

            except KeyboardInterrupt as exc:
                # The build has been terminated with a Ctrl-C so terminate
                # regardless of the number of remaining specs.
                err = 'Failed to install {0} due to {1}: {2}'
                tty.error(err.format(pkg.name, exc.__class__.__name__,
                          str(exc)))
                spack.hooks.on_install_cancel(task.request.pkg.spec)
                raise

            except (Exception, SystemExit) as exc:
                self._update_failed(task, True, exc)
                spack.hooks.on_install_failure(task.request.pkg.spec)

                # Best effort installs suppress the exception and mark the
                # package as a failure.
                if (not isinstance(exc, spack.error.SpackError) or
                    not exc.printed):
                    exc.printed = True
                    # SpackErrors can be printed by the build process or at
                    # lower levels -- skip printing if already printed.
                    # TODO: sort out this and SpackError.print_context()
                    tty.error('Failed to install {0} due to {1}: {2}'
                              .format(pkg.name, exc.__class__.__name__,
                                      str(exc)))
                # Terminate if requested to do so on the first failure.
                if self.fail_fast:
                    raise InstallError('{0}: {1}'
                                       .format(fail_fast_err, str(exc)))

                # Terminate at this point if the single explicit spec has
                # failed to install.
                if single_explicit_spec and task.explicit:
                    raise

                # Track explicit spec id and error to summarize when done
                if task.explicit:
                    failed_explicits.append((pkg_id, str(exc)))

            finally:
                # Remove the install prefix if anything went wrong during
                # install.
                if not keep_prefix and not action == InstallAction.OVERWRITE:
                    pkg.remove_prefix()

                # The subprocess *may* have removed the build stage. Mark it
                # not created so that the next time pkg.stage is invoked, we
                # check the filesystem for it.
                pkg.stage.created = False

            # Perform basic task cleanup for the installed spec to
            # include downgrading the write to a read lock
            self._cleanup_task(pkg)

        # Cleanup, which includes releasing all of the read locks
        self._cleanup_all_tasks()

        # Ensure we properly report if one or more explicit specs failed
        # or were not installed when should have been.
        missing = [request.pkg_id for request in self.build_requests if
                   request.install_args.get('install_package') and
                   request.pkg_id not in self.installed]
        if failed_explicits or missing:
            for pkg_id, err in failed_explicits:
                tty.error('{0}: {1}'.format(pkg_id, err))

            for pkg_id in missing:
                tty.error('{0}: Package was not installed'.format(pkg_id))

            raise InstallError('Installation request failed.  Refer to '
                               'reported errors for failing package(s).')