Partition resizing, take 2

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Okay, newer patch implementing resizing.  Still against an older tree
(726a485e58706b70c8fb2b9d4febe938a7c88963) but just to get it out there
while I work on the fun of rebasing to the current code and merging with
dlehman's encryption bits.

The patch implements the following:
1) Adds "pulsing progress bars" for GUI where you have the progress bar
bounce due to something taking an indeterminate amount of time.  We
should also be able to use this for other filesystem creation options
that we don't know how long they take.  For text mode, this just gives a
message and no progress bar
2) Moves writing out partitioning and mounting filesystems to be right
after the partitioning screen.  Note: this still needs something to let
the user know that their changes are going to be done immediately
3) Adds support for resizing partitions in the autopart loop.  This
requires the pyparted patch which I sent last time
4) Determines the maximum size a partition can be grown to
5) Adds support for resizing ext[23] filesystems and determining the
minimum size of the ext[23] filesystem
6) Cleans up the graphical UI when editing a pre-existing partition and
adds support for resize.  Contrast
http://katzj.fedorapeople.org/resize-poc.png to
http://katzj.fedorapeople.org/new-edit-part-dialog.png

At this point, I'm pretty happy with how things are looking and am
probably going to go ahead and commit once I get things rebased unless
anyone has any strong concerns.  There are still some more things which
can be done, but they can be easily done as small follow-up patches.

Jeremy
diff --git a/autopart.py b/autopart.py
index 8886241..9036224 100644
--- a/autopart.py
+++ b/autopart.py
@@ -865,6 +865,23 @@ def setPreexistParts(diskset, requests):
         part = disk.next_partition()
         while part:
             if part.geom.start == request.start and part.geom.end == request.end:
+                # if the partition is being resized, we do that now
+                if request.targetSize is not None:
+                    startSec = part.geom.start
+                    endSec = part.geom.start + long(((request.targetSize * 1024L * 1024L) / disk.dev.sector_size)) - 1
+
+                    try:
+                        g = part.geom.duplicate()
+                        g.set_end(endSec)
+                        constraint = g.constraint_exact()
+                        part.set_geometry(constraint, startSec, endSec)
+                    except parted.error, msg:
+                        log.error("error setting geometry for partition %s: %s" %(partedUtils.get_partition_name(part), msg))
+                        raise PartitioningError, _("Error resizing partition %s.\n\n%s") %(partedUtils.get_partition_name(part), msg)
+
+                    if startSec != part.geom.start:
+                        raise PartitioningError, _("Start of partition %s was moved when resizing") %(partedUtils.get_partition_name(part),)
+
                 request.device = partedUtils.get_partition_name(part)
                 if request.fstype:
                     if request.fstype.getName() != request.origfstype.getName():
@@ -987,13 +1004,18 @@ def processPartitioning(diskset, requests, newParts):
     for request in requests.requests:
         if request.type == REQUEST_RAID:
             request.size = request.getActualSize(requests, diskset)
-        if request.type == REQUEST_VG:
+        elif request.type == REQUEST_VG:
             request.size = request.getActualSize(requests, diskset)
-        if request.type == REQUEST_LV:
+        elif request.type == REQUEST_LV:
 	    if request.grow:
 		request.setSize(request.getStartSize())
 	    else:
 		request.size = request.getActualSize(requests, diskset)
+        elif request.preexist:
+            # we need to keep track of the max size of preexisting partitions
+            # FIXME: we should also get the max size for LVs at some point
+            part = partedUtils.get_partition_by_name(diskset.disks, request.device)
+            request.maxSize = partedUtils.getMaxAvailPartSizeMB(part)
 
 ##     print "disk layout after everything is done"
 ##     print diskset.diskState()
diff --git a/cmdline.py b/cmdline.py
index c343eb9..972ce9c 100644
--- a/cmdline.py
+++ b/cmdline.py
@@ -38,6 +38,9 @@ class ProgressWindow:
     def pop(self):
         print ""
 
+    def pulse(self):
+        pass
+
     def set(self, amount):
         if amount == self.total:
             print _("Completed"),
@@ -45,7 +48,7 @@ class ProgressWindow:
     def refresh(self):
         pass
 
-    def __init__(self, title, text, total, updpct = 0.05):
+    def __init__(self, title, text, total, updpct = 0.05, pulse = False):
         self.total = total
         print text
         print _("In progress...   "),
@@ -61,8 +64,8 @@ class InstallInterface:
     def shutdown(self):
         pass
 
