예제 #1
0
    def __init__(self, model, controller):
        self.model = model
        self.controller = controller
        self.dev_to_row = {}
        self.cur_netdevs = []
        self.error = Text("", align='center')
        self.device_table = TablePile(self._build_model_inputs(),
                                      spacing=2,
                                      colspecs={
                                          0: ColSpec(rpad=1),
                                          4: ColSpec(can_shrink=True, rpad=1),
                                      })

        self._create_bond_btn = menu_btn(_("Create bond"),
                                         on_press=self._create_bond)
        bp = button_pile([self._create_bond_btn])
        bp.align = 'left'

        self.listbox = ListBox([self.device_table] + [
            bp,
        ])
        self.bottom = Pile([
            Text(""),
            self._build_buttons(),
            Text(""),
        ])
        self.error_showing = False

        self.frame = Pile([('pack', Text("")),
                           ('pack', Padding.center_79(Text(_(self.excerpt)))),
                           ('pack', Text("")),
                           Padding.center_90(self.listbox),
                           ('pack', self.bottom)])
        self.frame.set_focus(self.bottom)
        super().__init__(self.frame)
예제 #2
0
 def __init__(self, app):
     self.app = app
     rows = [
         TableRow([
             Text(""),
             Text(_("DATE")),
             Text(_("KIND")),
             Text(_("STATUS")),
             Text(""),
         ])
     ]
     self.report_to_row = {}
     self.app.error_reporter.load_reports()
     for report in self.app.error_reporter.reports:
         connect_signal(report, "changed", self._report_changed, report)
         r = self.report_to_row[report] = self.row_for_report(report)
         rows.append(r)
     self.table = TablePile(rows, colspecs={1: ColSpec(can_shrink=True)})
     widgets = [
         Text(_("Select an error report to view:")),
         Text(""),
         self.table,
         Text(""),
         button_pile([close_btn(self)]),
     ]
     super().__init__("", widgets, 2, 2)
예제 #3
0
파일: raid.py 프로젝트: posm/subiquity
 def __init__(self):
     self.table = TablePile([], spacing=1)
     self.device_to_checkbox = {}
     self.device_to_selector = {}
     self.devices = {}  # {device:active|spare}
     self.all_rows = []
     self.no_selector_rows = []
     self.supports_spares = True
     super().__init__(self.table)
예제 #4
0
    def _create(self):
        # Create the widget for a nic. This consists of a Pile containing a
        # table, an info line and a blank line. The first row of the table is
        # the one that can be focused and has a menu for manipulating the nic,
        # the other rows summarize its address config.
        #   [ name type notes   ▸ ]   \
        #     address info            | <- table
        #     more address info       /
        #   mac / vendor info / model info
        #   <blank line>

        actions = []
        for action in NetDevAction:
            meth = getattr(self.parent, '_action_' + action.name)
            opens_dialog = getattr(meth, 'opens_dialog', False)
            if action in self.dev_info.enabled_actions:
                actions.append(
                    (action.str(), True, (action, meth), opens_dialog))

        menu = ActionMenu(actions)
        connect_signal(menu, 'action', self.parent._action, self)

        trows = [
            make_action_menu_row([
                Text("["),
                Text(self.dev_info.name),
                Text(self.dev_info.type),
                Text(self._notes(), wrap='clip'),
                menu,
                Text("]"),
            ], menu)
        ] + self._address_rows()

        self.table = TablePile(trows,
                               colspecs=self.parent.device_colspecs,
                               spacing=2)
        self.table.bind(self.parent.heading_table)

        if self.dev_info.type == "vlan":
            info = _("VLAN {id} on interface {link}").format(
                id=self.dev_info.vlan.id, link=self.dev_info.vlan.link)
        elif self.dev_info.type == "bond":
            info = _("bond master for {interfaces}").format(
                interfaces=', '.join(self.dev_info.bond.interfaces))
        else:
            info = " / ".join([
                self.dev_info.hwaddr,
                self.dev_info.vendor,
                self.dev_info.model,
            ])

        return Pile([
            ('pack', self.table),
            ('pack', Color.info_minor(Text("  " + info))),
            ('pack', Text("")),
        ])
예제 #5
0
    def _device_widget(self, dev, netdev_i=None):
        # Create the widget for a nic. This consists of a Pile containing a
        # table, an info line and a blank line. The first row of the table is
        # the one that can be focused and has a menu for manipulating the nic,
        # the other rows summarize its address config.
        #   [ name type notes   ▸ ]   \
        #     address info            | <- table
        #     more address info       /
        #   mac / vendor info / model info
        #   <blank line>
        if netdev_i is None:
            netdev_i = len(self.cur_netdevs)
        self.cur_netdevs[netdev_i:netdev_i] = [dev]

        actions = []
        for action in NetDevAction:
            meth = getattr(self, '_action_' + action.name)
            opens_dialog = getattr(meth, 'opens_dialog', False)
            if dev.supports_action(action):
                actions.append(
                    (_(action.value), True, (action, meth), opens_dialog))

        menu = ActionMenu(actions)
        connect_signal(menu, 'action', self._action, dev)

        trows = [
            make_action_menu_row([
                Text("["),
                Text(dev.name),
                Text(dev.type),
                Text(self._notes_for_device(dev), wrap='clip'),
                menu,
                Text("]"),
            ], menu)
        ] + self._address_rows_for_device(dev)

        table = TablePile(trows, colspecs=self.device_colspecs, spacing=2)
        self.dev_to_table[dev] = table
        table.bind(self.heading_table)

        if dev.type == "vlan":
            info = _("VLAN {id} on interface {link}").format(**dev.config)
        elif dev.type == "bond":
            info = _("bond master for {interfaces}").format(
                interfaces=', '.join(dev.config['interfaces']))
        else:
            info = " / ".join(
                [dev.info.hwaddr, dev.info.vendor, dev.info.model])

        return Pile([
            ('pack', table),
            ('pack', Color.info_minor(Text("  " + info))),
            ('pack', Text("")),
        ])
