diff --git a/lib/spack/spack/cmd/activate.py b/lib/spack/spack/cmd/activate.py
index c1e23852d64c6f157e656dbd9b11303d2262c7df..71eca4f4537219871ca85e7fde64e2a75f3fe6e9 100644
--- a/lib/spack/spack/cmd/activate.py
+++ b/lib/spack/spack/cmd/activate.py
@@ -30,6 +30,9 @@
 description = "Activate a package extension."
 
 def setup_parser(subparser):
+    subparser.add_argument(
+        '-f', '--force', action='store_true',
+        help="Activate without first activating dependencies.")
     subparser.add_argument(
         'spec', nargs=argparse.REMAINDER, help="spec of package extension to activate.")
 
@@ -44,6 +47,9 @@ def activate(parser, args):
     spack.db.get(specs[0])
 
     spec = spack.cmd.disambiguate_spec(specs[0])
+    if not spec.package.is_extension:
+        tty.die("%s is not an extension." % spec.name)
+
     if spec.package.activated:
         tty.die("Package %s is already activated." % specs[0].short_spec)
 
diff --git a/lib/spack/spack/cmd/deactivate.py b/lib/spack/spack/cmd/deactivate.py
index f37dfd79ed85e84847ab07f9837e3477a252b137..bfec618c8e2b8f9fa3270650249cfa0851fb03ba 100644
--- a/lib/spack/spack/cmd/deactivate.py
+++ b/lib/spack/spack/cmd/deactivate.py
@@ -24,8 +24,10 @@
 ##############################################################################
 from external import argparse
 import llnl.util.tty as tty
+
 import spack
 import spack.cmd
+from spack.graph import topological_sort
 
 description = "Deactivate a package extension."
 
@@ -33,6 +35,10 @@ 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(
+        '-a', '--all', action='store_true',
+        help="Deactivate all extensions of an extendable pacakge, or "
+        "deactivate an extension AND its dependencies.")
     subparser.add_argument(
         'spec', nargs=argparse.REMAINDER, help="spec of package extension to deactivate.")
 
@@ -42,12 +48,52 @@ def deactivate(parser, args):
     if len(specs) != 1:
         tty.die("deactivate requires one spec.  %d given." % len(specs))
 
-    # TODO: remove this hack when DAG info is stored in dir layout.
+    # TODO: remove this hack when DAG info is stored properly.
     # This ensures the ext spec is always normalized properly.
     spack.db.get(specs[0])
 
     spec = spack.cmd.disambiguate_spec(specs[0])
-    if not args.force and not spec.package.activated:
-        tty.die("Package %s is not activated." % specs[0].short_spec)
+    pkg = spec.package
+
+    if args.all:
+        if pkg.extendable:
+            tty.msg("Deactivating all extensions of %s" % pkg.spec.short_spec)
+            ext_pkgs = spack.db.installed_extensions_for(spec)
+            for ext_pkg in ext_pkgs:
+                ext_pkg.spec.normalize()
+                if ext_pkg.activated:
+                    ext_pkg.do_deactivate(force=True)
+
+        elif pkg.is_extension:
+            # TODO: store DAG info properly (see above)
+            spec.normalize()
+
+            tty.msg("Deactivating %s and all dependencies." % pkg.spec.short_spec)
+
+            topo_order = topological_sort(spec)
+            index = spec.index()
+
+            for name in topo_order:
+                espec = index[name]
+                epkg = espec.package
+
+                # TODO: store DAG info properly (see above)
+                epkg.spec.normalize()
+
+                if epkg.extends(pkg.extendee_spec):
+                    if epkg.activated or args.force:
+
+                        epkg.do_deactivate(force=args.force)
+
+        else:
+            tty.die("spack deactivate --all requires an extendable package or an extension.")
+
+    else:
+        if not pkg.is_extension:
+            tty.die("spack deactivate requires an extension.",
+                    "Did you mean 'spack deactivate --all'?")
+
+        if not args.force and not spec.package.activated:
+            tty.die("Package %s is not activated." % specs[0].short_spec)
 
-    spec.package.do_deactivate(force=args.force)
+        spec.package.do_deactivate(force=args.force)
diff --git a/lib/spack/spack/cmd/find.py b/lib/spack/spack/cmd/find.py
index dee1dfece71c058ecf0ab43acc8171d35b7e6426..70b10edb4eb2c1045df80d595ee712b1b30ff9b9 100644
--- a/lib/spack/spack/cmd/find.py
+++ b/lib/spack/spack/cmd/find.py
@@ -85,7 +85,7 @@ def display_specs(specs, **kwargs):
 
         elif mode == 'deps':
             for spec in specs:
-                print spec.tree(indent=4, format='$_$@$+', color=True),
+                print spec.tree(indent=4, format='$_$@$+$#', color=True),
 
         elif mode in ('short', 'long'):
             fmt = '$-_$@$+'
diff --git a/lib/spack/spack/directory_layout.py b/lib/spack/spack/directory_layout.py
index 5b80e93d6b89e994c385b8e20bd34255dd069122..b2cf5dc801744ea26e5e35cac3aa937de72be418 100644
--- a/lib/spack/spack/directory_layout.py
+++ b/lib/spack/spack/directory_layout.py
@@ -371,7 +371,7 @@ def add_extension(self, spec, ext_spec):
         _check_concrete(ext_spec)
 
         # Check whether it's already installed or if it's a conflict.
