2015-06-24 20:22:21 +00:00
|
|
|
# Copyright 2015 Canonical, Ltd.
|
|
|
|
#
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU Affero General Public License as
|
|
|
|
# published by the Free Software Foundation, either version 3 of the
|
|
|
|
# License, or (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU Affero General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
2015-07-21 15:55:02 +00:00
|
|
|
""" Filesystem
|
|
|
|
|
|
|
|
Provides storage device selection and additional storage
|
|
|
|
configuration.
|
|
|
|
|
|
|
|
"""
|
2015-06-24 20:22:21 +00:00
|
|
|
import logging
|
2015-07-21 15:55:02 +00:00
|
|
|
import json
|
|
|
|
import argparse
|
|
|
|
|
|
|
|
from subiquity.filesystem.blockdev import Blockdev
|
|
|
|
from probert import prober
|
|
|
|
from probert.storage import StorageInfo
|
2015-07-06 15:55:49 +00:00
|
|
|
import math
|
2015-07-17 00:06:13 +00:00
|
|
|
from urwid import (WidgetWrap, ListBox, Pile, BoxAdapter,
|
2015-07-22 02:51:06 +00:00
|
|
|
Text, Columns, LineBox, Edit, RadioButton,
|
|
|
|
IntEdit)
|
2015-06-24 20:22:21 +00:00
|
|
|
from subiquity.ui.lists import SimpleList
|
2015-07-16 21:58:32 +00:00
|
|
|
from subiquity.ui.buttons import done_btn, reset_btn, cancel_btn
|
2015-07-22 13:53:59 +00:00
|
|
|
from subiquity.ui.widgets import Box
|
2015-06-24 20:22:21 +00:00
|
|
|
from subiquity.ui.utils import Padding, Color
|
2015-07-22 18:57:53 +00:00
|
|
|
from subiquity.ui.interactive import (StringEditor, IntegerEditor, Selector)
|
2015-06-24 20:22:21 +00:00
|
|
|
|
2015-07-21 15:55:02 +00:00
|
|
|
log = logging.getLogger('subiquity.filesystem')
|
|
|
|
|
|
|
|
|
|
|
|
class FilesystemModel:
|
|
|
|
""" Model representing storage options
|
|
|
|
"""
|
2015-07-22 01:34:46 +00:00
|
|
|
prev_signal = (
|
|
|
|
'Back to network path',
|
|
|
|
'network:show',
|
|
|
|
'network'
|
|
|
|
)
|
|
|
|
|
|
|
|
signals = [
|
|
|
|
('Filesystem view',
|
|
|
|
'filesystem:show',
|
|
|
|
'filesystem'),
|
|
|
|
('Filesystem finish',
|
|
|
|
'filesystem:finish',
|
|
|
|
'filesystem_handler'),
|
|
|
|
('Show disk partition view',
|
|
|
|
'filesystem:show-disk-partition',
|
|
|
|
'disk_partition'),
|
|
|
|
('Finish disk partition',
|
|
|
|
'filesystem:finish-disk-partition',
|
|
|
|
'disk_partition_handler'),
|
|
|
|
('Add disk partition',
|
|
|
|
'filesystem:add-disk-partition',
|
|
|
|
'add_disk_partition'),
|
|
|
|
('Finish add disk partition',
|
|
|
|
'filesystem:finish-add-disk-partition',
|
|
|
|
'add_disk_partition_handler')
|
|
|
|
]
|
2015-07-21 15:55:02 +00:00
|
|
|
|
|
|
|
fs_menu = [
|
2015-07-21 20:34:46 +00:00
|
|
|
('Connect iSCSI network disk',
|
|
|
|
'filesystem:connect-iscsi-disk',
|
|
|
|
'connect_iscsi_disk'),
|
|
|
|
('Connect Ceph network disk',
|
|
|
|
'filesystem:connect-ceph-disk',
|
|
|
|
'connect_ceph_disk'),
|
|
|
|
('Create volume group (LVM2)',
|
|
|
|
'filesystem:create-volume-group',
|
|
|
|
'create_volume_group'),
|
|
|
|
('Create software RAID (MD)',
|
|
|
|
'filesystem:create-raid',
|
|
|
|
'create_raid'),
|
|
|
|
('Setup hierarchichal storage (bcache)',
|
|
|
|
'filesystem:setup-bcache',
|
|
|
|
'setup_bcache')
|
2015-07-21 15:55:02 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
partition_menu = [
|
2015-07-21 20:34:46 +00:00
|
|
|
('Add first GPT partition',
|
|
|
|
'filesystem:add-first-gpt-partition',
|
|
|
|
'add_first_gpt_partition'),
|
|
|
|
('Format or create swap on entire device (unusual, advanced)',
|
|
|
|
'filesystem:create-swap-entire-device',
|
|
|
|
'create_swap_entire_device')
|
2015-07-21 15:55:02 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
supported_filesystems = [
|
|
|
|
'ext4',
|
|
|
|
'xfs',
|
|
|
|
'btrfs',
|
|
|
|
'swap',
|
|
|
|
'bcache cache',
|
|
|
|
'bcache store',
|
|
|
|
'leave unformatted'
|
|
|
|
]
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
self.storage = {}
|
|
|
|
self.info = {}
|
|
|
|
self.devices = {}
|
|
|
|
self.options = argparse.Namespace(probe_storage=True,
|
|
|
|
probe_network=False)
|
|
|
|
self.prober = prober.Prober(self.options)
|
|
|
|
self.probe_storage()
|
|
|
|
|
2015-07-21 20:34:46 +00:00
|
|
|
def get_signal_by_name(self, selection):
|
2015-07-22 01:34:46 +00:00
|
|
|
for x, y, z in self.get_signals():
|
2015-07-21 20:34:46 +00:00
|
|
|
if x == selection:
|
|
|
|
return y
|
|
|
|
|
2015-07-22 01:34:46 +00:00
|
|
|
def get_signals(self):
|
|
|
|
return self.signals + self.fs_menu + self.partition_menu
|
|
|
|
|
|
|
|
def get_menu(self):
|
|
|
|
return self.fs_menu
|
|
|
|
|
2015-07-21 15:55:02 +00:00
|
|
|
def probe_storage(self):
|
|
|
|
self.prober.probe()
|
|
|
|
self.storage = self.prober.get_results().get('storage')
|
2015-07-22 02:51:06 +00:00
|
|
|
# TODO: Put this into a logging namespace for probert
|
|
|
|
# since its quite a bit of log information.
|
|
|
|
# log.debug('storage probe data:\n{}'.format(
|
|
|
|
# json.dumps(self.storage, indent=4, sort_keys=True)))
|
2015-07-21 15:55:02 +00:00
|
|
|
|
|
|
|
# TODO: replace this with Storage.get_device_by_match()
|
|
|
|
# which takes a lambda fn for matching
|
|
|
|
VALID_MAJORS = ['8', '253']
|
|
|
|
for disk in self.storage.keys():
|
|
|
|
if self.storage[disk]['DEVTYPE'] == 'disk' and \
|
|
|
|
self.storage[disk]['MAJOR'] in VALID_MAJORS:
|
|
|
|
log.debug('disk={}\n{}'.format(disk,
|
|
|
|
json.dumps(self.storage[disk], indent=4,
|
|
|
|
sort_keys=True)))
|
|
|
|
self.info[disk] = StorageInfo({disk: self.storage[disk]})
|
|
|
|
|
|
|
|
def get_disk(self, disk):
|
|
|
|
if disk not in self.devices:
|
2015-07-22 20:18:18 +00:00
|
|
|
self.devices[disk] = Blockdev(disk, self.info[disk].serial)
|
2015-07-21 15:55:02 +00:00
|
|
|
return self.devices[disk]
|
|
|
|
|
|
|
|
def get_partitions(self):
|
|
|
|
partitions = []
|
|
|
|
for dev in self.devices.values():
|
|
|
|
partnames = [part.path for part in dev.disk.partitions]
|
|
|
|
partitions += partnames
|
|
|
|
|
|
|
|
sorted(partitions)
|
|
|
|
return partitions
|
|
|
|
|
|
|
|
def get_available_disks(self):
|
|
|
|
return sorted(self.info.keys())
|
|
|
|
|
|
|
|
def get_used_disks(self):
|
|
|
|
return [dev.disk.path for dev in self.devices.values()
|
|
|
|
if dev.available is False]
|
|
|
|
|
|
|
|
def get_disk_info(self, disk):
|
|
|
|
return self.info[disk]
|
|
|
|
|
|
|
|
def get_disk_action(self, disk):
|
|
|
|
return self.devices[disk].get_actions()
|
2015-06-24 20:22:21 +00:00
|
|
|
|
2015-07-21 15:55:02 +00:00
|
|
|
def get_actions(self):
|
|
|
|
actions = []
|
|
|
|
for dev in self.devices.values():
|
|
|
|
actions += dev.get_actions()
|
|
|
|
return actions
|
2015-06-24 20:22:21 +00:00
|
|
|
|
|
|
|
|
2015-07-06 15:55:49 +00:00
|
|
|
def _humanize_size(size):
|
|
|
|
size = abs(size)
|
|
|
|
if size == 0:
|
|
|
|
return "0B"
|
|
|
|
units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']
|
|
|
|
p = math.floor(math.log(size, 2) / 10)
|
|
|
|
return "%.3f %s" % (size / math.pow(1024, p), units[int(p)])
|
|
|
|
|
|
|
|
|
2015-07-22 18:13:54 +00:00
|
|
|
def _dehumanize_size(size):
|
|
|
|
# convert human 'size' to integer
|
|
|
|
size_in = size
|
|
|
|
if size.endswith("B"):
|
|
|
|
size = size[:-1]
|
|
|
|
|
|
|
|
mpliers = {'B': 1, 'K': 2 ** 10, 'M': 2 ** 20, 'G': 2 ** 30, 'T': 2 ** 40}
|
|
|
|
|
|
|
|
num = size
|
|
|
|
mplier = 'B'
|
|
|
|
for m in mpliers:
|
|
|
|
if size.endswith(m):
|
|
|
|
mplier = m
|
|
|
|
num = size[0:-len(m)]
|
|
|
|
|
|
|
|
try:
|
|
|
|
num = float(num)
|
|
|
|
except ValueError:
|
2015-07-22 18:17:46 +00:00
|
|
|
raise ValueError("'{}' is not valid input.".format(size_in))
|
2015-07-22 18:13:54 +00:00
|
|
|
|
|
|
|
if num < 0:
|
2015-07-22 18:17:46 +00:00
|
|
|
raise ValueError("'{}': cannot be negative".format(size_in))
|
2015-07-22 18:13:54 +00:00
|
|
|
|
|
|
|
return int(num * mpliers[mplier])
|
|
|
|
|
|
|
|
|
2015-07-17 00:06:13 +00:00
|
|
|
class AddPartitionView(WidgetWrap):
|
|
|
|
|
2015-07-21 20:34:46 +00:00
|
|
|
def __init__(self, model, signal, selected_disk):
|
2015-07-17 00:06:13 +00:00
|
|
|
self.model = model
|
2015-07-22 20:18:18 +00:00
|
|
|
self.signal = signal
|
|
|
|
self.selected_disk = self.model.get_disk(selected_disk)
|
|
|
|
|
2015-07-22 18:57:53 +00:00
|
|
|
self.partnum = IntegerEditor(caption="Partition number (1-4): ",
|
|
|
|
default=1)
|
2015-07-22 20:18:18 +00:00
|
|
|
self.size = StringEditor(
|
|
|
|
caption="Size (max {}): ".format(
|
|
|
|
_humanize_size(self.selected_disk.freespace)))
|
2015-07-22 18:57:53 +00:00
|
|
|
self.mountpoint = StringEditor(caption="Mount: ", edit_text="/")
|
|
|
|
self.fstype = Selector(opts=self.model.supported_filesystems)
|
2015-07-22 02:51:06 +00:00
|
|
|
body = [
|
2015-07-22 14:05:17 +00:00
|
|
|
Padding.center_95(
|
2015-07-22 20:18:18 +00:00
|
|
|
Text("Adding partition to {}".format(
|
|
|
|
self.selected_disk.devpath))),
|
2015-07-22 02:51:06 +00:00
|
|
|
Padding.line_break(""),
|
2015-07-22 14:05:17 +00:00
|
|
|
Padding.center_90(self._container()),
|
2015-07-22 02:51:06 +00:00
|
|
|
Padding.line_break(""),
|
2015-07-22 14:05:17 +00:00
|
|
|
Padding.center_40(self._build_buttons())
|
2015-07-22 02:51:06 +00:00
|
|
|
]
|
2015-07-22 13:53:59 +00:00
|
|
|
partition_box = Padding.center_65(Box(body))
|
|
|
|
super().__init__(partition_box)
|
2015-07-17 00:06:13 +00:00
|
|
|
|
|
|
|
def _build_buttons(self):
|
|
|
|
cancel = cancel_btn(on_press=self.cancel)
|
|
|
|
done = done_btn(on_press=self.done)
|
|
|
|
|
|
|
|
buttons = [
|
|
|
|
Color.button_secondary(cancel, focus_map='button_secondary focus'),
|
|
|
|
Color.button_secondary(done, focus_map='button_secondary focus')
|
|
|
|
]
|
|
|
|
return Pile(buttons)
|
|
|
|
|
|
|
|
def _format_edit(self):
|
2015-07-22 18:57:53 +00:00
|
|
|
formats_list = Pile(self.fstype.group)
|
2015-07-22 02:53:36 +00:00
|
|
|
return Columns([(10, Text("Format: ")), formats_list], 2)
|
2015-07-17 00:06:13 +00:00
|
|
|
|
|
|
|
def _container(self):
|
|
|
|
total_items = [
|
2015-07-22 18:57:53 +00:00
|
|
|
self.partnum,
|
|
|
|
self.size,
|
2015-07-17 00:06:13 +00:00
|
|
|
self._format_edit(),
|
2015-07-22 18:57:53 +00:00
|
|
|
self.mountpoint
|
2015-07-17 00:06:13 +00:00
|
|
|
]
|
|
|
|
|
2015-07-22 13:57:43 +00:00
|
|
|
return Pile(total_items)
|
2015-07-17 00:06:13 +00:00
|
|
|
|
|
|
|
def cancel(self, button):
|
2015-07-22 02:51:06 +00:00
|
|
|
self.signal.emit_signal('filesystem:show')
|
2015-07-17 00:06:13 +00:00
|
|
|
|
2015-07-22 18:57:53 +00:00
|
|
|
def done(self, result):
|
2015-07-17 00:06:13 +00:00
|
|
|
""" partition spec
|
|
|
|
|
|
|
|
{ 'partition_number': Int,
|
|
|
|
'size': Int(M|G),
|
|
|
|
'format' Str(ext4|btrfs..,
|
|
|
|
'mount_point': Str
|
|
|
|
}
|
|
|
|
"""
|
2015-07-22 18:57:53 +00:00
|
|
|
result = {
|
|
|
|
"partnum": self.partnum.value,
|
2015-07-22 20:18:18 +00:00
|
|
|
"raw_size": self.size.value,
|
|
|
|
"bytes": _dehumanize_size(self.size.value),
|
2015-07-22 18:57:53 +00:00
|
|
|
"fstype": self.fstype.value,
|
|
|
|
"mountpoint": self.mountpoint.value
|
|
|
|
}
|
|
|
|
log.debug("Add Partition Result: {}".format(result))
|
2015-07-21 20:34:46 +00:00
|
|
|
self.signal.emit_signal(
|
2015-07-22 20:18:18 +00:00
|
|
|
'filesystem:finish-add-disk-partition',
|
|
|
|
self.selected_disk.devpath, result)
|
2015-07-17 00:06:13 +00:00
|
|
|
|
|
|
|
|
2015-07-16 21:58:32 +00:00
|
|
|
class DiskPartitionView(WidgetWrap):
|
2015-07-21 20:34:46 +00:00
|
|
|
def __init__(self, model, signal, selected_disk):
|
2015-06-24 20:22:21 +00:00
|
|
|
self.model = model
|
2015-07-21 20:34:46 +00:00
|
|
|
self.signal = signal
|
2015-07-16 21:58:32 +00:00
|
|
|
self.selected_disk = selected_disk
|
|
|
|
self.body = [
|
|
|
|
Padding.center_79(self._build_model_inputs()),
|
|
|
|
Padding.line_break(""),
|
|
|
|
Padding.center_79(self._build_menu()),
|
|
|
|
Padding.line_break(""),
|
|
|
|
Padding.center_20(self._build_buttons()),
|
|
|
|
]
|
|
|
|
super().__init__(ListBox(self.body))
|
|
|
|
|
|
|
|
def _build_buttons(self):
|
|
|
|
cancel = cancel_btn(on_press=self.cancel)
|
|
|
|
done = done_btn(on_press=self.done)
|
|
|
|
|
|
|
|
buttons = [
|
|
|
|
Color.button_secondary(cancel, focus_map='button_secondary focus'),
|
|
|
|
Color.button_secondary(done, focus_map='button_secondary focus')
|
|
|
|
]
|
|
|
|
return Pile(buttons)
|
|
|
|
|
|
|
|
def _build_model_inputs(self):
|
2015-07-22 20:18:18 +00:00
|
|
|
partitioned_disks = []
|
|
|
|
|
|
|
|
disk = self.model.get_disk(self.selected_disk)
|
|
|
|
|
|
|
|
for mnt, size, fstype, path in disk.get_fs_table():
|
|
|
|
mnt = Text(mnt)
|
|
|
|
size = Text("{} GB".format(size))
|
|
|
|
fstype = Text(fstype) if fstype else '-'
|
|
|
|
path = Text(path) if path else '-'
|
|
|
|
partition_column = Columns([
|
|
|
|
(15, path),
|
|
|
|
size,
|
|
|
|
fstype,
|
|
|
|
mnt
|
|
|
|
], 4)
|
|
|
|
partitioned_disks.append(partition_column)
|
2015-07-22 01:49:37 +00:00
|
|
|
btn = done_btn(label="FREE SPACE", on_press=self.add_partition)
|
2015-07-22 20:18:18 +00:00
|
|
|
btn = Color.button_primary(btn,
|
|
|
|
focus_map='button_primary focus')
|
|
|
|
free_space = str(_humanize_size(disk.freespace))
|
|
|
|
partitioned_disks.append(Columns([
|
|
|
|
(15, btn),
|
|
|
|
Text(free_space),
|
|
|
|
Text(""),
|
|
|
|
Text("")
|
|
|
|
], 4))
|
|
|
|
|
|
|
|
return BoxAdapter(SimpleList(partitioned_disks),
|
|
|
|
height=len(partitioned_disks))
|
2015-07-16 21:58:32 +00:00
|
|
|
|
|
|
|
def _build_menu(self):
|
|
|
|
opts = []
|
2015-07-22 01:49:37 +00:00
|
|
|
for opt, sig, _ in self.model.partition_menu:
|
2015-07-16 21:58:32 +00:00
|
|
|
opts.append(
|
|
|
|
Color.button_secondary(done_btn(label=opt,
|
2015-07-22 02:51:06 +00:00
|
|
|
on_press=self.on_menu_press),
|
2015-07-16 21:58:32 +00:00
|
|
|
focus_map='button_secondary focus'))
|
|
|
|
return Pile(opts)
|
|
|
|
|
2015-07-17 00:06:13 +00:00
|
|
|
def add_partition(self, partition):
|
2015-07-22 02:51:06 +00:00
|
|
|
if partition.label == "FREE SPACE":
|
|
|
|
self.signal.emit_signal('filesystem:add-disk-partition',
|
|
|
|
self.selected_disk)
|
|
|
|
else:
|
|
|
|
self.signal.emit_signal('filesystem:add-disk-partition',
|
|
|
|
partition.label)
|
|
|
|
|
|
|
|
def on_menu_press(self, result):
|
|
|
|
self.signal.emit_signal(self.model.get_signal_by_name(result.label))
|
2015-07-16 21:58:32 +00:00
|
|
|
|
2015-07-22 02:51:06 +00:00
|
|
|
def done(self, result):
|
|
|
|
self.signal.emit_signal('quit')
|
2015-07-16 21:58:32 +00:00
|
|
|
|
|
|
|
def cancel(self, button):
|
2015-07-22 02:51:06 +00:00
|
|
|
self.signal.emit_signal('filesystem:show')
|
2015-07-16 21:58:32 +00:00
|
|
|
|
|
|
|
|
|
|
|
class FilesystemView(WidgetWrap):
|
2015-07-21 20:34:46 +00:00
|
|
|
def __init__(self, model, signal):
|
2015-07-16 21:58:32 +00:00
|
|
|
self.model = model
|
2015-07-21 20:34:46 +00:00
|
|
|
self.signal = signal
|
2015-06-24 20:22:21 +00:00
|
|
|
self.items = []
|
|
|
|
self.body = [
|
2015-07-01 21:20:17 +00:00
|
|
|
Padding.center_79(Text("FILE SYSTEM")),
|
2015-06-30 20:08:16 +00:00
|
|
|
Padding.center_79(self._build_partition_list()),
|
|
|
|
Padding.line_break(""),
|
2015-07-01 21:20:17 +00:00
|
|
|
Padding.center_79(Text("AVAILABLE DISKS")),
|
2015-06-24 20:22:21 +00:00
|
|
|
Padding.center_79(self._build_model_inputs()),
|
|
|
|
Padding.line_break(""),
|
2015-07-16 21:58:32 +00:00
|
|
|
Padding.center_79(self._build_menu()),
|
2015-06-24 20:22:21 +00:00
|
|
|
Padding.line_break(""),
|
2015-07-10 20:58:25 +00:00
|
|
|
self._build_used_disks(),
|
2015-06-24 20:22:21 +00:00
|
|
|
Padding.center_20(self._build_buttons()),
|
|
|
|
]
|
|
|
|
super().__init__(ListBox(self.body))
|
|
|
|
|
2015-07-10 20:58:25 +00:00
|
|
|
def _build_used_disks(self):
|
|
|
|
pl = []
|
|
|
|
for disk in self.model.get_used_disks():
|
|
|
|
pl.append(Text(disk.path))
|
|
|
|
if len(pl):
|
|
|
|
return Padding.center_79(Text("USED DISKS"),
|
|
|
|
Padding.line_break(""),
|
|
|
|
Pile(pl))
|
|
|
|
return Pile(pl)
|
|
|
|
|
2015-06-30 20:08:16 +00:00
|
|
|
def _build_partition_list(self):
|
2015-07-01 21:20:17 +00:00
|
|
|
pl = []
|
2015-06-30 20:08:16 +00:00
|
|
|
if len(self.model.get_partitions()) == 0:
|
|
|
|
pl.append(Color.info_minor(
|
|
|
|
Text("No disks or partitions mounted")))
|
|
|
|
return Pile(pl)
|
|
|
|
for part in self.model.get_partitions():
|
|
|
|
pl.append(Text(part))
|
|
|
|
return Pile(pl)
|
|
|
|
|
2015-06-24 20:22:21 +00:00
|
|
|
def _build_buttons(self):
|
|
|
|
buttons = [
|
2015-07-10 20:58:25 +00:00
|
|
|
Color.button_secondary(reset_btn(on_press=self.reset),
|
|
|
|
focus_map='button_secondary focus'),
|
2015-06-24 20:22:21 +00:00
|
|
|
]
|
|
|
|
return Pile(buttons)
|
|
|
|
|
|
|
|
def _build_model_inputs(self):
|
2015-07-01 21:20:17 +00:00
|
|
|
col_1 = []
|
|
|
|
col_2 = []
|
2015-06-25 21:50:13 +00:00
|
|
|
|
2015-07-06 15:55:49 +00:00
|
|
|
for dname in self.model.get_available_disks():
|
|
|
|
disk = self.model.get_disk_info(dname)
|
2015-07-16 21:58:32 +00:00
|
|
|
btn = done_btn(label=disk.name,
|
|
|
|
on_press=self.show_disk_partition_view)
|
2015-07-13 15:05:53 +00:00
|
|
|
|
2015-07-01 21:20:17 +00:00
|
|
|
col_1.append(
|
2015-07-13 15:05:53 +00:00
|
|
|
Color.button_primary(btn, focus_map='button_primary focus'))
|
2015-07-06 15:55:49 +00:00
|
|
|
disk_sz = str(_humanize_size(disk.size))
|
2015-07-01 21:20:17 +00:00
|
|
|
col_2.append(Text(disk_sz))
|
|
|
|
|
|
|
|
col_1 = BoxAdapter(SimpleList(col_1),
|
|
|
|
height=len(col_1))
|
|
|
|
col_2 = BoxAdapter(SimpleList(col_2, is_selectable=False),
|
|
|
|
height=len(col_2))
|
2015-07-03 00:53:18 +00:00
|
|
|
return Columns([(15, col_1), col_2], 2)
|
2015-06-24 20:22:21 +00:00
|
|
|
|
2015-07-16 21:58:32 +00:00
|
|
|
def _build_menu(self):
|
2015-06-24 20:22:21 +00:00
|
|
|
opts = []
|
2015-07-22 01:34:46 +00:00
|
|
|
for opt, sig, _ in self.model.get_menu():
|
2015-06-24 20:22:21 +00:00
|
|
|
opts.append(
|
2015-07-21 21:04:28 +00:00
|
|
|
Color.button_secondary(
|
|
|
|
done_btn(label=opt,
|
|
|
|
on_press=self.on_fs_menu_press),
|
|
|
|
focus_map='button_secondary focus'))
|
2015-06-24 20:22:21 +00:00
|
|
|
return Pile(opts)
|
|
|
|
|
2015-07-21 21:04:28 +00:00
|
|
|
def on_fs_menu_press(self, result):
|
2015-07-10 20:58:25 +00:00
|
|
|
log.info("Filesystem View done() getting disk info")
|
|
|
|
actions = self.model.get_actions()
|
2015-07-21 21:04:28 +00:00
|
|
|
self.signal.emit_signal(
|
|
|
|
self.model.get_signal_by_name(result.label), False, actions)
|
2015-06-24 20:22:21 +00:00
|
|
|
|
|
|
|
def cancel(self, button):
|
2015-07-22 01:34:46 +00:00
|
|
|
self.signal.emit_signal(self.model.get_previous_signal)
|
2015-07-10 20:58:25 +00:00
|
|
|
|
|
|
|
def reset(self, button):
|
2015-07-21 20:34:46 +00:00
|
|
|
self.signal.emit_signal('filesystem:done', True)
|
2015-07-13 15:05:53 +00:00
|
|
|
|
|
|
|
def show_disk_partition_view(self, partition):
|
2015-07-21 20:34:46 +00:00
|
|
|
self.signal.emit_signal('filesystem:show-disk-partition',
|
|
|
|
partition.label)
|