예제 #6
0
 def __init__(self, parent):
     self.parent = parent
     self.table = TablePile([], spacing=2, colspecs={
         0: ColSpec(rpad=1),
         1: ColSpec(can_shrink=True),
         2: ColSpec(min_width=9),
         4: ColSpec(rpad=1),
         5: ColSpec(rpad=1),
     })
     self._no_mounts_content = Color.info_minor(
         Text(_("No disks or partitions mounted.")))
     super().__init__(self.table)
예제 #7
0
    def __init__(self, controller, systems):
        self.controller = controller

        heading_table = TablePile([
            TableRow([
                Color.info_minor(Text(header))
                for header in ["LABEL", "MODEL", "PUBLISHER", ""]
            ])
        ],
                                  spacing=2)

        trows = []
        systems = sorted(
            systems,
            key=lambda s:
            (s.brand.display_name, s.model.display_name, s.current, s.label))
        for s in systems:
            actions = []
            log.debug('actions: %s', s.actions)
            for act in sorted(s.actions, key=by_preferred_action_type):
                actions.append(
                    Action(label=act.title.capitalize(),
                           value=act,
                           enabled=True))
            menu = ActionMenu(actions)
            connect_signal(menu, 'action', self._system_action, s)
            srow = make_action_menu_row([
                Text(s.label),
                Text(s.model.display_name),
                Text(s.brand.display_name),
                Text("(installed)" if s.current else ""),
                menu,
            ], menu)
            trows.append(srow)

        systems_table = TablePile(trows, spacing=2)
        systems_table.bind(heading_table)
        rows = [
            Pile([heading_table, systems_table]),
        ]

        buttons = []
        if controller.model.current is not None:
            # back to options of current system
            buttons.append(back_btn("BACK", on_press=self.back))

        super().__init__(
            controller.model.current,
            screen(rows=rows,
                   buttons=button_pile(buttons),
                   focus_buttons=False,
                   excerpt=self.excerpt))
예제 #8
0
 def __init__(self, parent):
     self.parent = parent
     self.table = TablePile(
         [],
         spacing=2,
         colspecs={
             0: ColSpec(rpad=2),
             1: ColSpec(rpad=2),
             2: ColSpec(rpad=2),
             3: ColSpec(rpad=2),
         })
     self._no_zdev_content = Color.info_minor(
         Text(_("No zdev devices found.")))
     super().__init__(self.table)
예제 #9
0
 def __init__(self, parent, show_available):
     self.parent = parent
     self.show_available = show_available
     self.table = TablePile([],  spacing=2, colspecs={
         0: ColSpec(rpad=1),
         2: ColSpec(can_shrink=True),
         4: ColSpec(min_width=9),
         5: ColSpec(rpad=1),
     })
     if show_available:
         text = _("No available devices")
     else:
         text = _("No used devices")
     self._no_devices_content = Color.info_minor(Text(text))
     super().__init__(self.table)
예제 #10
0
 def __init__(self, app):
     rows = []
     keys = GLOBAL_KEYS
     if app.opts.run_on_serial:
         keys += SERIAL_GLOBAL_HELP_KEYS
     for key, text in keys:
         rows.append(TableRow([Text(_(key)), Text(_(text))]))
     if app.opts.dry_run:
         dro = _('(dry-run only)')
         for key, text in DRY_RUN_KEYS:
             rows.append(TableRow([Text(_(key)),
                                   Text(_(text) + ' ' + dro)]))
     table = TablePile(rows,
                       spacing=2,
                       colspecs={1: ColSpec(can_shrink=True)})
     widgets = [
         Pile([
             ('pack', Text(rewrap(GLOBAL_KEY_HELP))),
             ('pack', Text("")),
             ('pack', table),
         ]),
         Text(""),
         button_pile([close_btn(app, self)]),
     ]
     super().__init__(_("Shortcut Keys"), widgets, 0, 2)
예제 #11
0
파일: form.py 프로젝트: xuejinze1/subiquity
    def _build_table(self):
        widget = self.widget
        if self.field.takes_default_style:
            widget = Color.string_input(widget)

        self.caption_text = Text(self.field.caption)
        self.under_text = Text(self.help)

        if self.field.caption_first:
            self.caption_text.align = 'right'
            first_row = [self.caption_text, _Validator(self, widget)]
        else:
            first_row = [
                _Validator(
                    self,
                    UrwidPadding(widget,
                                 align='right',
                                 width=widget_width(widget))),
                self.caption_text,
            ]

        self._rows = [
            Toggleable(TableRow(row)) for row in [
                first_row,
                [Text(""), self.under_text],
            ]
        ]

        self._table = TablePile(self._rows, spacing=2, colspecs=form_colspecs)
예제 #12
0
파일: delete.py 프로젝트: sd-hd/subiquity
    def __init__(self, parent, obj):
        self.parent = parent
        self.obj = obj

        lines = [
            Text(
                _("Do you really want to delete the {desc} {label}?").format(
                    desc=obj.desc(), label=obj.label)),
            Text(""),
        ]
        stretchy_index = 0
        fs = obj.fs()
        if fs is not None:
            m = fs.mount()
            if m is not None:
                lines.append(
                    Text(
                        _("It is formatted as {fstype} and mounted at "
                          "{path}").format(fstype=fs.fstype, path=m.path)))
            else:
                lines.append(
                    Text(
                        _("It is formatted as {fstype} and not mounted.").
                        format(fstype=fs.fstype)))
        elif hasattr(obj, 'partitions') and len(obj.partitions()) > 0:
            n = len(obj.partitions())
            if obj.type == "lvm_volgroup":
                if n == 1:
                    things = _("logical volume")
                else:
                    things = _("logical volumes")
            else:
                if n == 1:
                    things = _("partition")
                else:
                    things = _("partitions")
            lines.append(
                Text(
                    _("It contains {n} {things}:").format(n=n, things=things)))
            lines.append(Text(""))
            stretchy_index = len(lines)
            rows = []
            for p, cells in summarize_device(obj):
                if p not in [None, obj]:
                    rows.append(TableRow(cells))
            lines.append(TablePile(rows))
        else:
            lines.append(Text(_("It is not formatted or mounted.")))

        delete_btn = danger_btn(label=_("Delete"), on_press=self.confirm)
        widgets = lines + [
            Text(""),
            button_pile([
                delete_btn,
                other_btn(label=_("Cancel"), on_press=self.cancel),
            ]),
        ]
        super().__init__("", widgets, stretchy_index, len(lines) + 1)