-        exts = self.extension_map(spec)
+        exts = self._extension_map(spec)
         self.check_extension_conflict(spec, ext_spec)
 
         # do the actual adding.
@@ -384,7 +384,7 @@ def remove_extension(self, spec, ext_spec):
         _check_concrete(ext_spec)
 
         # Make sure it's installed before removing.
-        exts = self.extension_map(spec)
+        exts = self._extension_map(spec)
         self.check_activated(spec, ext_spec)
 
         # do the actual removing.
@@ -450,10 +450,10 @@ def __init__(self, spec, ext_spec, conflict):
 
 
 class NoSuchExtensionError(DirectoryLayoutError):
-    """Raised when an extension isn't there on remove."""
+    """Raised when an extension isn't there on deactivate."""
     def __init__(self, spec, ext_spec):
         super(NoSuchExtensionError, self).__init__(
-            "%s cannot be removed from %s because it's not installed."% (
+            "%s cannot be removed from %s because it's not activated."% (
                 ext_spec.short_spec, spec.short_spec))
 
 
diff --git a/lib/spack/spack/hooks/extensions.py b/lib/spack/spack/hooks/extensions.py
index 9d6fa23d03467d925d202a4974aa48e89024e55c..cf87a78c8c802650fe261296e8d7f020352dac04 100644
--- a/lib/spack/spack/hooks/extensions.py
+++ b/lib/spack/spack/hooks/extensions.py
@@ -33,4 +33,4 @@ def pre_uninstall(pkg):
 
     if pkg.is_extension:
         if pkg.activated:
-            pkg.do_deactivate()
+            pkg.do_deactivate(force=True)
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index 5d04fed8ffdb880cb421c20d23693b304b534418..bc8541a184f035b7d32dd05ae9f0fbc2d14d109b 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -529,11 +529,8 @@ def extends(self, spec):
 
     @property
     def activated(self):
-        if not self.spec.concrete:
-            raise ValueError("Only concrete package extensions can be activated.")
         if not self.is_extension:
             raise ValueError("is_extension called on package that is not an extension.")
-
         exts = spack.install_layout.extension_map(self.extendee_spec)
         return (self.name in exts) and (exts[self.name] == self.spec)
 
@@ -956,20 +953,33 @@ def _sanity_check_extension(self):
             raise ValueError("%s does not extend %s!" % (self.name, self.extendee.name))
 
 
-    def do_activate(self):
+    def do_activate(self, **kwargs):
         """Called on an etension to invoke the extendee's activate method.
 
         Commands should call this routine, and should not call
         activate() directly.
         """
         self._sanity_check_extension()
+        force = kwargs.get('force', False)
+
+        # TODO: get rid of this normalize - DAG handling.
+        self.spec.normalize()
+
         spack.install_layout.check_extension_conflict(self.extendee_spec, self.spec)
 
+        if not force:
+            for spec in self.spec.traverse(root=False):
+                if spec.package.extends(self.extendee_spec):
+                    # TODO: fix this normalize() requirement -- revisit DAG handling.
+                    spec.package.spec.normalize()
+                    if not spec.package.activated:
+                        spec.package.do_activate(**kwargs)
+
         self.extendee_spec.package.activate(self, **self.extendee_args)
 
         spack.install_layout.add_extension(self.extendee_spec, self.spec)
         tty.msg("Activated extension %s for %s."
-                % (self.spec.short_spec, self.extendee_spec.short_spec))
+                % (self.spec.short_spec, self.extendee_spec.format("$_$@$+$%@")))
 
 
     def activate(self, extension, **kwargs):
@@ -994,15 +1004,21 @@ def ignore(filename):
 
     def do_deactivate(self, **kwargs):
         """Called on the extension to invoke extendee's deactivate() method."""
-        force = kwargs.get('force', False)
-
         self._sanity_check_extension()
+        force = kwargs.get('force', False)
 
         # Allow a force deactivate to happen.  This can unlink
         # spurious files if something was corrupted.
         if not force:
             spack.install_layout.check_activated(self.extendee_spec, self.spec)
 
+            activated = spack.install_layout.extension_map(self.extendee_spec)
+            for name, aspec in activated.items():
+                if aspec != self.spec and self.spec in aspec:
+                    raise ActivationError(
+                        "Cannot deactivate %s beacuse %s is activated and depends on it."
+                        % (self.spec.short_spec, aspec.short_spec))
+
         self.extendee_spec.package.deactivate(self, **self.extendee_args)
 
         # redundant activation check -- makes SURE the spec is not
@@ -1011,7 +1027,7 @@ def do_deactivate(self, **kwargs):
             spack.install_layout.remove_extension(self.extendee_spec, self.spec)
 
         tty.msg("Deactivated extension %s for %s."
-                % (self.spec.short_spec, self.extendee_spec.short_spec))
+                % (self.spec.short_spec, self.extendee_spec.format("$_$@$+$%@")))
 
 
     def deactivate(self, extension, **kwargs):
@@ -1236,7 +1252,15 @@ def __init__(self, cls):
             "Package %s has no version with a URL." % cls.__name__)
 
 
-class ExtensionConflictError(PackageError):
+class ExtensionError(PackageError): pass
+
+
+class ExtensionConflictError(ExtensionError):
     def __init__(self, path):
         super(ExtensionConflictError, self).__init__(
             "Extension blocked by file: %s" % path)
+
+
+class ActivationError(ExtensionError):
+    def __init__(self, msg, long_msg=None):
+        super(ActivationError, self).__init__(msg, long_msg)