Repository: spack/spack

Issue:
`package.do_install` signature
Below a cut and paste of [my original comment](https://github.com/LLNL/spack/pull/1603#issuecomment-251769903) in #1603 : 

> Sorry if I am late at being picky here, but I find the API of do_install growing quite unintuitive. Now we may call a do_install that does no install at all, while the semantic needed for this PR could have been obtained directly in the install command traversing the DAG with or without root and calling an unmodified version of do_install from there.

Moved to an issue as suggested by @citibeth .

@tgamblin Do you think it would be the case to add another tag like 'refactoring' ? 



Discussion:

Resolving patch:
diff --git a/lib/spack/spack/cmd/install.py b/lib/spack/spack/cmd/install.py
--- a/lib/spack/spack/cmd/install.py
+++ b/lib/spack/spack/cmd/install.py
@@ -35,12 +35,15 @@
 
 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.')
+        '--only',
+        default='package,dependencies',
+        dest='things_to_install',
+        choices=['package', 'dependencies', 'package,dependencies'],
+        help="""Select the mode of installation.
+The default is to install the package along with all its dependencies.
+Alternatively one can decide to install only the package or only
+the dependencies."""
+    )
     subparser.add_argument(
         '-j', '--jobs', action='store', type=int,
         help="Explicitly set number of make jobs.  Default is #cpus.")
@@ -63,15 +66,17 @@ def setup_parser(subparser):
         '--dirty', action='store_true', dest='dirty',
         help="Install a package *without* cleaning the environment.")
     subparser.add_argument(
-        'packages', nargs=argparse.REMAINDER,
-        help="specs of packages to install")
+        'package',
+        nargs=argparse.REMAINDER,
+        help="spec of the package to install"
+    )
     subparser.add_argument(
         '--run-tests', action='store_true', dest='run_tests',
         help="Run tests during installation of a package.")
 
 
 def install(parser, args):
-    if not args.packages:
+    if not args.package:
         tty.die("install requires at least one package argument")
 
     if args.jobs is not None:
@@ -81,17 +86,33 @@ def install(parser, args):
     if args.no_checksum:
         spack.do_checksum = False        # TODO: remove this global.
 
-    specs = spack.cmd.parse_specs(args.packages, concretize=True)
-    for spec in specs:
+    # Parse cli arguments and construct a dictionary
+    # that will be passed to Package.do_install API
+    kwargs = {
+        'keep_prefix': args.keep_prefix,
+        'keep_stage': args.keep_stage,
+        'install_deps': 'dependencies' in args.things_to_install,
+        'make_jobs': args.jobs,
+        'run_tests': args.run_tests,
+        'verbose': args.verbose,
+        'fake': args.fake,
+        'dirty': args.dirty
+    }
+
+    # Spec from cli
+    specs = spack.cmd.parse_specs(args.package, concretize=True)
+    if len(specs) != 1:
+        tty.error('only one spec can be installed at a time.')
+    spec = specs.pop()
+
+    if args.things_to_install == 'dependencies':
+        # Install dependencies as-if they were installed
+        # for root (explicit=False in the DB)
+        kwargs['explicit'] = False
+        for s in spec.dependencies():
+            p = spack.repo.get(s)
+            p.do_install(**kwargs)
+    else:
         package = spack.repo.get(spec)
-        package.do_install(
-            keep_prefix=args.keep_prefix,
-            keep_stage=args.keep_stage,
-            install_deps=not args.ignore_deps,
-            install_self=not args.deps_only,
-            make_jobs=args.jobs,
-            run_tests=args.run_tests,
-            verbose=args.verbose,
-            fake=args.fake,
-            dirty=args.dirty,
-            explicit=True)
+        kwargs['explicit'] = True
+        package.do_install(**kwargs)
diff --git a/lib/spack/spack/cmd/setup.py b/lib/spack/spack/cmd/setup.py
--- a/lib/spack/spack/cmd/setup.py
+++ b/lib/spack/spack/cmd/setup.py
@@ -92,7 +92,6 @@ def setup(self, args):
         package.do_install(
             keep_prefix=True,  # Don't remove install directory
             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/package.py b/lib/spack/spack/package.py
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -952,8 +952,6 @@ def do_install(self,
             even with exceptions.
         :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 \
@@ -998,7 +996,6 @@ def do_install(self,
                     keep_prefix=keep_prefix,
                     keep_stage=keep_stage,
                     install_deps=install_deps,
-                    install_self=True,
                     fake=fake,
                     skip_patch=skip_patch,
                     verbose=verbose,
@@ -1006,11 +1003,6 @@ def do_install(self,
                     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
 


Test patch:
diff --git a/lib/spack/spack/cmd/test_install.py b/lib/spack/spack/cmd/test_install.py
--- a/lib/spack/spack/cmd/test_install.py
+++ b/lib/spack/spack/cmd/test_install.py
@@ -181,7 +181,6 @@ def install_single_spec(spec, number_of_jobs):
         package.do_install(keep_prefix=False,
                            keep_stage=True,
                            install_deps=True,
-                           install_self=True,
                            make_jobs=number_of_jobs,
                            verbose=True,
                            fake=False)