예제 #13
0
    def __init__(self, controller, netdev_infos):
        self.controller = controller
        self.dev_name_to_table = {}
        self.cur_netdev_names = []
        self.error = Text("", align='center')

        self.device_colspecs = {
            0: ColSpec(rpad=1),
            3: ColSpec(min_width=15),
            4: ColSpec(can_shrink=True, rpad=1),
        }

        self.heading_table = TablePile([
            TableRow([
                Color.info_minor(Text(header)) for header in [
                    "",
                    "NAME",
                    "TYPE",
                    "NOTES",
                    "",
                ]
            ])
        ],
                                       spacing=2,
                                       colspecs=self.device_colspecs)

        self.device_pile = Pile([self.heading_table])

        for dev_info in netdev_infos:
            self.new_link(dev_info)

        self._create_bond_btn = menu_btn(_("Create bond"),
                                         on_press=self._create_bond)
        bp = button_pile([self._create_bond_btn])
        bp.align = 'left'

        rows = [
            self.device_pile,
            bp,
        ]

        self.buttons = button_pile([
            done_btn("TBD", on_press=self.done),  # See _route_watcher
            back_btn(_("Back"), on_press=self.cancel),
        ])
        self.bottom = Pile([
            ('pack', self.buttons),
        ])

        self.error_showing = False

        super().__init__(
            screen(rows=rows,
                   buttons=self.bottom,
                   focus_buttons=True,
                   excerpt=_(self.excerpt)))
예제 #14
0
 def _build_model_inputs(self):
     self.heading_table = TablePile([
         TableRow([
             Color.info_minor(Text(header)) for header in [
                 "", "NAME", "TYPE", "NOTES", "",
                 ]
             ])
         ],
         spacing=2, colspecs=self.device_colspecs)
     rows = [self.heading_table]
     for dev in self.model.get_all_netdevs():
         rows.append(self._device_widget(dev))
     return rows
예제 #15
0
 def show_apply_spinner(self):
     s = Spinner(self.controller.loop)
     s.start()
     c = TablePile([
         TableRow([
             Text(_("Applying changes")),
             s,
             ]),
         ], align='center')
     self.bottom.contents[0:0] = [
         (c, self.bottom.options()),
         (Text(""), self.bottom.options()),
         ]
예제 #16
0
 def __init__(self, parent, show_available):
     self.parent = parent
     self.show_available = show_available
     self.table = TablePile(
         [],
         spacing=2,
         colspecs={
             0: ColSpec(rpad=1),
             1: ColSpec(can_shrink=True),
             2: ColSpec(min_width=9),
             3: ColSpec(rpad=1),
             4: ColSpec(rpad=1),
         })
     if show_available:
         text = _("No available devices")
     else:
         text = _("No used devices")
     self._no_devices_content = Color.info_minor(Text(text))
     super().__init__(self.table)
     self.refresh_model_inputs()
     # I don't really know why this is required:
     self.table._select_first_selectable()
예제 #17
0
def ssh_help_texts(ssh_info):

    texts = [_(SSH_HELP_PROLOGUE), ""]

    if ssh_info is not None:
        if len(ssh_info.ips) > 1:
            texts.append(_(SSH_HELP_MULTIPLE_ADDRESSES))
            texts.append("")
            for ip in ssh_info.ips:
                texts.append(Text(
                    "{}@{}".format(ssh_info.username, ip), align='center'))
        else:
            texts.append(_(SSH_HELP_ONE_ADDRESSES).format(
                username=ssh_info.username, ip=str(ssh_info.ips[0])))
        texts.append("")
        if ssh_info.authorized_key_fingerprints:
            if len(ssh_info.authorized_key_fingerprints) == 1:
                key = ssh_info.authorized_key_fingerprints[0]
                texts.append(Text(_(SSH_HELP_EPILOGUE_ONE_KEY).format(
                    keytype=key.keytype, fingerprint=key.fingerprint)))
            else:
                texts.append(_(SSH_HELP_EPILOGUE_MULTIPLE_KEYS))
                texts.append("")
                rows = []
                for key in ssh_info.authorized_key_fingerprints:
                    rows.append(
                        TableRow([Text(key.keytype), Text(key.fingerprint)]))
                texts.append(TablePile(rows))
            if ssh_info.password_kind == PasswordKind.KNOWN:
                texts.append("")
                texts.append(SSH_HELP_EPILOGUE_KNOWN_PASS_KEYS.format(
                    password=ssh_info.password))
            elif ssh_info.password_kind == PasswordKind.UNKNOWN:
                texts.append("")
                texts.append(SSH_HELP_EPILOGUE_UNKNOWN_PASS_KEYS)
        else:
            if ssh_info.password_kind == PasswordKind.KNOWN:
                texts.append(SSH_HELP_EPILOGUE_KNOWN_PASS_NO_KEYS.format(
                    password=ssh_info.password))
            elif ssh_info.password_kind == PasswordKind.UNKNOWN:
                texts.append(SSH_HELP_EPILOGUE_UNKNOWN_PASS_NO_KEYS)
        texts.append("")
        texts.append(Text(summarize_host_keys([
            (key.keytype, key.fingerprint)
            for key in ssh_info.host_key_fingerprints
            ])))
    else:
        texts.append("")
        texts.append(_(SSH_HELP_NO_ADDRESSES))

    return texts
