[PATCH 3/4] Disk selection determines both ignoredisk.onlyuse and clearpart.drives.

David Lehman dlehman at redhat.com
Tue Jul 10 16:38:35 UTC 2012


This adds a way to hide devices from the devicetree without removing
them. The devicetree is initially populated without filtering because
we need to collect information about disks in the system as well as
free space in disks and filesystems. Disk selection in the storage
spoke establishes the set of disks to be used during install. We don't
want to re-populate the tree every time a disk is selected or
deselected. Instead, we just hide/unhide the disk and all devices it
contains.
---
 pyanaconda/storage/devicelibs/lvm.py |   15 +++++++++++-
 pyanaconda/storage/devicetree.py     |   43 ++++++++++++++++++++++++++++++---
 pyanaconda/ui/gui/spokes/storage.py  |   31 +++++++++++++++++++-----
 3 files changed, 77 insertions(+), 12 deletions(-)

diff --git a/pyanaconda/storage/devicelibs/lvm.py b/pyanaconda/storage/devicelibs/lvm.py
index 36fd980..136168b 100644
--- a/pyanaconda/storage/devicelibs/lvm.py
+++ b/pyanaconda/storage/devicelibs/lvm.py
@@ -83,7 +83,20 @@ def lvm_cc_addFilterRejectRegexp(regexp):
     log.debug("lvm filter: adding %s to the reject list" % regexp)
     config_args_data["filterRejects"].append(regexp)
 
-    # compoes config once more.
+    # compose config once more.
+    _composeConfig()
+
+def lvm_cc_removeFilterRejectRegexp(regexp):
+    """ Remove a regular expression from the --config string."""
+    global config_args_data
+    log.debug("lvm filter: removing %s from the reject list" % regexp)
+    try:
+        config_args_data["filterRejects"].remove(regexp)
+    except ValueError:
+        log.debug("%s wasn't in the reject list" % regexp)
+        return
+
+    # compose config once more.
     _composeConfig()
 
 def lvm_cc_resetFilter():
diff --git a/pyanaconda/storage/devicetree.py b/pyanaconda/storage/devicetree.py
index 2c36f83..ae69be2 100644
--- a/pyanaconda/storage/devicetree.py
+++ b/pyanaconda/storage/devicetree.py
@@ -166,6 +166,8 @@ class DeviceTree(object):
         # a list of all device names we encounter
         self.names = []
 
+        self._hidden = []
+
         # indicates whether or not the tree has been fully populated
         self.populated = False
 
@@ -1686,12 +1688,45 @@ class DeviceTree(object):
 
             self._removeDevice(md)
 
-    def _recursiveRemove(self, device):
+    def hide(self, device):
         for d in self.getChildren(device):
-            self._recursiveRemove(d)
+            self.hide(d)
+
+        log.info("hiding device %s %s (id %d)" % (device.type,
+                                                  device.name,
+                                                  device.id))
 
-        device.teardown()
-        self._removeDevice(device)
+        for action in reversed(self._actions):
+            if not action.device.dependsOn(device) and action.device != device:
+                continue
+
+            log.debug("cancelling action: %s" % action)
+            try:
+                action.cancel()
+            except Exception:
+                log.warning("failed to cancel action while hiding %s: %s"
+                            % (device.name, action))
+            finally:
+                self._actions.remove(action)
+
+        # XXX modifications that do not require actions, like setting a
+        #     mountpoint, will not be reversed here
+
+        # we're intentionally not modifying self.names here
+        self._devices.remove(device)
+        self._hidden.append(device)
+        lvm.lvm_cc_addFilterRejectRegexp(device.name)
+
+    def unhide(self, device):
+        # the hidden list should be in leaves-first order
+        for hidden in reversed(self._hidden):
+            if hidden == device or hidden.dependsOn(device):
+                log.info("unhiding device %s %s (id %d)" % (hidden.type,
+                                                            hidden.name,
+                                                            hidden.id))
+                self._hidden.remove(hidden)
+                self._devices.append(hidden)
+                lvm.lvm_cc_removeFilterRejectRegexp(device.name)
 
     def _setupLvs(self):
         ret = False