-    def progressWindow(self, title, text, total, updpct = 0.05):
-        return ProgressWindow(title, text, total, updpct)
+    def progressWindow(self, title, text, total, updpct = 0.05, pulse = False):
+        return ProgressWindow(title, text, total, updpct, pulse)
 
     def kickstartErrorWindow(self, text):
         s = _("The following error was found while parsing your "
diff --git a/dispatch.py b/dispatch.py
index 5775108..8d36483 100644
--- a/dispatch.py
+++ b/dispatch.py
@@ -78,8 +78,10 @@ installSteps = [
     ("upgradeswapsuggestion", upgradeSwapSuggestion, ),
     ("addswap", ),
     ("partitiondone", partitioningComplete, ),
+    ("enablefilesystems", turnOnFilesystems, ),
     ("upgrademigfind", upgradeMigrateFind, ),
     ("upgrademigratefs", ),
+    ("migratefilesystems", doMigrateFilesystems, ),
     ("upgbootloader", ),
     ("bootloadersetup", bootloaderSetupChoices, ),
     ("bootloader", ),
@@ -96,8 +98,6 @@ installSteps = [
     ("confirminstall", ),
     ("confirmupgrade", ),
     ("install", ),
-    ("enablefilesystems", turnOnFilesystems, ),
-    ("migratefilesystems", doMigrateFilesystems, ),
     ("setuptime", setupTimezone, ),
     ("preinstallconfig", doPreInstall, ),
     ("installpackages", doInstall, ),
diff --git a/fsset.py b/fsset.py
index 61ba6a0..9141411 100644
--- a/fsset.py
+++ b/fsset.py
@@ -2,6 +2,7 @@
 # fsset.py: filesystem management
 #
 # Matt Wilson <msw@xxxxxxxxxx>
+# Jeremy Katz <katzj@xxxxxxxxxx>
 #
 # Copyright 2001-2007 Red Hat, Inc.
 #
@@ -13,6 +14,7 @@
 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 #
 
+import math
 import string
 import isys
 import iutil
@@ -177,10 +179,18 @@ class FileSystemType:
         self.extraFormatArgs = []
         self.maxLabelChars = 16
         self.packages = []
+        self.resizable = False
         self.supportsFsProfiles = False
         self.fsProfileSpecifier = None
         self.fsprofile = None
 
+    def isResizable(self):
+        return self.resizable
+    def resize(self, entry, size, progress, chroot='/'):
+        pass
+    def getMinimumSize(self, device):
+        pass
+
     def isKernelFS(self):
         """Returns True if this is an in-kernel pseudo-filesystem."""
         return False
@@ -505,6 +515,81 @@ class extFileSystem(FileSystemType):
         self.packages = [ "e2fsprogs" ]
         self.supportsFsProfiles = True
         self.fsProfileSpecifier = "-T"
+        self.resizable = True
+
+    def resize(self, entry, size, progress, chroot='/'):
+        devicePath = entry.device.setupDevice(chroot)
+
+        log.info("checking %s prior to resize" %(devicePath,))
+        w = None
+        if progress:
+            w = progress(_("Checking"),
+                         _("Checking filesystem on %s...") %(devicePath), 
+                         100, pulse = True)
+            
+        rc = iutil.execWithPulseProgress("e2fsck", ["-f", "-p", "-C", "0", devicePath],
+                                         stdout="/dev/tty5", 
+                                         stderr="/dev/tty5", progress = w)
+        if rc >= 4:
+            raise RuntimeError, "Check of %s failed" %(devicePath,)
+        if progress:
+            w.pop()
+            w = progress(_("Resizing"),
+                         _("Resizing filesystem on %s...") %(devicePath), 
+                         100, pulse = True)
+
+        log.info("resizing %s" %(devicePath,))
+        rc = iutil.execWithPulseProgress("resize2fs", 
+                                         ["-p", devicePath, "%sM" %(size,)],
+                                         stdout="/dev/tty5", stderr="/dev/tty5",
+                                         progress = w)
+        if progress:
+            w.pop()
+        if rc:
+            raise RuntimeError, "Resize of %s failed" %(devicePath,)
+
+    def getMinimumSize(self, device):
+        """Return the minimum filesystem size in megabytes"""
+        devicePath = "/dev/%s" % (device,)
+        if not os.path.exists(devicePath):
+            isys.makeDevInode(device, devicePath)
+
+        # FIXME: it'd be nice if we didn't have to parse this out ourselves
+        buf = iutil.execWithCapture("/tmp/updates/dumpe2fs",
+                                    ["-h", devicePath],
+                                    stderr = "/dev/tty5")
+        blocks = free = bs = 0
+        for l in buf.split("\n"):
+            if l.startswith("Free blocks"):
+                try:
+                    free = l.split()[2]
+                    free = int(free)
+                except Exception, e:
+                    log.warning("error determining free blocks on %s: %s" %(devicePath, e))
+                    free = 0
+            elif l.startswith("Block size"):
+                try:
+                    bs = l.split()[2]
+                    bs = int(bs)
+                except Exception, e:
+                    log.warning("error determining block size of %s: %s" %(devicePath, e))
+                    bs = 0
+            elif l.startswith("Block count"):
+                try:
+                    blocks = l.split()[2]
+                    blocks = int(blocks)
+                except Exception, e:
+                    log.warning("error determining block count of %s: %s" %(devicePath, e))
+                    blocks = 0
+
+        if free == 0 or bs == 0:
+            log.warning("Unable to determinine minimal size for %s", devicePath)
+            return 1
+
+        used = math.ceil((blocks - free) * bs / 1024.0 / 1024.0)
+        log.info("used size of %s is %s" %(devicePath, used))
+        # FIXME: should we bump this beyond the absolute minimum?
+        return used
 
     def labelDevice(self, entry, chroot):
         devicePath = entry.device.setupDevice(chroot)
@@ -1376,6 +1461,24 @@ MAILADDR root
             if bootPart:
                 del bootPart
 
+    def resizeFilesystems (self, chroot = '/', shrink = False, grow = False):
+        for entry in self.entries:
+            if not entry.fsystem or not entry.fsystem.isResizable():
+                continue
+            if entry.resizeTargetSize is None:
+                continue
+            if shrink and not (entry.resizeTargetSize < entry.resizeOrigSize):
+                continue
+            if grow and not (entry.resizeTargetSize > entry.resizeOrigSize):
+                continue
+            entry.fsystem.resize(entry, entry.resizeTargetSize,
+                                 self.progressWindow, chroot)
+
+    def shrinkFilesystems (self, chroot):
+        self.resizeFilesystems(chroot, shrink = True)
+    def growFilesystems (self, chroot):
+        self.resizeFilesystems(chroot, grow = True)
+
     def formatSwap (self, chroot, forceFormat=False):
         formatted = []
         notformatted = []
@@ -1826,6 +1929,8 @@ class FileSystemSetEntry:
         self.fsystem = fsystem
         self.origfsystem = origfsystem
         self.migrate = migrate
+        self.resizeTargetSize = None
+        self.resizeOrigSize = None
         self.options = options
         self.mountcount = 0
         self.label = None
@@ -1907,6 +2012,15 @@ class FileSystemSetEntry:
     def getMigrate (self):
         return self.migrate
 
+    def setResizeTarget (self, targetsize, size):
+        if not self.fsystem.isResizable() and targetsize is not None:
+            raise ValueError, "Can't set a resize target for a non-resizable filesystem"
+        self.resizeTargetSize = targetsize
+        self.resizeOrigSize = size
+
+    def getResizeTarget (self):
+        return self.targetsize
+
     def isMounted (self):
         return self.mountcount > 0
 
diff --git a/gui.py b/gui.py
index b8ebb63..686ba76 100755
--- a/gui.py
+++ b/gui.py
@@ -511,7 +511,7 @@ class WaitWindow:
 
 class ProgressWindow:
     def __init__(self, title, text, total, updpct = 0.05, updsecs=10,
-                 parent = None):
+                 parent = None, pulse = False):
         if flags.rootpath or not runningMiniWm():
             self.window = gtk.Window()
             if parent:
@@ -543,6 +543,11 @@ class ProgressWindow:
     def refresh(self):
         processEvents()
 
+    def pulse(self):
+        self.progress.set_pulse_step(self.updpct)
+        self.progress.pulse()
+        processEvents()
+
     def set (self, amount):
         # only update widget if we've changed by 5% or our timeout has
         # expired
@@ -940,11 +945,12 @@ class InstallInterface:
         else:
             return WaitWindow (title, text)
 
-    def progressWindow (self, title, text, total, updpct = 0.05):
+    def progressWindow (self, title, text, total, updpct = 0.05, pulse = False):
         if self.icw:
-            return ProgressWindow (title, text, total, updpct, self.icw.window)
+            return ProgressWindow (title, text, total, updpct,
+                                   parent = self.icw.window, pulse = pulse)
         else:
-            return ProgressWindow (title, text, total, updpct)
+            return ProgressWindow (title, text, total, updpct, pulse = pulse)
 
     def packageProgressWindow (self, total, totalSize):
         self.ppw.setSizes (total, totalSize)
diff --git a/iutil.py b/iutil.py
index 926b0c6..f617487 100644
--- a/iutil.py
+++ b/iutil.py
@@ -96,6 +96,66 @@ def execWithCapture(command, argv, stdin = 0, stderr = 2, root='/'):
     pipe.wait()
     return rc
 
+def execWithPulseProgress(command, argv, stdin = 0, stdout = 1, stderr = 2,
+                          progress = None, root = '/'):
+    def chroot():
+        os.chroot(root)
+
+    argv = list(argv)
+    if type(stdin) == type("string"):
+        if os.access(stdin, os.R_OK):
+            stdin = open(stdin)
+        else:
+            stdin = 0
+    if type(stdout) == type("string"):
+        stdout = open(stdout, "w")
+    if type(stderr) == type("string"):
+        stderr = open(stderr, "w")
+
+    p = os.pipe()
+    childpid = os.fork()
+    if not childpid:
+        os.close(p[0])
+        os.dup2(p[1], 1)
+        os.dup2(stderr.fileno(), 2)
+        os.close(p[1])
+        stderr.close()
+
+        os.execvp(command, [command] + argv)
+        os._exit(1)
+
+    os.close(p[1])
+
+    while 1:
+        try:
+            s = os.read(p[0], 1)
+        except OSError, args:
+            (num, str) = args
+            if (num != 4):
+                raise IOError, args
+
+        stdout.write(s)
+        if progress: progress.pulse()
+
+        if len(s) < 1:
+            break
+
+    try:
+        (pid, status) = os.waitpid(childpid, 0)
+    except OSError, (num, msg):
+        log.critical("exception from waitpid: %s %s" %(num, msg))
+
+    progress and progress.pop()
+
+    # *shrug*  no clue why this would happen, but hope that things are fine
+    if status is None:
+        return 0
+
+    if os.WIFEXITED(status):
+        return os.WEXITSTATUS(status)
+
+    return 1
+
 ## Run a shell.
 def execConsole():
     try:
diff --git a/iw/lvm_dialog_gui.py b/iw/lvm_dialog_gui.py
index ae9c614..5368598 100644
--- a/iw/lvm_dialog_gui.py
+++ b/iw/lvm_dialog_gui.py
@@ -479,25 +479,15 @@ class VolumeGroupEditor:
                 format = 1
                 migrate = 0
             else:
-		if self.fsoptionsDict.has_key("formatrb"):
-		    formatrb = self.fsoptionsDict["formatrb"]
-		else:
-		    formatrb = None
-
-		if formatrb:
-                    format = formatrb.get_active()
+		if self.fsoptionsDict.has_key("formatcb"):
+                    format = self.fsoptionsDict["formatcb"].get_active()
                     if format:
                         fsystem = self.fsoptionsDict["fstypeCombo"].get_active_value()
                 else:
                     format = 0
 
-		if self.fsoptionsDict.has_key("migraterb"):
-		    migraterb = self.fsoptionsDict["migraterb"]
-		else:
-		    migraterb = None
-		    
-		if migraterb:
-                    migrate = migraterb.get_active()
+		if self.fsoptionsDict.has_key("migratecb"):
+		    migrate = self.fsoptionsDict["migratecb"].get_active()
                     if migrate:
                         fsystem = self.fsoptionsDict["migfstypeCombo"].get_active_value()
                 else:
diff --git a/iw/partition_dialog_gui.py b/iw/partition_dialog_gui.py
index 042be17..69849c3 100644
--- a/iw/partition_dialog_gui.py
+++ b/iw/partition_dialog_gui.py
@@ -190,30 +190,26 @@ class PartitionEditor:
                 # preexisting partition, just set mount point and format flag
                 request = copy.copy(self.origrequest)
 		
-		if self.fsoptionsDict.has_key("formatrb"):
-		    formatrb = self.fsoptionsDict["formatrb"]
-		else:
-		    formatrb = None
-
-		if formatrb:
-                    request.format = formatrb.get_active()
+		if self.fsoptionsDict.has_key("formatcb"):
+                    request.format = self.fsoptionsDict["formatcb"].get_active()
                     if request.format:
                         request.fstype = self.fsoptionsDict["fstypeCombo"].get_active_value()
                 else:
                     request.format = 0
 
-		if self.fsoptionsDict.has_key("migraterb"):
-		    migraterb = self.fsoptionsDict["migraterb"]
-		else:
-		    migraterb = None
-		    
-		if migraterb:
-                    request.migrate = migraterb.get_active()
+		if self.fsoptionsDict.has_key("migratecb"):
+                    request.migrate = self.fsoptionsDict["migratecb"].get_active()
                     if request.migrate:
                         request.fstype =self.fsoptionsDict["migfstypeCombo"].get_active_value()
                 else:
                     request.migrate = 0
 
+                if self.fsoptionsDict.has_key("resizecb") and self.fsoptionsDict["resizecb"].get_active():
+                    request.targetSize = self.fsoptionsDict["resizesb"].get_value_as_int()
+                else:
+                    request.targetSize = None
+                print "the target size for %s is %s" %(request.mountpoint, request.targetSize)
+
                 # set back if we are not formatting or migrating
 		origfstype = self.origrequest.origfstype
                 if not request.format and not request.migrate:
@@ -299,21 +295,6 @@ class PartitionEditor:
 	    lbl.set_mnemonic_widget(self.newfstypeCombo)
             maintable.attach(self.newfstypeCombo, 1, 2, row, row + 1)
         else:
-            maintable.attach(createAlignedLabel(_("Original File System "
-                                                  "Type:")),
-                             0, 1, row, row + 1)
-
-            if self.origrequest.origfstype:
-                typestr = self.origrequest.origfstype.getName()
-                if self.origrequest.origfstype.getName() == "foreign":
-                    part = get_partition_by_name(self.diskset.disks,
-                                                 self.origrequest.device)
-                    typestr = map_foreign_to_fsname(part.native_type)
-            else:
-                typestr = _("Unknown")
-
-            fstypelabel = gtk.Label(typestr)
-            maintable.attach(fstypelabel, 1, 2, row, row + 1)
             self.newfstypeCombo = None
             
         row = row + 1
@@ -417,10 +398,6 @@ class PartitionEditor:
                 cursize = (endsec - startsec)/2048
                 bycyl_sizelabel.set_text("%s" % (int(cursize)))
         else:
-            maintable.attach(createAlignedLabel(_("Size (MB):")),
-                             0, 1, row, row + 1)
-            sizelabel = gtk.Label("%d" % (origrequest.size))
-            maintable.attach(sizelabel, 1, 2, row, row + 1)
             self.sizespin = None
             
         row = row + 1
diff --git a/iw/partition_ui_helpers_gui.py b/iw/partition_ui_helpers_gui.py
index be66780..89a45d2 100644
--- a/iw/partition_ui_helpers_gui.py
+++ b/iw/partition_ui_helpers_gui.py
@@ -29,6 +29,11 @@ from partedUtils import *
 import rhpl
 from rhpl.translate import _, N_
 
+def istruefalse(val):
+    if val is None or not val:
+        return False
+    return True
+
 class WideCheckList(checklist.CheckList):
     def toggled_item(self, data, row):
 
@@ -206,6 +211,9 @@ def mountptchangeCB(widget, fstypecombo):
     if rhpl.getArch() == "ia64" and widget.get_children()[0].get_text() == "/boot/efi":
         fstypecombo.set_active_text("vfat")
 
+def resizeOptionCB(widget, resizesb):
+    resizesb.set_sensitive(widget.get_active())
+
 def formatOptionCB(widget, data):
     (combowidget, mntptcombo, ofstype) = data
     combowidget.set_sensitive(widget.get_active())
@@ -232,87 +240,80 @@ def noformatCB(widget, data):
 
     Returns the value of row after packing into the maintable,
     and a dictionary consistenting of:
-       noformatrb    - radiobutton for 'leave fs unchanged'
-       formatrb      - radiobutton for 'format as new fs'
+       noformatcb    - checkbutton for 'format as new fs'
        fstype        - part of format fstype menu
        fstypeMenu    - part of format fstype menu
-       migraterb     - radiobutton for migrate fs
-       migfstype     - menu for migrate fs types
+       migratecb     - checkbutton for migrate fs
        migfstypeMenu - menu for migrate fs types
+       resizecb      - checkbutton for 'resize fs'
+       resizesb      - spinbutton with resize target
 """
 def createPreExistFSOptionSection(origrequest, maintable, row, mountCombo,
                                   ignorefs=[]):
+    rc = {}
     ofstype = origrequest.fstype
 
-    maintable.attach(gtk.HSeparator(), 0, 2, row, row + 1)
-    row = row + 1
-
-    label = gtk.Label(_("How would you like to prepare the file system "
-		       "on this partition?"))
-    label.set_line_wrap(1)
-    label.set_alignment(0.0, 0.0)
+    formatcb = gtk.CheckButton(label=_("_Format as:"))
+    maintable.attach(formatcb, 0, 1, row, row + 1)
+    formatcb.set_active(istruefalse(origrequest.format))
+    rc["formatcb"] = formatcb
 
-    maintable.attach(label, 0, 2, row, row + 1)
-    row = row + 1
-
-    noformatrb = gtk.RadioButton(label=_("Leave _unchanged "
-					 "(preserve data)"))
-    noformatrb.set_active(1)
-    maintable.attach(noformatrb, 0, 2, row, row + 1)
-    row = row + 1
-
-    formatrb = gtk.RadioButton(label=_("_Format partition as:"),
-				    group=noformatrb)
-    formatrb.set_active(0)
-    if origrequest.format:
-	formatrb.set_active(1)
-
-    maintable.attach(formatrb, 0, 1, row, row + 1)
     fstypeCombo = createFSTypeMenu(ofstype, fstypechangeCB,
                                    mountCombo, ignorefs=ignorefs)
-    fstypeCombo.set_sensitive(formatrb.get_active())
+    fstypeCombo.set_sensitive(formatcb.get_active())
     maintable.attach(fstypeCombo, 1, 2, row, row + 1)
-    row = row + 1
+    row += 1
+    rc["fstypeCombo"] = fstypeCombo
 
-    if not formatrb.get_active() and not origrequest.migrate:
+    if not formatcb.get_active() and not origrequest.migrate:
 	mountCombo.set_data("prevmountable", ofstype.isMountable())
 
-    formatrb.connect("toggled", formatOptionCB,
-		     (fstypeCombo, mountCombo, ofstype))
+    formatcb.connect("toggled", formatOptionCB,
+                     (fstypeCombo, mountCombo, ofstype))
 
-    noformatrb.connect("toggled", noformatCB,
-		     (fstypeCombo, mountCombo, origrequest.origfstype))
 
     if origrequest.origfstype.isMigratable():
-	migraterb = gtk.RadioButton(label=_("Mi_grate partition to:"),
-				    group=noformatrb)
-	migraterb.set_active(0)
-	if origrequest.migrate:
-	    migraterb.set_active(1)
+	migratecb = gtk.CheckButton(label=_("Mi_grate filesystem to:"))
+        migratecb.set_active(istruefalse(origrequest.migrate))
 
 	migtypes = origrequest.origfstype.getMigratableFSTargets()
 
-	maintable.attach(migraterb, 0, 1, row, row + 1)
+	maintable.attach(migratecb, 0, 1, row, row + 1)
 	migfstypeCombo = createFSTypeMenu(ofstype, None, None,
                                           availablefstypes = migtypes)
-	migfstypeCombo.set_sensitive(migraterb.get_active())
+	migfstypeCombo.set_sensitive(migratecb.get_active())
 	maintable.attach(migfstypeCombo, 1, 2, row, row + 1)
-	row = row + 1
-
-	migraterb.connect("toggled", formatOptionCB,
+        row += 1
+	migratecb.connect("toggled", formatOptionCB,
                           (migfstypeCombo, mountCombo, ofstype))
-    else:
-	migraterb = None
-	migfstypeCombo = None
-
-    row = row + 1
-
-    rc = {}
-    for var in ['noformatrb', 'formatrb', 'fstypeCombo',
-                'migraterb', 'migfstypeCombo']:
-        if eval("%s" % (var,)) is not None:
-            rc[var] = eval("%s" % (var,))
-
+        rc["migratecb"] = migratecb
+        rc["migfstypeCombo"] = migfstypeCombo
+
+    # FIXME: we should support resizing LVs too
+    if origrequest.origfstype.isResizable() and origrequest.type == REQUEST_PREEXIST:
+        resizecb = gtk.CheckButton(label=_("_Resize partition"))
+        resizecb.set_active(origrequest.targetSize is not None)
+        rc["resizecb"] = resizecb
+        maintable.attach(resizecb, 0, 1, row, row + 1)
+
+        if origrequest.targetSize is not None:
+            value = origrequest.targetSize
+        else:
+            value = origrequest.size
+        adj = gtk.Adjustment(value = value,
+                             lower = origrequest.getMinimumResizeMB(),
+                             upper = origrequest.getMaximumResizeMB(),
+                             step_incr = 1)
+        resizesb = gtk.SpinButton(adj, digits = 0)
+        resizesb.set_property('numeric', True)
+        rc["resizesb"] = resizesb
+        maintable.attach(resizesb, 1, 2, row, row + 1)
+
+        resizecb.connect('toggled', resizeOptionCB, resizesb)
+        resizeOptionCB(resizecb, resizesb)
+
+        row += 1
+        
     return (row, rc)
 
 # do tests we just want in UI for now, not kickstart
diff --git a/iw/raid_dialog_gui.py b/iw/raid_dialog_gui.py
index 69e1cf6..09de387 100644
--- a/iw/raid_dialog_gui.py
+++ b/iw/raid_dialog_gui.py
@@ -167,27 +167,17 @@ class RaidEditor:
 		else:
 		    request.format = 0
 	    else:
-		if self.fsoptionsDict.has_key("formatrb"):
-		    formatrb = self.fsoptionsDict["formatrb"]
-		else:
-		    formatrb = None
-
-		if formatrb:
-                    request.format = formatrb.get_active()
+		if self.fsoptionsDict.has_key("formatcb"):
+                    request.format = self.fsoptionsDict["formatcb"].get_active()
                     if request.format:
-                        request.fstype = self.fsoptionsDict["fstypeCombo"].get_active_value()
+                        request.fsystem = self.fsoptionsDict["fstypeCombo"].get_active_value()
                 else:
                     request.format = 0
 
-		if self.fsoptionsDict.has_key("migraterb"):
-		    migraterb = self.fsoptionsDict["migraterb"]
-		else:
-		    migraterb = None
-		    
-		if migraterb:
-                    request.migrate = migraterb.get_active()
+		if self.fsoptionsDict.has_key("migratecb"):
+		    request.migrate = self.fsoptionsDict["migratecb"].get_active()
                     if request.migrate:
-                        request.fstype =self.fsoptionsDict["migfstypeCombo"].get_active_value()
+                        request.fsystem = self.fsoptionsDict["migfstypeCombo"].get_active_value()
                 else:
                     request.migrate = 0
 
diff --git a/packages.py b/packages.py
index aeefde2..09f3685 100644
--- a/packages.py
+++ b/packages.py
@@ -148,8 +148,10 @@ def turnOnFilesystems(anaconda):
                                        searchPath = 1)
             anaconda.id.partitions.doMetaDeletes(anaconda.id.diskset)
             anaconda.id.fsset.setActive(anaconda.id.diskset)
+            anaconda.id.fsset.shrinkFilesystems(anaconda.rootPath)
             if not anaconda.id.fsset.isActive():
                 anaconda.id.diskset.savePartitions ()
+            anaconda.id.fsset.growFilesystems(anaconda.rootPath)
             if not anaconda.id.fsset.volumesCreated:
                 anaconda.id.fsset.createLogicalVolumes(anaconda.rootPath)
             anaconda.id.fsset.formatSwap(anaconda.rootPath)
diff --git a/partRequests.py b/partRequests.py
index 3fbb812..fbb5e13 100644
--- a/partRequests.py
+++ b/partRequests.py
@@ -152,6 +152,9 @@ class RequestSpec:
         self.dev = None
         """A Device() as defined in fsset.py to correspond to this request."""
 
+        self.targetSize = None
+        """Size to resize to"""
+
     def __str__(self):
         if self.fstype:
             fsname = self.fstype.getName()
@@ -209,6 +212,9 @@ class RequestSpec:
         if self.fslabel:
             entry.setLabel(self.fslabel)
 
+        if self.targetSize and self.fstype.isResizable():
+            entry.setResizeTarget(self.targetSize, self.size)
+
         return entry
 
     def setProtected(self, val):
@@ -558,6 +564,18 @@ class PreexistingPartitionSpec(PartitionSpec):
                                mountpoint = mountpoint, preexist = 1)
         self.type = REQUEST_PREEXIST
 
+        self.maxResizeSize = None
+        """Maximum size of this partition request"""
+
+    def getMaximumResizeMB(self):
+        if self.maxResizeSize is not None:
+            return self.maxResizeSize
+        log.warning("%s doesn't have a max size set" %(self.device,))
+        return MAX_PART_SIZE
+
+    def getMinimumResizeMB(self):
+        return self.fstype.getMinimumSize(self.device)
+
 class RaidRequestSpec(RequestSpec):
     """Request to represent RAID devices."""
     
diff --git a/partedUtils.py b/partedUtils.py
index 273f372..a4bac97 100644
--- a/partedUtils.py
+++ b/partedUtils.py
@@ -96,6 +96,24 @@ def getDeviceSizeMB(dev):
     return (float(dev.heads * dev.cylinders * dev.sectors) / (1024 * 1024)
             * dev.sector_size)
 
+def getMaxAvailPartSizeMB(part):
+    """Return the maximum size this partition can grow to by looking
+    at contiguous freespace partitions."""
+
+    disk = part.disk
+    maxlen = part.geom.length
+
+    # let's look at the next partition(s) and if they're freespace,
+    # they can add to our maximum size.
+    np = disk.next_partition(part)
+    while np:
+        if np.type & parted.PARTITION_FREESPACE:
+            maxlen += np.geom.length
+        else:
+            break
+        np = disk.next_partition(np)
+    return math.floor(maxlen * part.geom.dev.sector_size / 1024.0 / 1024.0)
+
 def get_partition_by_name(disks, partname):
     """Return the parted part object associated with partname.  
 
diff --git a/partitions.py b/partitions.py
index 101b3f9..2d3fda0 100644
--- a/partitions.py
+++ b/partitions.py
@@ -101,30 +101,6 @@ def partitioningComplete(anaconda):
             raise RuntimeError, ("Managed to not get an entry back from "
                                  "request.toEntry")
 
-    if (not flags.setupFilesystems
-        or iutil.memAvailable() > isys.EARLY_SWAP_RAM):
-        return
-
-    if not anaconda.isKickstart:
-        rc = anaconda.intf.messageWindow(_("Low Memory"),
-                            _("As you don't have much memory in this "
-                              "machine, we need to turn on swap space "
-                              "immediately. To do this we'll have to "
-                              "write your new partition table to the disk "
-                              "immediately. Is that OK?"), "yesno")
-    else:
-        rc = 1
-
-    if rc:
-        anaconda.id.partitions.doMetaDeletes(anaconda.id.diskset)
-        anaconda.id.fsset.setActive(anaconda.id.diskset)
-        anaconda.id.diskset.savePartitions ()
-        anaconda.id.fsset.createLogicalVolumes(anaconda.rootPath)
-        anaconda.id.fsset.formatSwap(anaconda.rootPath)
-        anaconda.id.fsset.turnOnSwap(anaconda.rootPath)
-
-    return
-
 
 class Partitions:
     """Defines all of the partition requests and delete requests."""
@@ -217,6 +193,7 @@ class Partitions:
                                                              drive = drive,
                                                              format = format)
                 spec.device = fsset.PartedPartitionDevice(part).getDevice()
+                spec.maxSize = partedUtils.getMaxAvailPartSizeMB(part)
 
                 # set label if makes sense
                 if ptype and ptype.isMountable() and \
@@ -225,6 +202,7 @@ class Partitions:
                         if labels[spec.device] and len(labels[spec.device])>0:
                             spec.fslabel = labels[spec.device]
 
+                print "added %s of size %s with max size of %s" %(spec.device, size, spec.maxSize)
                 self.addRequest(spec)
                 part = disk.next_partition(part)
 
diff --git a/scripts/upd-instroot b/scripts/upd-instroot
index 8312eb9..4d695df 100755
--- a/scripts/upd-instroot
+++ b/scripts/upd-instroot
@@ -416,6 +416,7 @@ sbin/busybox.anaconda
 sbin/clock
 sbin/debugfs
 sbin/dosfslabel
+sbin/dumpe2fs
 sbin/e2fsck
 sbin/e2fsadm
 sbin/e2label
diff --git a/text.py b/text.py
index a5eefb5..87b8bc2 100644
--- a/text.py
+++ b/text.py
@@ -115,6 +115,9 @@ class ProgressWindow:
         del self.scale
         self.scale = None
 
+    def pulse(self):
+        pass
+
     def set(self, amount):
         self.scale.set(int(float(amount) * self.multiplier))
         self.screen.refresh()
@@ -122,7 +125,7 @@ class ProgressWindow:
     def refresh(self):
         pass
 
-    def __init__(self, screen, title, text, total, updpct = 0.05):
+    def __init__(self, screen, title, text, total, updpct = 0.05, pulse = False):
         self.multiplier = 1
         if total == 1.0:
             self.multiplier = 100
@@ -136,7 +139,8 @@ class ProgressWindow:
 	g.add(t, 0, 0, (0, 0, 0, 1), anchorLeft=1)
 
         self.scale = Scale(int(width), int(float(total) * self.multiplier))
-        g.add(self.scale, 0, 1)
+        if not pulse:
+            g.add(self.scale, 0, 1)
                 
 	g.draw()
 	self.screen.refresh()
@@ -351,8 +355,8 @@ class InstallInterface:
 		pdb.post_mortem(tb)
 	    os._exit(1)
 
-    def progressWindow(self, title, text, total, updpct = 0.05):
-        return ProgressWindow(self.screen, title, text, total, updpct)
+    def progressWindow(self, title, text, total, updpct = 0.05, pulse = False):
+        return ProgressWindow(self.screen, title, text, total, updpct, pulse)
 
     def messageWindow(self, title, text, type="ok", default = None,
 		      custom_icon=None, custom_buttons=[]):
_______________________________________________
Anaconda-devel-list mailing list
Anaconda-devel-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/anaconda-devel-list

[Index of Archives]     [Kickstart]     [Fedora Users]     [Fedora Legacy List]     [Fedora Maintainers]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [Yosemite Photos]     [KDE Users]     [Fedora Tools]
  Powered by Linux