예제 #18
0
    def __init__(self, model, controller):
        self.model = model
        self.controller = controller
        self.dev_to_row = {}
        self.cur_netdevs = []
        self.error = Text("", align='center')
        self.device_table = TablePile(
            self._build_model_inputs(),
            spacing=2, colspecs={
                0: ColSpec(rpad=1),
                4: ColSpec(can_shrink=True, rpad=1),
                })

        self._create_bond_btn = menu_btn(
            _("Create bond"), on_press=self._create_bond)
        bp = button_pile([self._create_bond_btn])
        bp.align = 'left'

        rows = [
            self.device_table,
            bp,
        ]

        buttons = button_pile([
                    done_btn(_("Done"), on_press=self.done),
                    back_btn(_("Back"), on_press=self.cancel),
                    ])
        self.bottom = Pile([
            ('pack', buttons),
        ])

        self.error_showing = False

        super().__init__(screen(
            rows=rows,
            buttons=self.bottom,
            focus_buttons=True,
            excerpt=self.excerpt))
예제 #19
0
 def __init__(self, parent, disk):
     self.parent = parent
     dinfo = disk.info_for_display()
     rows = []
     for label, key in labels_keys:
         v = str(dinfo[key])
         rows.append(TableRow([Text(label, align='right'), Text(v)]))
     widgets = [
         TablePile(rows, colspecs={1: ColSpec(can_shrink=True)}),
         Text(""),
         button_pile([done_btn(_("Close"), on_press=self.close)]),
         ]
     title = _("Info for {}").format(disk.label)
     super().__init__(title, widgets, 0, 2)
예제 #20
0
 def __init__(self, parent):
     super().__init__(parent)
     options = []
     tables = []
     for disk in parent.model.all_disks():
         for obj, cells in summarize_device(disk):
             table = TablePile([TableRow(cells)])
             tables.append(table)
             options.append(Option((table, obj is disk, obj)))
     t0 = tables[0]
     for t in tables[1:]:
         t0.bind(t)
     self.disk.widget.options = options
     self.disk.widget.index = 0
     connect_signal(self.use_lvm.widget, 'change', self._toggle)
     self.lvm_options.enabled = self.use_lvm.value
예제 #21
0
    def _build_table(self):
        widget = self.widget
        if self.field.takes_default_style:
            widget = Color.string_input(widget)

        self.caption_text = Text(self.field.caption, align="right")
        self.under_text = Text(self.help)

        self._rows = [
            Toggleable(TableRow(row)) for row in [
                [self.caption_text,
                 _Validator(self, widget)],
                [Text(""), self.under_text],
            ]
        ]

        self._table = TablePile(self._rows, spacing=2, colspecs=form_colspecs)
예제 #22
0
 def _guidance(self):
     todos = []
     if not self.model.is_root_mounted():
         todos.append(_("Mount a filesystem at /"))
     if self.model.needs_bootloader_partition():
         todos.append(_("Select a boot disk"))
     if not todos:
         return None
     rows = [
         TableRow([
             Text(_("To continue you need to:")),
             Text(todos[0]),
         ]),
     ]
     for todo in todos[1:]:
         rows.append(TableRow([Text(""), Text(todo)]))
     rows.append(TableRow([Text("")]))
     return TablePile(rows)
예제 #23
0
파일: help.py 프로젝트: rpalkin/subiquity
 def __init__(self, app, parent):
     rows = []
     for key, text in GLOBAL_KEYS:
         rows.append(TableRow([Text(_(key)), Text(_(text))]))
     if app.opts.dry_run:
         for key, text in DRY_RUN_KEYS:
             rows.append(TableRow([Text(_(key)), Text(_(text))]))
     table = TablePile(
         rows, spacing=2, colspecs={1: ColSpec(can_shrink=True)})
     widgets = [
         Pile([
             ('pack', Text(rewrap(GLOBAL_KEY_HELP))),
             ('pack', Text("")),
             ('pack', table),
             ]),
         Text(""),
         button_pile([close_btn(parent)]),
         ]
     super().__init__(_("Shortcut Keys"), widgets, 0, 2)
예제 #24
0
 def __init__(self, parent):
     super().__init__(parent)
     options = []
     tables = []
     initial = -1
     for disk in parent.model.all_disks():
         for obj, cells in summarize_device(disk):
             table = TablePile([TableRow(cells)])
             tables.append(table)
             enabled = False
             if obj is disk and disk.size > 6 * (2**30):
                 enabled = True
                 if initial < 0:
                     initial = len(options)
             options.append(Option((table, enabled, obj)))
     t0 = tables[0]
     for t in tables[1:]:
         t0.bind(t)
     self.disk.widget.options = options
     self.disk.widget.index = initial
     connect_signal(self.use_lvm.widget, 'change', self._toggle)
     self.lvm_options.enabled = self.use_lvm.value
예제 #25
0
    def _build_table(self):
        widget = self.widget
        if self.field.takes_default_style:
            widget = Color.string_input(widget)

        if self.help is not NO_HELP:
            self.under_text = Text(self.help)
        else:
            self.under_text = Text("")
        if self.field.caption is NO_CAPTION:
            first_row = [(2, _Validator(self, widget))]
            second_row = [(2, self.under_text)]
        else:
            self.caption_text = Text(_(self.field.caption))

            if self.field.caption_first:
                self.caption_text.align = 'right'
                first_row = [self.caption_text, _Validator(self, widget)]
            else:
                first_row = [
                    _Validator(
                        self,
                        UrwidPadding(widget,
                                     align='right',
                                     width=widget_width(widget))),
                    self.caption_text,
                ]
            second_row = [Text(""), self.under_text]

        rows = [first_row]
        if self.help is not NO_HELP:
            rows.append(second_row)

        self._rows = [Toggleable(TableRow(row)) for row in rows]

        self._table = TablePile(self._rows, spacing=2, colspecs=form_colspecs)
