diff --git a/subiquity/controllers/filesystem.py b/subiquity/controllers/filesystem.py index f92380fa..e468fe16 100644 --- a/subiquity/controllers/filesystem.py +++ b/subiquity/controllers/filesystem.py @@ -112,8 +112,8 @@ class FilesystemController(BaseController): # Filesystem/Disk partition ----------------------------------------------- def partition_disk(self, disk): - log.debug("In disk partition view, using {} as the disk.".format(disk.path)) - title = ("Partition, format, and mount {}".format(disk.path)) + log.debug("In disk partition view, using {} as the disk.".format(disk.serial)) + title = ("Partition, format, and mount {}".format(disk.serial)) footer = ("Partition the disk, or format the entire device " "without partitions.") self.ui.set_header(title) @@ -236,8 +236,8 @@ class FilesystemController(BaseController): self.signal.prev_signal() def format_entire(self, disk): - log.debug("format_entire {}".format(disk)) - header = ("Format and/or mount {}".format(disk.path)) + log.debug("format_entire {}".format(disk.serial)) + header = ("Format and/or mount {}".format(disk.serial)) footer = ("Format or mount whole disk.") self.ui.set_header(header) self.ui.set_footer(footer) @@ -247,10 +247,10 @@ class FilesystemController(BaseController): def format_mount_partition(self, partition): log.debug("format_entire {}".format(partition)) if partition.fs() is not None: - header = ("Mount {}".format(partition.path)) + header = ("Mount partition {} of {}".format(partition.number, partition.device.serial)) footer = ("Mount partition.") else: - header = ("Format and mount {}".format(partition.path)) + header = ("Format and mount partition {} of {}".format(partition.number, partition.device.serial)) footer = ("Format and mount partition.") self.ui.set_header(header) self.ui.set_footer(footer) diff --git a/subiquity/models/filesystem.py b/subiquity/models/filesystem.py index b7cdb07f..712cb33c 100644 --- a/subiquity/models/filesystem.py +++ b/subiquity/models/filesystem.py @@ -153,6 +153,9 @@ class Disk: def size(self): return self._info.size - (2<<20) # The first and last megabyte of the disk are not usable. + def desc(self): + return "local disk" + @property def used(self): if self._fs is not None: @@ -183,6 +186,9 @@ class Partition: def fs(self): return self._fs + def desc(self): + return "partition of {}".format(self.device.desc()) + @property def available(self): if self.flag == 'bios_grub': @@ -242,10 +248,13 @@ class FilesystemModel(object): ] fs_by_name = {} + longest_fs_name = 0 for t in supported_filesystems: if len(t) > 2: fs = t[2] if fs.label is not None: + if len(fs.label) > longest_fs_name: + longest_fs_name = len(fs.label) fs_by_name[fs.label] = fs def __init__(self, prober, opts): @@ -310,7 +319,7 @@ class FilesystemModel(object): self._disks[disk.path] = disk def all_disks(self): - return [disk for (path, disk) in sorted(self._available_disks.items())] + return sorted(self._available_disks.values(), key=lambda x:x.serial) def get_disk(self, path): return self._available_disks.get(path) diff --git a/subiquity/ui/views/filesystem/add_partition.py b/subiquity/ui/views/filesystem/add_partition.py index a9476661..532d2c5d 100644 --- a/subiquity/ui/views/filesystem/add_partition.py +++ b/subiquity/ui/views/filesystem/add_partition.py @@ -103,8 +103,6 @@ class AddPartitionView(BaseView): connect_signal(self.form, 'cancel', self.cancel) body = [ - Text("Adding partition to {}".format(self.disk.path), align="center"), - Padding.line_break(""), self.form.as_rows(self), Padding.line_break(""), Padding.fixed_10(self.form.buttons), diff --git a/subiquity/ui/views/filesystem/disk_partition.py b/subiquity/ui/views/filesystem/disk_partition.py index 85b04d1d..0f63d7d3 100644 --- a/subiquity/ui/views/filesystem/disk_partition.py +++ b/subiquity/ui/views/filesystem/disk_partition.py @@ -56,8 +56,7 @@ class DiskPartitionView(BaseView): def _build_model_inputs(self): partitioned_disks = [] - def format_volume(part): - path = part.path + def format_volume(label, part): size = humanize_size(part.size) if part.fs() is None: fstype = '-' @@ -69,16 +68,16 @@ class DiskPartitionView(BaseView): fstype = part.fs().fstype mountpoint = part.fs().mount().path return Columns([ - (15, Text(path)), + (15, Text(label)), Text(size), Text(fstype), Text(mountpoint), ], 4) if self.disk.fs() is not None: - partitioned_disks.append(format_volume(self.disk)) + partitioned_disks.append(format_volume("entire disk", self.disk)) else: for part in self.disk.partitions(): - partitioned_disks.append(format_volume(part)) + partitioned_disks.append(format_volume("partition {}".format(part.number), part)) if self.disk.free > 0: free_space = humanize_size(self.disk.free) partitioned_disks.append(Columns([ diff --git a/subiquity/ui/views/filesystem/filesystem.py b/subiquity/ui/views/filesystem/filesystem.py index 255b30c6..5154d04d 100644 --- a/subiquity/ui/views/filesystem/filesystem.py +++ b/subiquity/ui/views/filesystem/filesystem.py @@ -78,23 +78,23 @@ class FilesystemView(BaseView): self.controller = controller self.items = [] self.body = [ - Padding.center_79(Text("FILE SYSTEM")), - Padding.line_break(""), - Padding.center_79(self._build_filesystem_list()), - Padding.line_break(""), - Padding.center_79(Text("AVAILABLE DISKS AND PARTITIONS")), - Padding.line_break(""), - Padding.center_79(self._build_available_inputs()), - Padding.line_break(""), - #Padding.center_79(self._build_menu()), - #Padding.line_break(""), - #Padding.center_79(Text("USED DISKS")), - #Padding.line_break(""), - #Padding.center_79(self._build_used_disks()), - #Padding.line_break(""), + Text("FILE SYSTEM SUMMARY"), + Text(""), + self._build_filesystem_list(), + Text(""), + Text("AVAILABLE DEVICES"), + Text(""), + self._build_available_inputs(), + Text(""), + #self._build_menu(), + #Text(""), + #Text("USED DISKS"), + #Text(""), + #self._build_used_disks(), + #Text(""), Padding.fixed_10(self._build_buttons()), ] - super().__init__(ListBox(self.body)) + super().__init__(Padding.center_90(ListBox(self.body))) log.debug('FileSystemView init complete()') def _build_used_disks(self): @@ -104,19 +104,30 @@ class FilesystemView(BaseView): def _build_filesystem_list(self): log.debug('FileSystemView: building part list') cols = [] - for m in self.model._mounts: - cols.append((m.device.volume.path, humanize_size(m.device.volume.size), m.device.fstype, m.path)) + longest_path = len("MOUNT POINT") + for m in sorted(self.model._mounts, key=lambda m:m.path): + path = m.path + longest_path = max(longest_path, len(path)) + for p, *_ in reversed(cols): + if path.startswith(p): + path = [('info_minor', p), path[len(p):]] + break + cols.append((m.path, path, humanize_size(m.device.volume.size), m.device.fstype, m.device.volume.desc())) for fs in self.model._filesystems: if fs.fstype == 'swap': - cols.append((fs.volume.path, humanize_size(fs.volume.size), fs.fstype, 'SWAP')) + cols.append((None, 'SWAP', humanize_size(fs.volume.size), fs.fstype, fs.device.volume.desc())) if len(cols) == 0: return Pile([Color.info_minor( Text("No disks or partitions mounted."))]) - cols.insert(0, ("PARTITION", "SIZE", "TYPE", "MOUNT POINT")) + cols.insert(0, (None, "MOUNT POINT", "SIZE", "TYPE", "DEVICE TYPE")) pl = [] - for a, b, c, d in cols: - pl.append(Columns([(15, Text(a)), Text(b), Text(c), Text(d)], 4)) + for _, a, b, c, d in cols: + if b == "SIZE": + b = Text(b, align='center') + else: + b = Text(b, align='right') + pl.append(Columns([(longest_path, Text(a)), (9, b), (self.model.longest_fs_name, Text(c)), Text(d)], 4)) return Pile(pl) def _build_buttons(self): @@ -136,39 +147,74 @@ class FilesystemView(BaseView): def _build_available_inputs(self): inputs = [] - def col(col1, col2, col3): - inputs.append(Columns([(15, col1), (10, col2), col3], 2)) + def col3(col1, col2, col3): + inputs.append(Columns([(40, col1), (10, col2), (10, col3)], 2)) + def col2(col1, col2): + inputs.append(Columns([(40, col1), col2], 2)) + def col1(col1): + inputs.append(Columns([(40, col1)], 1)) - col(Text("DEVICE"), Text("SIZE"), Text("TYPE")) + col3(Text("DEVICE"), Text("SIZE", align="center"), Text("TYPE")) for disk in self.model.all_disks(): + disk_label = Text(disk.serial) + size = Text(humanize_size(disk.size).rjust(9)) + typ = Text(disk.desc()) + col3(disk_label, size, typ) + if disk.fs() is not None: + label = "entire device, " + fs = disk.fs() + if fs is not None: + if fs.mount(): + label += "%-*s"%(self.model.longest_fs_name+2, fs.fstype+',') + fs.mount().path + else: + label += fs.fstype + else: + label += "unformatted" + if not fs.mount(): + disk_btn = menu_btn(label=label) + connect_signal(disk_btn, 'click', self.click_disk, disk) + disk_btn = Color.menu_button(disk_btn) + else: + disk_btn = Color.info_minor(Text(" " + label)) + col1(disk_btn) + for partition in disk.partitions(): + label = "partition {}, ".format(partition.number) + fs = partition.fs() + if fs is not None: + if fs.mount(): + label += "%-*s"%(self.model.longest_fs_name+2, fs.fstype+',') + fs.mount().path + else: + label += fs.fstype + else: + label += "unformatted" + size = Text("{:>9} ({}%)".format(humanize_size(partition.size), int(100*partition.size/disk.size))) + if partition.available: + part_btn = menu_btn(label=label) + connect_signal(part_btn, 'click', self.click_partition, partition) + part_btn = Color.menu_button(part_btn) + col2(part_btn, size) + else: + part_btn = Color.info_minor(Text(" " + label)) + size = Color.info_minor(size) + col2(part_btn, size) if disk.available: - disk_btn = menu_btn(label=disk.path) - connect_signal(disk_btn, 'click', self.click_disk, disk) - col1 = Color.menu_button(disk_btn) - col2 = Text(humanize_size(disk.size)) if disk.used > 0: + disk_btn = menu_btn(label="FREE SPACE") + connect_signal(disk_btn, 'click', self.click_disk, disk) + disk_btn = Color.menu_button(disk_btn) size = disk.size free = disk.free percent = int(100*free/size) if percent == 0: continue - col3 = Text("local disk, {} ({}%) free".format(humanize_size(free), percent)) + size = Text("{:>9} ({}%)".format(humanize_size(free), percent)) + col2(disk_btn, size) else: - col3 = Text("local disk") - col(col1, col2, col3) - for partition in disk.partitions(): - if partition.available: - part_btn = menu_btn(label=' ' + partition.path) - connect_signal(part_btn, 'click', self.click_partition, partition) - col1 = Color.menu_button(part_btn) - if partition.fs() is not None: - fs = partition.fs().fstype - else: - fs = "unformatted" - col2 = Text(humanize_size(partition.size)) - col3 = Text("{} partition on local disk".format(fs)) - col(col1, col2, col3) + disk_btn = menu_btn(label="ADD FIRST PARTITION") + connect_signal(disk_btn, 'click', self.click_disk, disk) + disk_btn = Color.menu_button(disk_btn) + col2(disk_btn, Text("")) if len(inputs) == 1: return Pile([Color.info_minor( @@ -177,7 +223,10 @@ class FilesystemView(BaseView): return Pile(inputs) def click_disk(self, sender, disk): - self.controller.partition_disk(disk) + if disk.fs() is not None: + self.controller.format_entire(disk) + else: + self.controller.partition_disk(disk) def click_partition(self, sender, partition): self.controller.format_mount_partition(partition)