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/>.
|
|
|
|
|
|
|
|
import logging
|
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,
|
|
|
|
Text, Columns, LineBox, Edit, RadioButton)
|
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-06-24 20:22:21 +00:00
|
|
|
from subiquity.ui.utils import Padding, Color
|
2015-07-16 21:58:32 +00:00
|
|
|
from subiquity.signals import emit_signal
|
2015-06-24 20:22:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
log = logging.getLogger('subiquity.filesystemView')
|
|
|
|
|
|
|
|
|
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-17 00:06:13 +00:00
|
|
|
class AddPartitionView(WidgetWrap):
|
|
|
|
signals = [
|
|
|
|
'fs:add-partition:done',
|
|
|
|
'fs:add-partition:cancel'
|
|
|
|
]
|
|
|
|
|
|
|
|
def __init__(self, model, selected_disk):
|
|
|
|
self.partition_spec = {}
|
|
|
|
self.model = model
|
|
|
|
body = ListBox([
|
|
|
|
Padding.center_79(
|
|
|
|
Text("Adding partition to {}".format(selected_disk))),
|
|
|
|
Padding.center_79(self._container()),
|
|
|
|
Padding.center_79(self._build_buttons())
|
|
|
|
])
|
|
|
|
box = BoxAdapter(body,
|
|
|
|
len(body))
|
|
|
|
super().__init__(LineBox(box))
|
|
|
|
|
|
|
|
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 _partition_edit(self):
|
|
|
|
return Edit(caption="Partition number (1-4)",
|
|
|
|
edit_text="1")
|
|
|
|
|
|
|
|
def _size_edit(self):
|
|
|
|
return Edit(caption="Size (max 2Tb)")
|
|
|
|
|
|
|
|
def _format_edit(self):
|
|
|
|
group = []
|
|
|
|
for fs in self.model.supported_filesystems:
|
|
|
|
RadioButton(group, fs)
|
|
|
|
return SimpleList(group)
|
|
|
|
|
|
|
|
def _mount_point_edit(self):
|
|
|
|
return Edit(caption="Mount", edit_text="/")
|
|
|
|
|
|
|
|
def _container(self):
|
|
|
|
total_items = [
|
|
|
|
self._partition_edit(),
|
|
|
|
self._size_edit(),
|
|
|
|
self._format_edit(),
|
|
|
|
self._mount_point_edit()
|
|
|
|
]
|
|
|
|
|
|
|
|
return SimpleList(total_items)
|
|
|
|
|
|
|
|
def cancel(self, button):
|
|
|
|
emit_signal(self, 'fs:add-partition:done', False)
|
|
|
|
|
|
|
|
def done(self):
|
|
|
|
""" partition spec
|
|
|
|
|
|
|
|
{ 'partition_number': Int,
|
|
|
|
'size': Int(M|G),
|
|
|
|
'format' Str(ext4|btrfs..,
|
|
|
|
'mount_point': Str
|
|
|
|
}
|
|
|
|
"""
|
|
|
|
if not self.partition_spec:
|
|
|
|
# TODO: Maybe popup warning?
|
|
|
|
return
|
|
|
|
emit_signal(self, 'fs:add-partition:done', self.partition_spec)
|
|
|
|
|
|
|
|
|
2015-07-16 21:58:32 +00:00
|
|
|
class DiskPartitionView(WidgetWrap):
|
|
|
|
signals = [
|
2015-07-17 00:06:13 +00:00
|
|
|
'fs:dp:show-add-partition',
|
2015-07-16 21:58:32 +00:00
|
|
|
'fs:dp:done',
|
|
|
|
]
|
|
|
|
|
2015-07-17 00:06:13 +00:00
|
|
|
def __init__(self, model, selected_disk):
|
2015-06-24 20:22:21 +00:00
|
|
|
self.model = model
|
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):
|
|
|
|
col_1 = []
|
|
|
|
col_2 = []
|
|
|
|
|
|
|
|
disk = self.model.get_disk_info(self.selected_disk)
|
2015-07-17 00:06:13 +00:00
|
|
|
btn = done_btn(label="FREE SPACE", on_press=self.add_paritition)
|
2015-07-16 21:58:32 +00:00
|
|
|
col_1.append(Color.button_primary(btn,
|
|
|
|
focus_map='button_primary focus'))
|
|
|
|
disk_sz = str(_humanize_size(disk.size))
|
|
|
|
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))
|
|
|
|
return Columns([(15, col_1), col_2], 2)
|
|
|
|
|
|
|
|
def _build_menu(self):
|
|
|
|
opts = []
|
|
|
|
for opt in self.model.partition_menu:
|
|
|
|
opts.append(
|
|
|
|
Color.button_secondary(done_btn(label=opt,
|
|
|
|
on_press=self.done),
|
|
|
|
focus_map='button_secondary focus'))
|
|
|
|
return Pile(opts)
|
|
|
|
|
2015-07-17 00:06:13 +00:00
|
|
|
def add_partition(self, partition):
|
|
|
|
emit_signal(self, 'fs:dp:show-add-partition', True)
|
2015-07-16 21:58:32 +00:00
|
|
|
|
|
|
|
def done(self, button):
|
|
|
|
emit_signal(self, 'fs:dp:done', True)
|
|
|
|
|
|
|
|
def cancel(self, button):
|
|
|
|
emit_signal(self, 'fs:dp:done', False)
|
|
|
|
|
|
|
|
|
|
|
|
class FilesystemView(WidgetWrap):
|
|
|
|
signals = [
|
|
|
|
"fs:done",
|
|
|
|
"fs:reset",
|
|
|
|
"fs:dp:view"
|
|
|
|
]
|
|
|
|
|
|
|
|
def __init__(self, model):
|
|
|
|
self.model = model
|
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'),
|
|
|
|
Color.button_secondary(done_btn(on_press=self.done),
|
2015-06-24 20:22:21 +00:00
|
|
|
focus_map='button_secondary focus'),
|
|
|
|
]
|
|
|
|
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-16 21:58:32 +00:00
|
|
|
for opt in self.model.fs_menu:
|
2015-06-24 20:22:21 +00:00
|
|
|
opts.append(
|
2015-07-10 20:58:25 +00:00
|
|
|
Color.button_secondary(done_btn(label=opt,
|
|
|
|
on_press=self.done),
|
2015-06-24 20:22:21 +00:00
|
|
|
focus_map='button_secondary focus'))
|
|
|
|
return Pile(opts)
|
|
|
|
|
2015-07-10 20:58:25 +00:00
|
|
|
def done(self, button):
|
|
|
|
log.info("Filesystem View done() getting disk info")
|
|
|
|
actions = self.model.get_actions()
|
2015-07-16 21:58:32 +00:00
|
|
|
emit_signal(self, 'fs:done', False, actions)
|
2015-06-24 20:22:21 +00:00
|
|
|
|
|
|
|
def cancel(self, button):
|
2015-07-16 21:58:32 +00:00
|
|
|
emit_signal(self, 'fs:done')
|
2015-07-10 20:58:25 +00:00
|
|
|
|
|
|
|
def reset(self, button):
|
2015-07-16 21:58:32 +00:00
|
|
|
emit_signal(self, 'fs:done', True)
|
2015-07-13 15:05:53 +00:00
|
|
|
|
|
|
|
def show_disk_partition_view(self, partition):
|
2015-07-16 21:58:32 +00:00
|
|
|
emit_signal(self, 'fs:dp:view', partition.label)
|