예제 #26
0
class NetworkView(BaseView):
    title = _("Network connections")
    excerpt = _("Configure at least one interface this server can use to talk "
                "to other machines, and which preferably provides sufficient "
                "access for updates.")
    footer = _("Select an interface to configure it or select Done to "
               "continue")

    def __init__(self, model, controller):
        self.model = model
        self.controller = controller
        self.dev_to_row = {}
        self.cur_netdevs = []
        self.error = Text("", align='center')
        self.device_table = TablePile(self._build_model_inputs(),
                                      spacing=2,
                                      colspecs={
                                          0: ColSpec(rpad=1),
                                          4: ColSpec(can_shrink=True, rpad=1),
                                      })

        self._create_bond_btn = menu_btn(_("Create bond"),
                                         on_press=self._create_bond)
        bp = button_pile([self._create_bond_btn])
        bp.align = 'left'

        self.listbox = ListBox([self.device_table] + [
            bp,
        ])
        self.bottom = Pile([
            Text(""),
            self._build_buttons(),
            Text(""),
        ])
        self.error_showing = False

        self.frame = Pile([('pack', Text("")),
                           ('pack', Padding.center_79(Text(_(self.excerpt)))),
                           ('pack', Text("")),
                           Padding.center_90(self.listbox),
                           ('pack', self.bottom)])
        self.frame.set_focus(self.bottom)
        super().__init__(self.frame)

    def _build_buttons(self):
        back = back_btn(_("Back"), on_press=self.cancel)
        done = done_btn(_("Done"), on_press=self.done)
        return button_pile([done, back])

    _action_INFO = _stretchy_shower(ViewInterfaceInfo)
    _action_EDIT_WLAN = _stretchy_shower(NetworkConfigureWLANStretchy)
    _action_EDIT_IPV4 = _stretchy_shower(EditNetworkStretchy, 4)
    _action_EDIT_IPV6 = _stretchy_shower(EditNetworkStretchy, 6)
    _action_EDIT_BOND = _stretchy_shower(BondStretchy)
    _action_ADD_VLAN = _stretchy_shower(AddVlanStretchy)

    def _action_DELETE(self, device):
        self.controller.rm_virtual_interface(device)

    def _action(self, sender, action, device):
        action, meth = action
        log.debug("_action %s %s", action.name, device.name)
        meth(device)

    def _cells_for_device(self, dev):
        notes = []
        if dev.is_bond_slave:
            notes.append(
                _("enslaved to {}").format(dev._net_info.bond['master']))
        for v in 4, 6:
            if dev.configured_ip_addresses_for_version(v):
                notes.extend([
                    "{} (static)".format(a)
                    for a in dev.configured_ip_addresses_for_version(v)
                ])
            elif dev.dhcp_for_version(v):
                if v == 4:
                    fam = AF_INET
                elif v == 6:
                    fam = AF_INET6
                fam_addresses = []
                for a in dev._net_info.addresses.values():
                    log.debug("a %s", a.serialize())
                    if a.family == fam and a.source == 'dhcp':
                        fam_addresses.append("{} (from dhcp)".format(
                            a.address))
                if fam_addresses:
                    notes.extend(fam_addresses)
                else:
                    notes.append(
                        _("DHCPv{v} has supplied no addresses").format(v=v))
        if notes:
            notes = ", ".join(notes)
        else:
            notes = '-'
        return (dev.name, dev.type, notes)

    def new_link(self, new_dev):
        for i, cur_dev in enumerate(self.cur_netdevs):
            if cur_dev.name > new_dev.name:
                netdev_i = i
                break
        else:
            netdev_i = len(self.cur_netdevs)
        new_rows = self._rows_for_device(new_dev, netdev_i)
        self.device_table.insert_rows(3 * netdev_i + 1, new_rows)

    def update_link(self, dev):
        row = self.dev_to_row[dev]
        for i, text in enumerate(self._cells_for_device(dev)):
            row.columns[2 * (i + 1)].set_text(text)

    def del_link(self, dev):
        log.debug("del_link %s", (dev in self.cur_netdevs))
        if dev in self.cur_netdevs:
            netdev_i = self.cur_netdevs.index(dev)
            self.device_table.remove_rows(3 * netdev_i, 3 * (netdev_i + 1))
            del self.cur_netdevs[netdev_i]
        if isinstance(self._w, StretchyOverlay):
            stretchy = self._w.stretchy
            if getattr(stretchy, 'device', None) is dev:
                self.remove_overlay()

    def _rows_for_device(self, dev, netdev_i=None):
        if netdev_i is None:
            netdev_i = len(self.cur_netdevs)
        rows = []
        name, typ, addresses = self._cells_for_device(dev)
        actions = []
        for action in NetDevAction:
            meth = getattr(self, '_action_' + action.name)
            opens_dialog = getattr(meth, 'opens_dialog', False)
            if dev.supports_action(action):
                actions.append(
                    (_(action.value), True, (action, meth), opens_dialog))
        menu = ActionMenu(actions)
        connect_signal(menu, 'action', self._action, dev)
        row = make_action_menu_row([
            Text("["),
            Text(name),
            Text(typ),
            Text(addresses, wrap='clip'),
            menu,
            Text("]"),
        ], menu)
        self.dev_to_row[dev] = row.base_widget
        self.cur_netdevs[netdev_i:netdev_i] = [dev]
        rows.append(row)
        if dev.type == "vlan":
            info = _("VLAN {id} on interface {link}").format(
                **dev._configuration)
        elif dev.type == "bond":
            info = _("bond master for {}").format(', '.join(
                dev._net_info.bond['slaves']))
        else:
            info = " / ".join([dev.hwaddr, dev.vendor, dev.model])
        rows.append(
            Color.info_minor(TableRow([Text(""), (4, Text(info)),
                                       Text("")])))
        rows.append(Color.info_minor(TableRow([(4, Text(""))])))
        return rows

    def _build_model_inputs(self):
        netdevs = self.model.get_all_netdevs()
        masters = []
        for master in netdevs:
            if not master._net_info.bond['is_master']:
                continue
            masters.append((_("Set master to %s") % master.name, True, {
                'action': 'add_master',
                'master': master
            }, False))
        rows = []
        rows.append(
            TableRow([
                Color.info_minor(Text(header))
                for header in ["", "NAME", "TYPE", "NOTES / ADDRESSES", ""]
            ]))
        for dev in netdevs:
            rows.extend(self._rows_for_device(dev))
        return rows

    def _create_bond(self, sender):
        self.show_stretchy_overlay(BondStretchy(self))

    def show_network_error(self, action, info=None):
        self.error_showing = True
        self.bottom.contents[0:0] = [
            (Text(""), self.bottom.options()),
            (Color.info_error(self.error), self.bottom.options()),
        ]
        if action == 'stop-networkd':
            exc = info[0]
            self.error.set_text("Stopping systemd-networkd-failed: %r" %
                                (exc.stderr, ))
        elif action == 'apply':
            self.error.set_text("Network configuration could not be applied; "
                                "please verify your settings.")
        elif action == 'timeout':
            self.error.set_text("Network configuration timed out; "
                                "please verify your settings.")
        elif action == 'down':
            self.error.set_text("Downing network interfaces failed.")
        elif action == 'canceled':
            self.error.set_text("Network configuration canceled.")
        elif action == 'add-vlan':
            self.error.set_text("Failed to add a VLAN tag.")
        elif action == 'rm-dev':
            self.error.set_text("Failed to delete a virtual interface.")
        else:
            self.error.set_text("An unexpected error has occurred; "
                                "please verify your settings.")

    def done(self, result):
        if self.error_showing:
            self.bottom.contents[0:2] = []
        self.controller.network_finish(self.model.render())

    def cancel(self, button=None):
        self.controller.cancel()