diff --git a/pyanaconda/ui/gui/spokes/storage.py b/pyanaconda/ui/gui/spokes/storage.py
index 4cf3f5e..0e3ecec 100644
--- a/pyanaconda/ui/gui/spokes/storage.py
+++ b/pyanaconda/ui/gui/spokes/storage.py
@@ -240,7 +240,12 @@ class StorageSpoke(NormalSpoke):
     def __init__(self, *args, **kwargs):
         NormalSpoke.__init__(self, *args, **kwargs)
         self._ready = False
-        self.selected_disks = self.data.clearpart.drives[:]
+        self.selected_disks = self.data.ignoredisk.onlyuse[:]
+
+        # This list gets set up once in initialize and should not be modified
+        # except perhaps to add advanced devices. It will remain the full list
+        # of disks that can be included in the install.
+        self.disks = []
 
         if not flags.automatedInstall:
             # default to using autopart for interactive installs
@@ -252,6 +257,7 @@ class StorageSpoke(NormalSpoke):
         self.clearPartType = CLEARPART_TYPE_LINUX
 
     def apply(self):
+        self.data.ignoredisk.onlyuse = self.selected_disks[:]
         self.data.clearpart.drives = self.selected_disks[:]
         self.data.autopart.autopart = self.autopart
 
@@ -263,6 +269,14 @@ class StorageSpoke(NormalSpoke):
         else:
             self.clearPartType = CLEARPART_TYPE_NONE
 
+        for disk in self.disks:
+            if disk.name not in self.selected_disks and \
+               disk in self.storage.devices:
+                self.storage.devicetree.hide(disk)
+            elif disk.name in self.selected_disks and \
+                 disk not in self.storage.devices:
+                self.storage.devicetree.unhide(disk)
+
         self.data.bootloader.location = "mbr"
 
         self.data.clearpart.initAll = True
@@ -301,10 +315,10 @@ class StorageSpoke(NormalSpoke):
     def status(self):
         """ A short string describing the current status of storage setup. """
         msg = _("No disks selected")
-        if self.data.clearpart.drives:
+        if self.data.ignoredisk.onlyuse:
             msg = P_(("%d disk selected"),
                      ("%d disks selected"),
-                     len(self.data.clearpart.drives)) % len(self.data.clearpart.drives)
+                     len(self.data.ignoredisk.onlyuse)) % len(self.data.ignoredisk.onlyuse)
 
             if self.data.autopart.autopart:
                 msg = _("Automatic partitioning selected")
@@ -330,7 +344,7 @@ class StorageSpoke(NormalSpoke):
 
     def refresh(self):
         # synchronize our local data store with the global ksdata
-        self.selected_disks = self.data.clearpart.drives[:]
+        self.selected_disks = self.data.ignoredisk.onlyuse[:]
         self.autopart = self.data.autopart.autopart
 
         # update the selections in the ui
@@ -367,7 +381,7 @@ class StorageSpoke(NormalSpoke):
         if storageThread:
             storageThread.join()
 
-        print self.data.clearpart.drives
+        print self.data.ignoredisk.onlyuse
 
         self.disks = getDisks(self.storage.devicetree)
 
@@ -408,7 +422,9 @@ class StorageSpoke(NormalSpoke):
         capacity = 0
         free = Size(bytes=0)
 
-        free_space = self.storage.getFreeSpace(clearPartType=self.clearPartType)
+        # pass in our disk list so hidden disks' free space is available
+        free_space = self.storage.getFreeSpace(disks=self.disks,
+                                               clearPartType=self.clearPartType)
         selected = [d for d in self.disks if d.name in self.selected_disks]
 
         for disk in selected:
@@ -448,7 +464,8 @@ class StorageSpoke(NormalSpoke):
     # signal handlers
     def on_summary_clicked(self, button):
         # show the selected disks dialog
-        free_space = self.storage.getFreeSpace()
+        # pass in our disk list so hidden disks' free space is available
+        free_space = self.storage.getFreeSpace(disks=self.disks)
         dialog = SelectedDisksDialog(self.data,)
         dialog.refresh([d for d in self.disks if d.name in self.selected_disks],
                        free_space)
-- 
1.7.7.6



More information about the anaconda-patches mailing list