Merge pull request #212 from CanonicalLtd/mwhudson/disks-by-id

refer to disks in the UI by id not path
This commit is contained in:
Michael Hudson-Doyle 2017-04-07 10:27:01 +12:00 committed by GitHub
commit 5c3f12aac9
5 changed files with 113 additions and 58 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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),

View File

@ -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([

View File

@ -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)