예제 #27
0
class ErrorReportListStretchy(Stretchy):

    def __init__(self, app):
        self.app = app
        rows = [
            TableRow([
                Text(""),
                Text(_("DATE")),
                Text(_("KIND")),
                Text(_("STATUS")),
                Text(""),
            ])]
        self.report_to_row = {}
        for report in self.app.controllers.Error.reports:
            connect_signal(report, "changed", self._report_changed, report)
            r = self.report_to_row[report] = self.row_for_report(report)
            rows.append(r)
        self.table = TablePile(rows, colspecs={1: ColSpec(can_shrink=True)})
        widgets = [
            Text(_("Select an error report to view:")),
            Text(""),
            self.table,
            Text(""),
            button_pile([close_btn(self)]),
            ]
        super().__init__("", widgets, 2, 2)

    def open_report(self, sender, report):
        self.app.add_global_overlay(
            ErrorReportStretchy(self.app, report, False))

    def state_for_report(self, report):
        if report.seen:
            return _("VIEWED")
        return _("UNVIEWED")

    def cells_for_report(self, report):
        date = report.pr.get("Date", "???")
        icon = ClickableIcon(date)
        connect_signal(icon, 'click', self.open_report, report)
        return [
            Text("["),
            icon,
            Text(_(report.kind.value)),
            Text(_(self.state_for_report(report))),
            Text("]"),
            ]

    def row_for_report(self, report):
        return Color.menu_button(
            TableRow(self.cells_for_report(report)))

    def _report_changed(self, report):
        old_r = self.report_to_row.get(report)
        if old_r is None:
            return
        old_r = old_r.base_widget
        new_cells = self.cells_for_report(report)
        for (s1, old_c), new_c in zip(old_r.cells, new_cells):
            old_c.set_text(new_c.text)
        self.table.invalidate()
