From abc9412f23dd3b131fc1126b8fd03ca49f6fd56d Mon Sep 17 00:00:00 2001
From: Elizabeth Fischer <rpf2116@columbia.edu>
Date: Wed, 5 Oct 2016 14:23:06 -0400
Subject: [PATCH] New command flag: spack install --dependencies-only (#1603)

* 1. Renamed ignore_deps variable to install_deps (use positive logic).  UI remains the same.

2. install_self kwarg added to do_install().  Enables installation of a package's dependencies without installing the package itself.

3. Added `spack install --dependencies-only <package>` command.

* Flak8 fixes

* Indentation problem
---
 lib/spack/spack/cmd/diy.py          |  2 +-
 lib/spack/spack/cmd/install.py      |  8 ++++-
 lib/spack/spack/cmd/setup.py        |  3 +-
 lib/spack/spack/cmd/test_install.py |  3 +-
 lib/spack/spack/package.py          | 47 +++++++++++++++++------------
 5 files changed, 40 insertions(+), 23 deletions(-)

diff --git a/lib/spack/spack/cmd/diy.py b/lib/spack/spack/cmd/diy.py
index 9833e8cdce..d60fd6bc7a 100644
--- a/lib/spack/spack/cmd/diy.py
+++ b/lib/spack/spack/cmd/diy.py
@@ -101,7 +101,7 @@ def diy(self, args):
 
         package.do_install(
             keep_prefix=args.keep_prefix,
-            ignore_deps=args.ignore_deps,
+            install_deps=not args.ignore_deps,
             verbose=not args.quiet,
             keep_stage=True,   # don't remove source dir for DIY.
             dirty=args.dirty)
diff --git a/lib/spack/spack/cmd/install.py b/lib/spack/spack/cmd/install.py
index 7663a97a28..e51024b05f 100644
--- a/lib/spack/spack/cmd/install.py
+++ b/lib/spack/spack/cmd/install.py
@@ -22,6 +22,7 @@
 # License along with this program; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 ##############################################################################
+from __future__ import print_function
 import argparse
 
 import llnl.util.tty as tty
@@ -36,6 +37,10 @@ def setup_parser(subparser):
     subparser.add_argument(
         '-i', '--ignore-dependencies', action='store_true', dest='ignore_deps',
         help="Do not try to install dependencies of requested packages.")
+    subparser.add_argument(
+        '-d', '--dependencies-only', action='store_true', dest='deps_only',
+        help='Install dependencies of this package, ' +
+        'but not the package itself.')
     subparser.add_argument(
         '-j', '--jobs', action='store', type=int,
         help="Explicitly set number of make jobs.  Default is #cpus.")
@@ -83,7 +88,8 @@ def install(parser, args):
             package.do_install(
                 keep_prefix=args.keep_prefix,
                 keep_stage=args.keep_stage,
-                ignore_deps=args.ignore_deps,
+                install_deps=not args.ignore_deps,
+                install_self=not args.deps_only,
                 make_jobs=args.jobs,
                 run_tests=args.run_tests,
                 verbose=args.verbose,
diff --git a/lib/spack/spack/cmd/setup.py b/lib/spack/spack/cmd/setup.py
index 4dfa13eccf..c63c566338 100644
--- a/lib/spack/spack/cmd/setup.py
+++ b/lib/spack/spack/cmd/setup.py
@@ -91,7 +91,8 @@ def setup(self, args):
 
         package.do_install(
             keep_prefix=True,  # Don't remove install directory
-            ignore_deps=args.ignore_deps,
+            install_deps=not args.ignore_deps,
+            install_self=True,
             verbose=args.verbose,
             keep_stage=True,   # don't remove source dir for SETUP.
             install_phases=set(['setup', 'provenance']),
diff --git a/lib/spack/spack/cmd/test_install.py b/lib/spack/spack/cmd/test_install.py
index 8e7173e9a2..c35f2740a0 100644
--- a/lib/spack/spack/cmd/test_install.py
+++ b/lib/spack/spack/cmd/test_install.py
@@ -180,7 +180,8 @@ def install_single_spec(spec, number_of_jobs):
         start_time = time.time()
         package.do_install(keep_prefix=False,
                            keep_stage=True,
-                           ignore_deps=False,
+                           install_deps=True,
+                           install_self=True,
                            make_jobs=number_of_jobs,
                            verbose=True,
                            fake=False)
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index cb7f6b3f39..b272cc3eba 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -259,7 +259,7 @@ class SomePackage(Package):
            parallel = False
            ...
 
-    This changes thd default behavior so that make is sequential.  If you still
+    This changes the default behavior so that make is sequential.  If you still
     want to build some parts in parallel, you can do this in your install
     function:
 
@@ -868,7 +868,8 @@ def _resource_stage(self, resource):
     def do_install(self,
                    keep_prefix=False,
                    keep_stage=False,
-                   ignore_deps=False,
+                   install_deps=True,
+                   install_self=True,
                    skip_patch=False,
                    verbose=False,
                    make_jobs=None,
@@ -887,8 +888,10 @@ def do_install(self,
         :param keep_stage: By default, stage is destroyed only if there are \
             no exceptions during build. Set to True to keep the stage
             even with exceptions.
-        :param ignore_deps: Don't install dependencies before installing this \
-                       package
+        :param install_deps: Install dependencies before installing this \
+            package
+        :param install_self: Install this package once dependencies have \
+            been installed.
         :param fake: Don't really build; install fake stub files instead.
         :param skip_patch: Skip patch stage of build if True.
         :param verbose: Display verbose build output (by default, suppresses \
@@ -896,6 +899,7 @@ def do_install(self,
         :param dirty: Don't clean the build environment before installing.
         :param make_jobs: Number of make jobs to use for install. Default is \
             ncpus
+        :param force: Install again, even if already installed.
         :param run_tests: Run tests within the package's install()
         """
         if not self.spec.concrete:
@@ -922,16 +926,24 @@ def do_install(self,
         tty.msg("Installing %s" % self.name)
 
         # First, install dependencies recursively.
-        if not ignore_deps:
-            self.do_install_dependencies(keep_prefix=keep_prefix,
-                                         keep_stage=keep_stage,
-                                         ignore_deps=ignore_deps,
-                                         fake=fake,
-                                         skip_patch=skip_patch,
-                                         verbose=verbose,
-                                         make_jobs=make_jobs,
-                                         run_tests=run_tests,
-                                         dirty=dirty)
+        if install_deps:
+            for dep in self.spec.dependencies():
+                dep.package.do_install(
+                    keep_prefix=keep_prefix,
+                    keep_stage=keep_stage,
+                    install_deps=install_deps,
+                    install_self=True,
+                    fake=fake,
+                    skip_patch=skip_patch,
+                    verbose=verbose,
+                    make_jobs=make_jobs,
+                    run_tests=run_tests,
+                    dirty=dirty)
+
+        # The rest of this function is to install ourself,
+        # once deps have been installed.
+        if not install_self:
+            return
 
         # Set run_tests flag before starting build.
         self.run_tests = run_tests
@@ -939,6 +951,7 @@ def do_install(self,
         # Set parallelism before starting build.
         self.make_jobs = make_jobs
 
+        # ------------------- BEGIN def build_process()
         # Then install the package itself.
         def build_process():
             """Forked for each build. Has its own process and python
@@ -1022,6 +1035,7 @@ def build_process():
                     (_hms(self._fetch_time), _hms(build_time),
                      _hms(self._total_time)))
             print_pkg(self.prefix)
+        # ------------------- END def build_process()
 
         try:
             # Create the install prefix and fork the build process.
@@ -1079,11 +1093,6 @@ def check_paths(path_list, filetype, predicate):
             raise InstallError(
                 "Install failed for %s.  Nothing was installed!" % self.name)
 
-    def do_install_dependencies(self, **kwargs):
-        # Pass along paths of dependencies here
-        for dep in self.spec.dependencies():
-            dep.package.do_install(**kwargs)
-
     @property
     def build_log_path(self):
         if self.installed:
-- 
GitLab