BTRFS and RAID are not always in the device type combo, so we can't count on using direct index access to the combo. --- pyanaconda/ui/gui/spokes/custom.py | 181 +++++++++++++++++++++++++++--------- 1 files changed, 135 insertions(+), 46 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/custom.py b/pyanaconda/ui/gui/spokes/custom.py index 28bce13..6eb881b 100644 --- a/pyanaconda/ui/gui/spokes/custom.py +++ b/pyanaconda/ui/gui/spokes/custom.py @@ -46,6 +46,7 @@ from pyanaconda.threads import threadMgr
from pyanaconda.storage.formats import device_formats from pyanaconda.storage.formats import getFormat +from pyanaconda.storage.formats.fs import FS from pyanaconda.storage.size import Size from pyanaconda.storage import Root from pyanaconda.storage import findExistingInstallations @@ -99,8 +100,11 @@ mountpoint_validation_msgs = {MOUNTPOINT_OK: "", MOUNTPOINT_IN_USE: mountpoint_in_use_msg, MOUNTPOINT_EMPTY: empty_mountpoint_msg}
-# btrfs has to be the last type in the list since it gets removed and added -# depending on the device's formatting +DEVICE_TEXT_LVM = _("LVM") +DEVICE_TEXT_MD = _("RAID") +DEVICE_TEXT_PARTITION = _("Standard Partition") +DEVICE_TEXT_BTRFS = _("BTRFS") + # FIXME: use these everywhere instead of the AUTOPART_TYPE constants DEVICE_TYPE_LVM = 0 DEVICE_TYPE_MD = 1 @@ -269,6 +273,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): self._current_selector = None self._when_create_text = "" self._devices = [] + self._fs_types = [] # list of supported fstypes self._unused_devices = None # None indicates uninitialized self._free_space = Size(bytes=0)
@@ -461,8 +466,6 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): self._configButton = self.builder.get_object("configureButton")
def initialize(self): - from pyanaconda.storage.formats.fs import FS - NormalSpoke.initialize(self)
label = self.builder.get_object("whenCreateLabel") @@ -486,14 +489,20 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): # Populate the list of valid filesystem types from the format classes. # Unfortunately, we have to narrow them down a little bit more because # this list will include things like PVs and RAID members. - combo = self.builder.get_object("fileSystemTypeCombo") + fsCombo = self.builder.get_object("fileSystemTypeCombo") + fsCombo.remove_all() + self._fs_types = [] for cls in device_formats.itervalues(): obj = cls() - if obj.supported and obj.formattable and \ - obj.type != "btrfs" and \ - (isinstance(obj, FS) or - obj.type in ["biosboot", "prepboot", "swap"]): - combo.append_text(obj.name) + + # btrfs is always handled by on_device_type_changed + supported_fs = (obj.type != "btrfs" and + obj.supported and obj.formattable and + (isinstance(obj, FS) or + obj.type in ["biosboot", "prepboot", "swap"])) + if supported_fs: + fsCombo.append_text(obj.name) + self._fs_types.append(obj.name)
def _mountpointName(self, mountpoint): # If there's a mount point, apply a kind of lame scheme to it to figure @@ -852,7 +861,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): log.debug("new size: %s" % size) log.debug("old size: %s" % device.size)
- device_type = self.builder.get_object("deviceTypeCombo").get_active() + device_type = self._get_current_device_type() device_type_map = {DEVICE_TYPE_PARTITION: AUTOPART_TYPE_PLAIN, DEVICE_TYPE_BTRFS: AUTOPART_TYPE_BTRFS, DEVICE_TYPE_LVM: AUTOPART_TYPE_LVM, @@ -1226,8 +1235,9 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): (button, label) = widget_dict[feature] button.set_sensitive(feature not in disabled)
- def _populate_raid(self, device_type, raid_level, size): + def _populate_raid(self, raid_level, size): """ Set up the raid-specific portion of the device details. """ + device_type = self._get_current_device_type() log.debug("populate_raid: %s, %s" % (device_type, raid_level))
if device_type == DEVICE_TYPE_MD: @@ -1277,6 +1287,24 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): # some features are not available to some raid levels button.set_sensitive(feature not in disabled)
+ def _get_current_device_type(self): + typeCombo = self.builder.get_object("deviceTypeCombo") + device_type_text = typeCombo.get_active_text() + log.info("getting device type for %s" % device_type_text) + device_type = None + if device_type_text == DEVICE_TEXT_LVM: + device_type = DEVICE_TYPE_LVM + elif device_type_text == DEVICE_TEXT_MD: + device_type = DEVICE_TYPE_MD + elif device_type_text == DEVICE_TEXT_PARTITION: + device_type = DEVICE_TYPE_PARTITION + elif device_type_text == DEVICE_TEXT_BTRFS: + device_type = DEVICE_TYPE_BTRFS + else: + log.error("unknown device type: '%s'" % device_type_text) + + return device_type + def _populate_right_side(self, selector): log.debug("populate_right_side: %s" % selector._device) encryptCheckbox = self.builder.get_object("encryptCheckbox") @@ -1332,38 +1360,93 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
encryptCheckbox.set_active(device.encrypted)
+ ## + ## Set up the filesystem type combo. + ## + + # remove any fs types that aren't supported + remove_indices = [] + for idx, data in enumerate(fsCombo.get_model()): + fs_type = data[0] + if fs_type not in self._fs_types: + remove_indices.insert(0, idx) + continue + + if fs_type == device.format.name: + fsCombo.set_active(idx) + + for remove_idx in remove_indices: + fsCombo.remove(remove_idx) + + # if the current device has unsupported formatting, add an entry for it + if device.format.name not in self._fs_types: + fsCombo.append_text(device.format.name) + fsCombo.set_active(len(fsCombo.get_model()) - 1) + + # Give them a way to reset to original formatting. Whenever we add a + # "reformat this" widget this will need revisiting. + if device.exists and \ + device.format.type != device.originalFormat.type and \ + device.originalFormat.type not in self._fs_types: + fsCombo.append_text(device.originalFormat.name) + + ## + ## Set up the device type combo. + ## + + btrfs_pos = None + btrfs_included = False + md_pos = None + md_included = False + for idx, itr in enumerate(typeCombo.get_model()): + if itr[0] == DEVICE_TEXT_BTRFS: + btrfs_pos = idx + btrfs_included = True + elif itr[0] == DEVICE_TEXT_MD: + md_pos = idx + md_included = True + + # only include md if there are two or more disks + include_md = (use_dev.type == "mdarray" or + len(self._clearpartDevices) > 1) + if include_md and not md_included: + typeCombo.append_text(DEVICE_TEXT_RAID) + elif md_included and not include_md: + typeCombo.remove(md_pos) + # if the format is swap the device type can't be btrfs include_btrfs = use_dev.format.type not in ("swap", "prepboot", "biosboot") - # btrfs has to be the last type in the list - btrfs_included = typeCombo.get_model()[-1][0] == "BTRFS" if include_btrfs and not btrfs_included: - typeCombo.append_text("BTRFS") + typeCombo.append_text(DEVICE_TEXT_BTRFS) elif btrfs_included and not include_btrfs: - typeCombo.remove(len(typeCombo.get_model()) - 1) - - # if the format is unknown/none, add that to the list - # otherwise, make sure it's not in the list - unknown_fmt = getFormat(None) - include_unknown = device.format.type is None - unknown_included = fsCombo.get_model()[-1][0] == unknown_fmt.name - if include_unknown and not unknown_included: - fsCombo.append_text(unknown_fmt.name) - elif unknown_included and not include_unknown: - fsCombo.remove(len(fsCombo.get_model()) - 1) - - # FIXME: What do we do if we can't figure it out? + typeCombo.remove(btrfs_pos) + + md_pos = None + btrfs_pos = None + partition_pos = None + lvm_pos = None + for idx, itr in enumerate(typeCombo.get_model()): + if itr[0] == DEVICE_TEXT_BTRFS: + btrfs_pos = idx + elif itr[0] == DEVICE_TEXT_MD: + md_pos = idx + elif itr[0] == DEVICE_TEXT_PARTITION: + partition_pos = idx + elif itr[0] == DEVICE_TEXT_LVM: + lvm_pos = idx + raid_level = None if use_dev.type == "lvmlv": # TODO: striping/mirroring - typeCombo.set_active(DEVICE_TYPE_LVM) + typeCombo.set_active(lvm_pos) elif use_dev.type == "mdarray": - typeCombo.set_active(DEVICE_TYPE_MD) + typeCombo.set_active(md_pos) raid_level = mdraid.raidLevelString(use_dev.level) elif use_dev.type == "partition": - typeCombo.set_active(DEVICE_TYPE_PARTITION) + typeCombo.set_active(partition_pos) elif use_dev.type.startswith("btrfs"): - typeCombo.set_active(DEVICE_TYPE_BTRFS) + typeCombo.set_active(btrfs_pos) if hasattr(use_dev, "volume"): raid_level = use_dev.volume.dataLevel or "single" else: @@ -1372,14 +1455,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): # you can't change the type of an existing device typeCombo.set_sensitive(not device.exists)
- # FIXME: What do we do if we can't figure it out? - model = fsCombo.get_model() - for i in range(0, len(model)): - if model[i][0] == device.format.name: - fsCombo.set_active(i) - break - - self._populate_raid(typeCombo.get_active(), raid_level, device.size) + self._populate_raid(raid_level, device.size) self.builder.get_object("optionsNotebook").set_sensitive(not device.exists)
### @@ -1744,10 +1820,13 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): return
new_type = combo.get_active_text() + if new_type is None: + return log.debug("fs type changed: %s" % new_type) fmt = getFormat(new_type) mountPointEntry = self.builder.get_object("mountPointEntry") labelEntry = self.builder.get_object("labelEntry") + # FIXME: can't set a label on an existing format as of now labelEntry.set_sensitive(hasattr(fmt, "label")) mountPointEntry.set_sensitive(fmt.mountable)
@@ -1755,9 +1834,11 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): if not self._initialized: return
- new_type = combo.get_active() + new_type = self._get_current_device_type() log.debug("device_type_changed: %s %s" % (new_type, combo.get_active_text())) + if new_type is None: + return
# if device type is not btrfs we want to make sure btrfs is not in the # fstype combo @@ -1782,19 +1863,27 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): raid_level = "raid0"
size = self.builder.get_object("sizeSpinner").get_value() - self._populate_raid(new_type, raid_level, size) + self._populate_raid(raid_level, size)
# begin btrfs magic fsCombo = self.builder.get_object("fileSystemTypeCombo") model = fsCombo.get_model() - btrfs_included = "btrfs" in [f[0] for f in model] - active_index = 0 + btrfs_included = False + btrfs_pos = None + for idx, data in enumerate(model): + if data[0] == "btrfs": + btrfs_included = True + btrfs_pos = idx + + active_index = fsCombo.get_active() + fstype = fsCombo.get_active_text() if btrfs_included and not include_btrfs: for i in range(0, len(model)): - if model[i][0] == self.storage.defaultFSType: + if fstype == "btrfs" and \ + model[i][0] == self.storage.defaultFSType: active_index = i break - fsCombo.remove(len(model) - 1) # remove btrfs, which is always last + fsCombo.remove(btrfs_pos) elif include_btrfs and not btrfs_included: fsCombo.append_text("btrfs") active_index = len(fsCombo.get_model()) - 1
--- pyanaconda/ui/gui/spokes/custom.py | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/custom.py b/pyanaconda/ui/gui/spokes/custom.py index 6eb881b..15d01a9 100644 --- a/pyanaconda/ui/gui/spokes/custom.py +++ b/pyanaconda/ui/gui/spokes/custom.py @@ -1260,7 +1260,12 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): raid_level=base_level)
widget_dict = self._get_raid_widget_dict(device_type) - base_size = factory.device_size + try: + base_size = factory.device_size + except ValueError as e: + log.error("failed to populate UI raid options: %s" % e) + return + active = raid_level_features[raid_level] disabled = self._get_raid_disabled_features(raid_level) for feature in raid_features:
--- pyanaconda/ui/gui/spokes/custom.py | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/custom.py b/pyanaconda/ui/gui/spokes/custom.py index 15d01a9..2c9df36 100644 --- a/pyanaconda/ui/gui/spokes/custom.py +++ b/pyanaconda/ui/gui/spokes/custom.py @@ -996,7 +996,8 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): # you can't change the type of an existing device, so we # don't need to concern ourselves with adding a new # selector to the new page - selector.props.mountpoint = mountpoint + selector.props.mountpoint = (mountpoint or + selector._device.format.name) selector.props.name = (self._mountpointName(mountpoint) or selector._device.format.name)
@@ -1112,7 +1113,8 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): self.window.show_all() else: if old_mountpoint: - selector.props.mountpoint = mountpoint + selector.props.mountpoint = (mountpoint or + selector._device.format.name) selector.props.name = (self._mountpointName(mountpoint) or selector._device.format.name) else:
--- pyanaconda/storage/partitioning.py | 20 ++++++++++++++++++-- 1 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/pyanaconda/storage/partitioning.py b/pyanaconda/storage/partitioning.py index 7528ed3..ee3c997 100644 --- a/pyanaconda/storage/partitioning.py +++ b/pyanaconda/storage/partitioning.py @@ -1583,7 +1583,15 @@ class TotalSizeSet(object): size has been achieved. """ def __init__(self, devices, size): - self.devices = devices + self.devices = [] + for device in devices: + if isinstance(device, LUKSDevice): + partition = device.slave + else: + partition = device + + self.devices.append(partition) + self.size = size
self.requests = [] @@ -1608,7 +1616,15 @@ class TotalSizeSet(object): class SameSizeSet(object): """ Set of device requests with a common target size. """ def __init__(self, devices, size, grow=False, max_size=None): - self.devices = devices + self.devices = [] + for device in devices: + if isinstance(device, LUKSDevice): + partition = device.slave + else: + partition = device + + self.devices.append(partition) + self.size = int(size / len(devices)) self.grow = grow self.max_size = max_size
--- pyanaconda/storage/formats/fs.py | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/pyanaconda/storage/formats/fs.py b/pyanaconda/storage/formats/fs.py index f4afea7..a5d8dc7 100644 --- a/pyanaconda/storage/formats/fs.py +++ b/pyanaconda/storage/formats/fs.py @@ -999,6 +999,10 @@ class Ext2FS(FS): if size is None: log.warning("failed to get minimum size for %s filesystem " "on %s" % (self.mountType, self.device)) + else: + orig_size = size + size = min(size * 1.1, size + 500) + log.debug("padding min size from %d up to %d" % (orig_size, size))
self._minInstanceSize = size
@@ -1397,7 +1401,8 @@ class NTFS(FS): log.warning("Unable to discover minimum size of filesystem " "on %s" %(self.device,)) else: - size = minSize + size = min(minSize * 1.1, minSize + 500) + log.debug("padding min size from %d up to %d" % (minSize, size))
self._minInstanceSize = size
/boot can be on btrfs or lvm. This should be handled in the ui. --- pyanaconda/storage/__init__.py | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-)
diff --git a/pyanaconda/storage/__init__.py b/pyanaconda/storage/__init__.py index 19d76e3..6f60ec4 100644 --- a/pyanaconda/storage/__init__.py +++ b/pyanaconda/storage/__init__.py @@ -2013,9 +2013,6 @@ class Storage(object):
if fstype == "swap" and device_type == AUTOPART_TYPE_BTRFS: device_type = AUTOPART_TYPE_PLAIN - elif device_type != AUTOPART_TYPE_PLAIN and \ - mountpoint and mountpoint.startswith("/boot"): - device_type = AUTOPART_TYPE_PLAIN
fmt_args = {} if label:
--- pyanaconda/storage/devicelibs/btrfs.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/pyanaconda/storage/devicelibs/btrfs.py b/pyanaconda/storage/devicelibs/btrfs.py index f114ba4..0aab1d0 100644 --- a/pyanaconda/storage/devicelibs/btrfs.py +++ b/pyanaconda/storage/devicelibs/btrfs.py @@ -42,7 +42,7 @@ def btrfs(args, capture=False): kwargs["stdout"] = "/dev/tty5"
ret = exec_func("btrfs", args, **kwargs) - if ret: + if ret and not capture: raise BTRFSError(ret) return ret
Catch some common errors that are not practical to prevent via the UI and show an error message instead of attempting to carry out the request. --- pyanaconda/ui/gui/spokes/custom.py | 40 +++++++++++++++++++++++++++++------ 1 files changed, 33 insertions(+), 7 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/custom.py b/pyanaconda/ui/gui/spokes/custom.py index 2c9df36..114cffb 100644 --- a/pyanaconda/ui/gui/spokes/custom.py +++ b/pyanaconda/ui/gui/spokes/custom.py @@ -134,6 +134,9 @@ feature_raid_levels = {"Performance": "raid0", "DistError": "raid5", "RedundantError": "raid6"}
+partition_only_format_types = ["efi", "hfs+", "prepboot", "biosboot", + "appleboot"] + class UIStorageFilter(logging.Filter): def filter(self, record): record.name = "storage.ui" @@ -895,10 +898,34 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): if error: self._error = mountpoint_validation_msgs[error] self.window.set_info(Gtk.MessageType.WARNING, self._error) + self.window.show_all() return
raid_level = self._get_raid_level()
+ fs_type_short = getFormat(fs_type).type + + ## + ## VALIDATION + ## + error = None + if device_type != AUTOPART_TYPE_PLAIN and mountpoint == "/boot/efi": + error = (_("/boot/efi must be on a device of type %s") + % DEVICE_TEXT_PARTITION) + elif device_type != AUTOPART_TYPE_PLAIN and \ + fs_type_short in partition_only_format_types: + error = (_("%s must be on a device of type %s") + % (fs_type, DEVICE_TEXT_PARTITION)) + elif mountpoint and encrypted and mountpoint.startswith("/boot"): + error = _("%s cannot be encrypted") % mountpoint + elif encrypted and fs_type_short in partition_only_format_types: + error = _("%s cannot be encrypted") % fs_type + + if error: + self.window.set_info(Gtk.MessageType.WARNING, error) + self.window.show_all() + return + with ui_storage_logger(): # create a new factory using the appropriate size and type factory = self.__storage.getDeviceFactory(device_type, size, @@ -1422,8 +1449,8 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): typeCombo.remove(md_pos)
# if the format is swap the device type can't be btrfs - include_btrfs = use_dev.format.type not in ("swap", "prepboot", - "biosboot") + include_btrfs = (use_dev.format.type not in + partition_only_format_types + ["swap"]) if include_btrfs and not btrfs_included: typeCombo.append_text(DEVICE_TEXT_BTRFS) elif btrfs_included and not include_btrfs: @@ -1524,17 +1551,16 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): mountpoint = None
device_type = self.data.autopart.type - if device_type == AUTOPART_TYPE_LVM and \ + if device_type != AUTOPART_TYPE_PLAIN and \ mountpoint == "/boot/efi": device_type = AUTOPART_TYPE_PLAIN - elif device_type == AUTOPART_TYPE_BTRFS and \ - (fstype in ("swap", "biosboot", "prepboot") or \ - (mountpoint and mountpoint.startswith("/boot"))): + elif device_type != AUTOPART_TYPE_PLAIN and \ + fstype in partition_only_format_types: device_type = AUTOPART_TYPE_PLAIN
# some devices should never be encrypted if ((mountpoint and mountpoint.startswith("/boot")) or - fstype in ("biosboot", "prepboot")): + fstype in partition_only_format_types): encrypted = False
disks = self._clearpartDevices
On Tue, Oct 09, 2012 at 05:23:58PM -0500, David Lehman wrote:
BTRFS and RAID are not always in the device type combo, so we can't count on using direct index access to the combo.
pyanaconda/ui/gui/spokes/custom.py | 181 +++++++++++++++++++++++++++--------- 1 files changed, 135 insertions(+), 46 deletions(-)
All these patches look ok. I don't really like the translated compares in 1/8, but I don't think there's much else you can do.
anaconda-patches@lists.fedorahosted.org