예제 #28
0
파일: raid.py 프로젝트: posm/subiquity
class MultiDeviceChooser(WidgetWrap, WantsToKnowFormField):
    signals = ['change']

    def __init__(self):
        self.table = TablePile([], spacing=1)
        self.device_to_checkbox = {}
        self.device_to_selector = {}
        self.devices = {}  # {device:active|spare}
        self.all_rows = []
        self.no_selector_rows = []
        self.supports_spares = True
        super().__init__(self.table)

    @property
    def value(self):
        return self.devices

    @value.setter
    def value(self, value):
        log.debug("MDC set value %s", {d.id: v for d, v in value.items()})
        self.devices = value
        for d, s in self.device_to_selector.items():
            if d in self.devices:
                s.enable()
                s.base_widget.value = self.devices[d]
            else:
                s.disable()
        for d, b in self.device_to_checkbox.items():
            b.set_state(d in self.devices)

    @property
    def active_devices(self):
        return {device for device, status in self.devices.items()
                if status == 'active'}

    @property
    def spare_devices(self):
        return {device for device, status in self.devices.items()
                if status == 'spare'}

    def set_supports_spares(self, val):
        if val == self.supports_spares:
            return
        self.supports_spares = val
        if val:
            for device in list(self.devices):
                self.device_to_selector[device].enable()
                selector = self.device_to_selector[device]
                self.devices[device] = selector.base_widget.value
            self.table.set_contents(self.all_rows)
        else:
            for device in list(self.devices):
                self.device_to_selector[device].disable()
                self.devices[device] = 'active'
            self.table.set_contents(self.no_selector_rows)

    def _state_change_device(self, sender, state, device):
        if state:
            if self.supports_spares:
                self.device_to_selector[device].enable()
            selector = self.device_to_selector[device]
            self.devices[device] = selector.base_widget.value
        else:
            self.device_to_selector[device].disable()
            del self.devices[device]
        self._emit('change', self.devices)

    def _select_active_spare(self, sender, value, device):
        self.devices[device] = value
        self._emit('change', self.devices)

    def _summarize(self, prefix, device):
        if device.fs() is not None:
            fs = device.fs()
            text = prefix + _("formatted as {}").format(fs.fstype)
            if fs.mount():
                text += _(", mounted at {}").format(fs.mount().path)
            else:
                text += _(", not mounted")
        else:
            text = prefix + _("unused {}").format(device.desc())
        return TableRow([(2, Color.info_minor(Text(text)))])

    def set_bound_form_field(self, bff):
        super().set_bound_form_field(bff)
        self.all_rows = []
        for kind, device in bff.form.all_devices:
            if kind == LABEL:
                self.all_rows.append(TableRow([
                    Text("    " + device.label),
                    Text(humanize_size(device.size), align='right')
                ]))
                self.no_selector_rows.append(self.all_rows[-1])
                self.all_rows.append(TableRow([
                    (2, Color.info_minor(Text("      " + device.desc())))
                ]))
                self.no_selector_rows.append(self.all_rows[-1])
            else:
                if kind == DEVICE:
                    label = device.label
                    prefix = "    "
                elif kind == PART:
                    label = _("  partition {}").format(device._number)
                    prefix = "      "
                else:
                    raise Exception("unexpected kind {}".format(kind))
                box = CheckBox(
                    label,
                    on_state_change=self._state_change_device,
                    user_data=device)
                self.device_to_checkbox[device] = box
                size = Text(humanize_size(device.size), align='right')
                self.all_rows.append(Color.menu_button(TableRow([box, size])))
                self.no_selector_rows.append(self.all_rows[-1])
                selector = Selector(['active', 'spare'])
                connect_signal(
                    selector, 'select', self._select_active_spare, device)
                selector = Toggleable(
                    UrwidPadding(
                        Color.menu_button(selector),
                        left=len(prefix)))
                selector.disable()
                self.device_to_selector[device] = selector
                self.all_rows.append(TableRow([(2, selector)]))
                # Do not append that one to no_selector_rows!
                self.all_rows.append(self._summarize(prefix, device))
                self.no_selector_rows.append(self.all_rows[-1])
        self.table.set_contents(self.all_rows)
        log.debug("%s", self.table._w.focus_position)
예제 #29
0
class DeviceList(WidgetWrap):
    def __init__(self, parent, show_available):
        self.parent = parent
        self.show_available = show_available
        self.table = TablePile(
            [],
            spacing=2,
            colspecs={
                0: ColSpec(rpad=1),
                2: ColSpec(can_shrink=True),
                4: ColSpec(min_width=9),
                5: ColSpec(rpad=1),
            })
        if show_available:
            text = _("No available devices")
        else:
            text = _("No used devices")
        self._no_devices_content = Color.info_minor(Text(text))
        super().__init__(self.table)

    _disk_INFO = _stretchy_shower(DiskInfoStretchy)
    _disk_REFORMAT = _stretchy_shower(ConfirmReformatStretchy)
    _disk_PARTITION = _stretchy_shower(PartitionStretchy)
    _disk_FORMAT = _stretchy_shower(FormatEntireStretchy)

    def _disk_REMOVE(self, disk):
        cd = disk.constructed_device(skip_dm_crypt=False)
        if cd.type == "dm_crypt":
            self.parent.model.remove_dm_crypt(cd)
            disk, cd = cd, cd.constructed_device()
        if cd.type == "raid":
            if disk in cd.devices:
                cd.devices.remove(disk)
            else:
                cd.spare_devices.remove(disk)
        elif cd.type == "lvm_volgroup":
            cd.devices.remove(disk)
        else:
            1 / 0
        disk._constructed_device = None
        self.parent.refresh_model_inputs()

    def _disk_TOGGLE_BOOT(self, disk):
        if boot.is_boot_device(disk):
            self.parent.controller.remove_boot_disk(disk)
        else:
            self.parent.controller.add_boot_disk(disk)
        self.parent.refresh_model_inputs()

    _partition_EDIT = _stretchy_shower(
        lambda parent, part: PartitionStretchy(parent, part.device, part))
    _partition_REMOVE = _disk_REMOVE
    _partition_DELETE = _stretchy_shower(ConfirmDeleteStretchy)

    _raid_EDIT = _stretchy_shower(RaidStretchy)
    _raid_PARTITION = _disk_PARTITION
    _raid_FORMAT = _disk_FORMAT
    _raid_REFORMAT = _disk_REFORMAT
    _raid_REMOVE = _disk_REMOVE
    _raid_DELETE = _partition_DELETE

    _lvm_volgroup_EDIT = _stretchy_shower(VolGroupStretchy)
    _lvm_volgroup_CREATE_LV = _disk_PARTITION
    _lvm_volgroup_DELETE = _partition_DELETE

    _lvm_partition_EDIT = _stretchy_shower(
        lambda parent, part: PartitionStretchy(parent, part.volgroup, part))
    _lvm_partition_DELETE = _partition_DELETE

    def _action(self, sender, value, device):
        action, meth = value
        log.debug('_action %s %s', action, device.id)
        meth(device)

    def _label_REMOVE(self, action, device):
        cd = device.constructed_device()
        if cd:
            return _("Remove from {device}").format(device=labels.desc(cd))
        else:
            return action.str()

    def _label_PARTITION(self, action, device):
        return _("Add {ptype} Partition").format(
            ptype=device.ptable_for_new_partition().upper())

    def _label_TOGGLE_BOOT(self, action, device):
        if boot.is_boot_device(device):
            return _("Stop Using As Boot Device")
        else:
            if self.parent.controller.supports_resilient_boot:
                if boot.all_boot_devices(self.parent.model):
                    return _("Add As Another Boot Device")
            return _("Use As Boot Device")

    def _action_menu_for_device(self, device):
        device_actions = []
        for action in DeviceAction.supported(device):
            label_meth = getattr(self, '_label_{}'.format(action.name),
                                 lambda a, d: a.str())
            label = label_meth(action, device)
            enabled, whynot = action.can(device)
            if whynot:
                assert not enabled
                enabled = True
                label += " *"
                meth = _whynot_shower(self.parent, action, whynot)
            else:
                meth_name = '_{}_{}'.format(device.type, action.name)
                meth = getattr(self, meth_name)
            if not whynot and action in [
                    DeviceAction.DELETE, DeviceAction.REFORMAT
            ]:
                label = Color.danger_button(ActionMenuOpenButton(label))
            device_actions.append(
                Action(label=label,
                       enabled=enabled,
                       value=(action, meth),
                       opens_dialog=getattr(meth, 'opens_dialog', False)))
        menu = ActionMenu(device_actions)
        connect_signal(menu, 'action', self._action, device)
        return menu

    def refresh_model_inputs(self):
        devices = [
            d for d in self.parent.model.all_devices()
            if (d.available() == self.show_available or (
                not self.show_available and d.has_unavailable_partition()))
        ]
        if len(devices) == 0:
            self._w = Padding.push_2(self._no_devices_content)
            self.table.table_rows = []
            return
        self._w = self.table
        rows = []

        rows.append(
            Color.info_minor(
                TableRow([
                    Text(""),
                    (2, Text(_("DEVICE"))),
                    Text(_("TYPE")),
                    Text(_("SIZE"), align="center"),
                    Text(""),
                    Text(""),
                ])))
        for device in devices:
            for obj, cells in summarize_device(
                    device,
                    lambda part: part.available() == self.show_available):
                if obj is not None:
                    menu = self._action_menu_for_device(obj)
                else:
                    menu = Text("")
                if obj is device:
                    start, end = '[', ']'
                else:
                    start, end = '', ''
                cells = [Text(start)] + cells + [menu, Text(end)]
                if obj is not None:
                    rows.append(make_action_menu_row(cells, menu))
                else:
                    rows.append(TableRow(cells))
            if (self.show_available and device.used > 0
                    and device.free_for_partitions > 0):
                free = humanize_size(device.free_for_partitions)
                rows.append(
                    TableRow([
                        Text(""),
                        (3, Color.info_minor(Text(_("free space")))),
                        Text(free, align="right"),
                        Text(""),
                        Text(""),
                    ]))
            rows.append(TableRow([Text("")]))
        self.table.set_contents(rows[:-1])
        if self.table._w.focus_position >= len(rows):
            self.table._w.focus_position = len(rows) - 1
        while not self.table._w.focus.selectable():
            self.table._w.focus_position -= 1
