This adds the ability to create new partitions for swap or mountable filesystem of the default type (currently ext4).
Size input is passed directly to Size ctor via spec=, so to get 20GB you enter something like '20GB' or '20 gb'. Entering a size of 0 or no size spec at all will get you the default partition size, which is 500MB.
Very basic validation is done on mountpoints as well, but there is no feedback -- we just don't create anything if there's a problem.
--- pyanaconda/storage/size.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/pyanaconda/storage/size.py b/pyanaconda/storage/size.py index 1906ee0..eb3e2e4 100644 --- a/pyanaconda/storage/size.py +++ b/pyanaconda/storage/size.py @@ -185,7 +185,7 @@ class Size(Decimal): check = _makeSpecs(prefix, abbr)
if spec in check: - return self / Decimal(factor) + return Decimal(self / Decimal(factor))
return None
--- pyanaconda/ui/gui/spokes/storage.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/storage.py b/pyanaconda/ui/gui/spokes/storage.py index e0d98b0..95d1454 100644 --- a/pyanaconda/ui/gui/spokes/storage.py +++ b/pyanaconda/ui/gui/spokes/storage.py @@ -242,7 +242,8 @@ class StorageChecker(object): def checkStorage(self): communication.send_message(self._mainSpokeClass, _("Checking storage configuration...")) - (self.errors, self.warnings) = self.storage.sanityCheck() + (StorageChecker.errors, + StorageChecker.warnings) = self.storage.sanityCheck() communication.send_ready(self._mainSpokeClass)
class StorageSpoke(NormalSpoke, StorageChecker):
--- pyanaconda/ui/gui/spokes/custom.py | 66 +++++++++++++++++++++++++++++++++--- 1 files changed, 61 insertions(+), 5 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/custom.py b/pyanaconda/ui/gui/spokes/custom.py index 4be9ed2..899fdc5 100644 --- a/pyanaconda/ui/gui/spokes/custom.py +++ b/pyanaconda/ui/gui/spokes/custom.py @@ -32,10 +32,14 @@ _ = lambda x: gettext.ldgettext("anaconda", x) N_ = lambda x: x P_ = lambda x, y, z: gettext.ldngettext("anaconda", x, y, z)
+from pykickstart.constants import * + from pyanaconda.product import productName, productVersion from pyanaconda.storage.formats import device_formats from pyanaconda.storage.size import Size from pyanaconda.storage import Root +from pyanaconda.storage.partitioning import doPartitioning +from pyanaconda.storage.errors import StorageError
from pyanaconda.ui.gui import UIObject from pyanaconda.ui.gui.spokes import NormalSpoke @@ -56,10 +60,23 @@ class AddDialog(UIObject): mainWidgetName = "addDialog" uiFile = "spokes/custom.ui"
+ def __init__(self, *args, **kwargs): + UIObject.__init__(self, *args, **kwargs) + self.size = Size(bytes=0) + self.mountpoint = "" + def on_add_cancel_clicked(self, button, *args): self.window.destroy()
def on_add_confirm_clicked(self, button, *args): + self.mountpoint = self.builder.get_object("addMountPointEntry").get_text() + + size_text = self.builder.get_object("sizeEntry").get_text() + try: + self.size = Size(spec=size_text) + except Exception: + pass + self.window.destroy()
def refresh(self): @@ -110,6 +127,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): self._when_create_text = ""
def apply(self): + self.storage.setUpBootLoader() StorageChecker.run(self)
@property @@ -292,7 +310,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): page.show_all() self._accordion.addPage(page, cb=self.on_page_clicked)
- if not did_expand and self._current_selector and root.name == self._current_selector._root.name: + if not did_expand and getattr(self._current_selector, "_root", None) and root.name == self._current_selector._root.name: did_expand = True self._accordion.expandPage(root.name)
@@ -414,9 +432,47 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): dialog.refresh() rc = dialog.run()
- if rc == 1: - # FIXME: Do creation. - pass + if rc != 1: + # user cancel + return + + # create a device of the default type, using any disks, with an + # appropriate fstype and mountpoint + mountpoint = dialog.mountpoint + size = dialog.size + fstype = self.storage.defaultFSType + if mountpoint.lower() == "swap": + fstype = "swap" + mountpoint = None + elif mountpoint == "/boot": + fstype = self.storage.defaultBootFSType + elif mountpoint == "/boot/efi": + if iutil.isMactel(): + fstype = "hfs+" + else: + fstype = "efi" + elif not mountpoint or not mountpoint.startswith("/"): + return + + if not size: + # no size specified, so use the default size + size = None + + if self.data.autopart.type == AUTOPART_TYPE_PLAIN: + # create a partition for this new filesystem + size_mb = float(size.convertTo(spec="mb")) + device = self.storage.newPartition(size=size_mb, + fmt_type=fstype, + mountpoint=mountpoint) + self.storage.createDevice(device) + try: + doPartitioning(self.storage) + except StorageError as e: + actions = self.storage.devicetree.findActions(device=device) + for a in reversed(actions): + self.storage.devicetree.cancelAction(a) + else: + self._do_refresh()
def _destroy_device(self, device): # if this device has parents with no other children, remove them too @@ -476,7 +532,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
# If the root is now empty, remove it. Devices from the Unused page # will have no root. - if self.storage.roots and root and len(root.swaps + root.mounts.values()) == 0: + if root and root in self.storage.roots and len(root.swaps + root.mounts.values()) == 0: self.storage.roots.remove(root)
self._update_ui_for_removals()
@@ -414,9 +432,47 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker): dialog.refresh() rc = dialog.run()
if rc == 1:# FIXME: Do creation.pass
if rc != 1:# user cancelreturn# create a device of the default type, using any disks, with an# appropriate fstype and mountpointmountpoint = dialog.mountpointsize = dialog.sizefstype = self.storage.defaultFSTypeif mountpoint.lower() == "swap":fstype = "swap"mountpoint = Noneelif mountpoint == "/boot":fstype = self.storage.defaultBootFSTypeelif mountpoint == "/boot/efi":if iutil.isMactel():fstype = "hfs+"else:fstype = "efi"elif not mountpoint or not mountpoint.startswith("/"):return
This reminds me an awful lot of code we have in the PartitionData class out of kickstart.py. I don't suppose there's a good way to combine the two, though.
- Chris
Size input is passed directly to Size ctor via spec=, so to get 20GB you enter something like '20GB' or '20 gb'. Entering a size of 0 or no size spec at all will get you the default partition size, which is 500MB.
Can we make this discoverable somehow - like perhaps a pop up if you hover the mouse over the entry field? Otherwise, I don't know that we have any way for the user to figure this out.
- Chris
anaconda-patches@lists.fedorahosted.org