From 614c22fc1b1ac10c85ed9e27a1e59eeb88de0898 Mon Sep 17 00:00:00 2001
From: Todd Gamblin <tgamblin@llnl.gov>
Date: Mon, 16 Feb 2015 12:41:22 -0800
Subject: [PATCH] Allow forced deactivation -- best effort unlinking

spack deactivate -f will unlink even if Spack thinks the package isn't enabled.
Made deactivate routines idempotent.
---
 lib/spack/llnl/util/link_tree.py     | 4 ++++
 lib/spack/spack/cmd/deactivate.py    | 7 +++++--
 lib/spack/spack/cmd/find.py          | 3 +++
 var/spack/packages/python/package.py | 5 +++--
 4 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/lib/spack/llnl/util/link_tree.py b/lib/spack/llnl/util/link_tree.py
index 4e4e48316e..4d778eca1e 100644
--- a/lib/spack/llnl/util/link_tree.py
+++ b/lib/spack/llnl/util/link_tree.py
@@ -175,6 +175,10 @@ def unmerge(self, dest_root, **kwargs):
         kwargs['order'] = 'post'
         for src, dest in traverse_tree(self._root, dest_root, **kwargs):
             if os.path.isdir(src):
+                # Skip non-existing links.
+                if not os.path.exists(dest):
+                    continue
+
                 if not os.path.isdir(dest):
                     raise ValueError("File blocks directory: %s" % dest)
 
diff --git a/lib/spack/spack/cmd/deactivate.py b/lib/spack/spack/cmd/deactivate.py
index fd13f051df..f37dfd79ed 100644
--- a/lib/spack/spack/cmd/deactivate.py
+++ b/lib/spack/spack/cmd/deactivate.py
@@ -30,6 +30,9 @@
 description = "Deactivate a package extension."
 
 def setup_parser(subparser):
+    subparser.add_argument(
+        '-f', '--force', action='store_true',
+        help="Run deactivation even if spec is NOT currently activated.")
     subparser.add_argument(
         'spec', nargs=argparse.REMAINDER, help="spec of package extension to deactivate.")
 
@@ -44,7 +47,7 @@ def deactivate(parser, args):
     spack.db.get(specs[0])
 
     spec = spack.cmd.disambiguate_spec(specs[0])
-    if not spec.package.activated:
+    if not args.force and not spec.package.activated:
         tty.die("Package %s is not activated." % specs[0].short_spec)
 
-    spec.package.do_deactivate()
+    spec.package.do_deactivate(force=args.force)
diff --git a/lib/spack/spack/cmd/find.py b/lib/spack/spack/cmd/find.py
index f6f503afe5..dee1dfece7 100644
--- a/lib/spack/spack/cmd/find.py
+++ b/lib/spack/spack/cmd/find.py
@@ -122,5 +122,8 @@ def find(parser, args):
 
     if not args.mode:
         args.mode = 'short'
+
+    if sys.stdout.isatty():
+        tty.msg("%d installed packages." % len(specs))
     display_specs(specs, mode=args.mode)
 
diff --git a/var/spack/packages/python/package.py b/var/spack/packages/python/package.py
index fb875a7eeb..705d002e80 100644
--- a/var/spack/packages/python/package.py
+++ b/var/spack/packages/python/package.py
@@ -155,5 +155,6 @@ def deactivate(self, ext_pkg, **args):
         super(Python, self).deactivate(ext_pkg, **args)
 
         exts = spack.install_layout.extension_map(self.spec)
-        del exts[ext_pkg.name]
-        self.write_easy_install_pth(exts)
+        if ext_pkg.name in exts:        # Make deactivate idempotent.
+            del exts[ext_pkg.name]
+            self.write_easy_install_pth(exts)
-- 
GitLab