예제 #30
0
class MountList(WidgetWrap):
    def __init__(self, parent):
        self.parent = parent
        self.table = TablePile(
            [],
            spacing=2,
            colspecs={
                0: ColSpec(rpad=1),
                1: ColSpec(can_shrink=True),
                2: ColSpec(min_width=9),
                4: ColSpec(rpad=1),
                5: ColSpec(rpad=1),
            })
        self._no_mounts_content = Color.info_minor(
            Text(_("No disks or partitions mounted.")))
        super().__init__(self.table)

    def _mount_action(self, sender, action, mount):
        log.debug('_mount_action %s %s', action, mount)
        if action == 'unmount':
            self.parent.controller.delete_mount(mount)
            self.parent.refresh_model_inputs()

    def refresh_model_inputs(self):
        mountinfos = [
            MountInfo(mount=m)
            for m in sorted(self.parent.model.all_mounts(),
                            key=lambda m: (m.path == "", m.path))
        ]
        if len(mountinfos) == 0:
            self.table.set_contents([])
            self._w = Padding.push_2(self._no_mounts_content)
            return
        self._w = self.table

        rows = [
            TableRow([
                Color.info_minor(heading) for heading in [
                    Text(" "),
                    Text(_("MOUNT POINT")),
                    Text(_("SIZE"), align='center'),
                    Text(_("TYPE")),
                    Text(_("DEVICE TYPE")),
                    Text(" "),
                    Text(" "),
                ]
            ])
        ]

        for i, mi in enumerate(mountinfos):
            path_markup = mi.path
            if path_markup == "":
                path_markup = "SWAP"
            else:
                for j in range(i - 1, -1, -1):
                    mi2 = mountinfos[j]
                    if mi.startswith(mi2):
                        part1 = "/".join(mi.split_path[:len(mi2.split_path)])
                        part2 = "/".join([''] +
                                         mi.split_path[len(mi2.split_path):])
                        path_markup = [('info_minor', part1), part2]
                        break
                    if j == 0 and mi2.split_path == ['', '']:
                        path_markup = [
                            ('info_minor', "/"),
                            "/".join(mi.split_path[1:]),
                        ]
            actions = [(_("Unmount"), mi.mount.can_delete(), 'unmount')]
            menu = ActionMenu(actions)
            connect_signal(menu, 'action', self._mount_action, mi.mount)
            cells = [
                Text("["),
                Text(path_markup),
                Text(mi.size, align='right'),
                Text(mi.fstype),
                Text(mi.desc),
                menu,
                Text("]"),
            ]
            row = make_action_menu_row(cells,
                                       menu,
                                       attr_map='menu_button',
                                       focus_map={
                                           None: 'menu_button focus',
                                           'info_minor': 'menu_button focus',
                                       })
            rows.append(row)
        self.table.set_contents(rows)
        if self.table._w.focus_position >= len(rows):
            self.table._w.focus_position = len(rows) - 1