示例#1
0
class FilterSpoke(NormalSpoke):
    builderObjects = [
        "diskStore", "filterWindow", "searchModel", "multipathModel",
        "otherModel", "raidModel", "zModel"
    ]
    mainWidgetName = "filterWindow"
    uiFile = "spokes/filter.glade"

    category = SystemCategory

    title = N_("_INSTALLATION DESTINATION")

    def __init__(self, *args):
        NormalSpoke.__init__(self, *args)
        self.applyOnSkip = True

    @property
    def indirect(self):
        return True

    def apply(self):
        onlyuse = self.selected_disks[:]
        for disk in [d for d in self.storage.disks if d.name in onlyuse]:
            onlyuse.extend(
                [d.name for d in disk.ancestors if d.name not in onlyuse])

        self.data.ignoredisk.onlyuse = onlyuse
        self.data.clearpart.drives = self.selected_disks[:]

    def initialize(self):
        NormalSpoke.initialize(self)

        self.pages = [
            SearchPage(self.storage, self.builder),
            MultipathPage(self.storage, self.builder),
            OtherPage(self.storage, self.builder),
            RaidPage(self.storage, self.builder),
            ZPage(self.storage, self.builder)
        ]

        self._notebook = self.builder.get_object("advancedNotebook")

        if not arch.isS390():
            self._notebook.remove_page(-1)
            self.builder.get_object("addZFCPButton").destroy()

        if not has_fcoe():
            self.builder.get_object("addFCOEButton").destroy()

        self._store = self.builder.get_object("diskStore")
        self._addDisksButton = self.builder.get_object("addDisksButton")

    def _real_ancestors(self, disk):
        # Return a list of all the ancestors of a disk, but remove the disk
        # itself from this list.
        return [d for d in disk.ancestors if d.name != disk.name]

    def refresh(self):
        NormalSpoke.refresh(self)

        self.disks = getDisks(self.storage.devicetree)
        self.selected_disks = self.data.ignoredisk.onlyuse[:]

        self.ancestors = itertools.chain(
            *map(self._real_ancestors, self.disks))
        self.ancestors = map(lambda d: d.name, self.ancestors)

        self._store.clear()

        allDisks = []
        multipathDisks = []
        otherDisks = []
        raidDisks = []
        zDisks = []

        # Now all all the non-local disks to the store.  Everything has been set up
        # ahead of time, so there's no need to configure anything.  We first make
        # these lists of disks, then call setup on each individual page.  This is
        # because there could be page-specific setup to do that requires a complete
        # view of all the disks on that page.
        for disk in self.disks:
            if self.pages[1].ismember(disk):
                multipathDisks.append(disk)
            elif self.pages[2].ismember(disk):
                otherDisks.append(disk)
            elif self.pages[3].ismember(disk):
                raidDisks.append(disk)
            elif self.pages[4].ismember(disk):
                zDisks.append(disk)

            allDisks.append(disk)

        self.pages[0].setup(self._store, self.selected_disks, allDisks)
        self.pages[1].setup(self._store, self.selected_disks, multipathDisks)
        self.pages[2].setup(self._store, self.selected_disks, otherDisks)
        self.pages[3].setup(self._store, self.selected_disks, raidDisks)
        self.pages[4].setup(self._store, self.selected_disks, zDisks)

        self._update_summary()

    def _update_summary(self):
        summaryButton = self.builder.get_object("summary_button")
        label = summaryButton.get_children()[0]

        # We need to remove ancestor devices from the count.  Otherwise, we'll
        # end up in a situation where selecting one multipath device could
        # potentially show three devices selected (mpatha, sda, sdb for instance).
        count = len([
            disk for disk in self.selected_disks if disk not in self.ancestors
        ])

        summary = P_("%d _storage device selected",
                     "%d _storage devices selected", count) % count

        label.set_use_markup(True)
        label.set_markup("<span foreground='blue'><u>%s</u></span>" % summary)
        label.set_use_underline(True)

        summaryButton.set_visible(count > 0)
        label.set_sensitive(count > 0)

    def on_back_clicked(self, button):
        self.skipTo = "StorageSpoke"
        NormalSpoke.on_back_clicked(self, button)

    def on_summary_clicked(self, button):
        dialog = SelectedDisksDialog(self.data)

        # Include any disks selected in the initial storage spoke, plus any
        # selected in this filter UI.
        disks = [
            disk for disk in self.disks if disk.name in self.selected_disks
        ]
        free_space = self.storage.getFreeSpace(disks=disks)

        with enlightbox(self.window, dialog.window):
            dialog.refresh(disks, free_space, showRemove=False, setBoot=False)
            dialog.run()

    def on_find_clicked(self, button):
        n = self._notebook.get_current_page()
        self.pages[n].filterActive = True
        self.pages[n].model.refilter()

    def on_clear_icon_clicked(self, entry, icon_pos, event):
        if icon_pos == Gtk.EntryIconPosition.SECONDARY:
            entry.set_text("")

    def on_page_switched(self, notebook, newPage, newPageNum, *args):
        self.pages[newPageNum].model.refilter()
        notebook.get_nth_page(newPageNum).show_all()

    def on_row_toggled(self, button, path):
        if not path:
            return

        page_index = self._notebook.get_current_page()
        filter_model = self.pages[page_index].model
        model_itr = filter_model.get_iter(path)
        itr = filter_model.convert_iter_to_child_iter(model_itr)
        self._store[itr][1] = not self._store[itr][1]

        if self._store[itr][1] and self._store[itr][
                3] not in self.selected_disks:
            self.selected_disks.append(self._store[itr][3])
        elif not self._store[itr][1] and self._store[itr][
                3] in self.selected_disks:
            self.selected_disks.remove(self._store[itr][3])

        self._update_summary()

    def on_add_iscsi_clicked(self, widget, *args):
        dialog = ISCSIDialog(self.data, self.storage)

        with enlightbox(self.window, dialog.window):
            dialog.refresh()
            dialog.run()

        # We now need to refresh so any new disks picked up by adding advanced
        # storage are displayed in the UI.
        self.refresh()

    def on_add_fcoe_clicked(self, widget, *args):
        dialog = FCoEDialog(self.data, self.storage)

        with enlightbox(self.window, dialog.window):
            dialog.refresh()
            dialog.run()

        # We now need to refresh so any new disks picked up by adding advanced
        # storage are displayed in the UI.
        self.refresh()

    def on_add_zfcp_clicked(self, widget, *args):
        dialog = ZFCPDialog(self.data, self.storage)

        with enlightbox(self.window, dialog.window):
            dialog.refresh()
            dialog.run()

        # We now need to refresh so any new disks picked up by adding advanced
        # storage are displayed in the UI.
        self.refresh()

    ##
    ## SEARCH TAB SIGNAL HANDLERS
    ##
    def on_search_type_changed(self, combo):
        ndx = combo.get_active()

        notebook = self.builder.get_object("searchTypeNotebook")
        findButton = self.builder.get_object("searchFindButton")

        findButton.set_sensitive(ndx != 0)
        notebook.set_current_page(ndx)

    ##
    ## MULTIPATH TAB SIGNAL HANDLERS
    ##
    def on_multipath_type_changed(self, combo):
        ndx = combo.get_active()

        notebook = self.builder.get_object("multipathTypeNotebook")
        findButton = self.builder.get_object("multipathFindButton")

        findButton.set_sensitive(ndx != 0)
        notebook.set_current_page(ndx)

    ##
    ## OTHER TAB SIGNAL HANDLERS
    ##
    def on_other_type_combo_changed(self, combo):
        ndx = combo.get_active()

        notebook = self.builder.get_object("otherTypeNotebook")
        findButton = self.builder.get_object("otherFindButton")

        findButton.set_sensitive(ndx != 0)
        notebook.set_current_page(ndx)

    ##
    ## Z TAB SIGNAL HANDLERS
    ##
    def on_z_type_combo_changed(self, combo):
        ndx = combo.get_active()

        notebook = self.builder.get_object("zTypeNotebook")
        findButton = self.builder.get_object("zFindButton")

        findButton.set_sensitive(ndx != 0)
        notebook.set_current_page(ndx)
示例#2
0
class UserSpoke(FirstbootSpokeMixIn, EditTUISpoke):
    """
       .. inheritance-diagram:: UserSpoke
          :parts: 3
    """
    title = N_("User creation")
    category = UserSettingsCategory

    edit_fields = [
        Entry("Create user", "_create", EditTUISpoke.CHECK, True),
        Entry("Fullname", "gecos", GECOS_VALID,
              lambda self, args: args._create),
        Entry("Username", "name", check_username,
              lambda self, args: args._create),
        Entry("Use password", "_use_password", EditTUISpoke.CHECK,
              lambda self, args: args._create),
        Entry("Password", "_password", EditTUISpoke.PASSWORD,
              lambda self, args: args._use_password and args._create),
        Entry("Administrator", "_admin", EditTUISpoke.CHECK,
              lambda self, args: args._create),
        Entry("Groups", "_groups", GROUPLIST_SIMPLE_VALID,
              lambda self, args: args._create)
    ]

    @classmethod
    def should_run(cls, environment, data):
        # the user spoke should run always in the anaconda and in firstboot only
        # when doing reconfig or if no user has been created in the installation
        if environment == ANACONDA_ENVIRON:
            return True
        elif environment == FIRSTBOOT_ENVIRON and data is None:
            # cannot decide, stay in the game and let another call with data
            # available (will come) decide
            return True
        elif environment == FIRSTBOOT_ENVIRON and data and \
                (data.firstboot.firstboot == FIRSTBOOT_RECONFIG or \
                     len(data.user.userList) == 0):
            return True
        else:
            return False

    def __init__(self, app, data, storage, payload, instclass):
        FirstbootSpokeMixIn.__init__(self)
        EditTUISpoke.__init__(self, app, data, storage, payload, instclass,
                              "user")
        if self.data.user.userList:
            self.args = self.data.user.userList[0]
            self.args._create = True
        else:
            self.args = self.data.UserData()
            self.args._create = False

        self.args._use_password = self.args.isCrypted or self.args.password

        # Keep the password separate from the kickstart data until apply()
        # so that all of the properties are set at once
        self.args._password = ""

        self.errors = []

    def refresh(self, args=None):
        self.args._admin = "wheel" in self.args.groups
        self.args._groups = ", ".join(self.args.groups)

        # if we have any errors, display them
        while self.errors:
            print(self.errors.pop())

        return EditTUISpoke.refresh(self, args)

    @property
    def completed(self):
        """ Verify a user is created; verify pw is set if option checked. """
        if len(self.data.user.userList) > 0:
            if self.args._use_password and not bool(self.args.password
                                                    or self.args.isCrypted):
                return False
            else:
                return True
        else:
            return False

    @property
    def showable(self):
        return not (self.completed and flags.automatedInstall and
                    self.data.user.seen and not self.dialog.policy.changesok)

    @property
    def mandatory(self):
        """ Only mandatory if the root pw hasn't been set in the UI
            eg. not mandatory if the root account was locked in a kickstart
        """
        return not self.data.rootpw.password and not self.data.rootpw.lock

    @property
    def status(self):
        if len(self.data.user.userList) == 0:
            return _("No user will be created")
        elif self.args._use_password and not bool(self.args.password
                                                  or self.args.isCrypted):
            return _("You must set a password")
        elif "wheel" in self.data.user.userList[0].groups:
            return _("Administrator %s will be created"
                     ) % self.data.user.userList[0].name
        else:
            return _(
                "User %s will be created") % self.data.user.userList[0].name

    def input(self, args, key):
        self.dialog.wrong_input_message = None
        try:
            field = self.visible_fields[int(key) - 1]
        except (ValueError, IndexError):
            pass
        else:
            if field.attribute == "gecos":
                self.dialog.wrong_input_message = _(
                    "Full name can't contain the ':' character")
            elif field.attribute == "name":
                # more granular message is returned by check_username
                pass
            elif field.attribute == "_groups":
                self.dialog.wrong_input_message = _(
                    "Either a group name in the group list is invalid or groups are not separated by a comma"
                )

        return EditTUISpoke.input(self, args, key)

    def apply(self):
        if self.args.gecos and not self.args.name:
            username = guess_username(self.args.gecos)
            valid, msg = check_username(username)
            if not valid:
                self.errors.append(
                    _("Invalid user name: %(name)s.\n%(error_message)s") % {
                        "name": username,
                        "error_message": msg
                    })
            else:
                self.args.name = guess_username(self.args.gecos)

        self.args.groups = [
            g.strip() for g in self.args._groups.split(",") if g
        ]

        # Add or remove the user from wheel group
        if self.args._admin and "wheel" not in self.args.groups:
            self.args.groups.append("wheel")
        elif not self.args._admin and "wheel" in self.args.groups:
            self.args.groups.remove("wheel")

        # Add or remove the user from userlist as needed
        if self.args._create and (self.args not in self.data.user.userList
                                  and self.args.name):
            self.data.user.userList.append(self.args)
        elif (not self.args._create) and (self.args
                                          in self.data.user.userList):
            self.data.user.userList.remove(self.args)

        # encrypt and store password only if user entered anything; this should
        # preserve passwords set via kickstart
        if self.args._use_password and len(self.args._password) > 0:
            self.args.password = self.args._password
            self.args.isCrypted = True
            self.args.password_kickstarted = False
        # clear pw when user unselects to use pw
        else:
            self.args.password = ""
            self.args.isCrypted = False
            self.args.password_kickstarted = False
示例#3
0
from blivet.devicefactory import SIZE_POLICY_MAX
from blivet.devicefactory import DEVICE_TYPE_LVM
from blivet.devicefactory import DEVICE_TYPE_BTRFS
from blivet.devicefactory import DEVICE_TYPE_LVM_THINP
from blivet.devicefactory import DEVICE_TYPE_MD
from blivet.devicefactory import get_supported_raid_levels
from blivet.devicelibs import btrfs
from blivet.devicelibs import mdraid
from blivet.devicelibs import raid

import logging

log = logging.getLogger("anaconda")

RAID_NOT_ENOUGH_DISKS = N_("The RAID level you have selected (%(level)s) "
                           "requires more disks (%(min)d) than you "
                           "currently have selected (%(count)d).")

CONTAINER_DIALOG_TITLE = N_("CONFIGURE %(container_type)s")
CONTAINER_DIALOG_TEXT = N_("Please create a name for this %(container_type)s "
                           "and select at least one disk below.")

ContainerType = namedtuple("ContainerType", ["name", "label"])

CONTAINER_TYPES = {
    DEVICE_TYPE_LVM:
    ContainerType(
        N_("Volume Group"),
        CN_("GUI|Custom Partitioning|Configure|Devices", "_Volume Group:")),
    DEVICE_TYPE_LVM_THINP:
    ContainerType(
示例#4
0
def get_container_type(device_type):
    return CONTAINER_TYPES.get(
        device_type,
        ContainerType(
            N_("container"),
            CN_("GUI|Custom Partitioning|Configure|Devices", "container")))
示例#5
0
class ProgressSpoke(StandaloneTUISpoke):
    title = N_("Progress")

    postForHub = SummaryHub
    priority = 0

    def __init__(self, app, ksdata, storage, payload, instclass):
        StandaloneTUISpoke.__init__(self, app, ksdata, storage, payload,
                                    instclass)
        self._stepped = False

    @property
    def completed(self):
        # this spoke is never completed, initially
        return False

    def _update_progress(self):
        """Handle progress updates from install thread."""

        from pyanaconda.progress import progressQ
        import Queue

        q = progressQ.q

        # Grab all messages may have appeared since last time this method ran.
        while True:
            # Attempt to get a message out of the queue for how we should update
            # the progress bar.  If there's no message, don't error out.
            # Also flush the communication Queue at least once a second and
            # process it's events so we can react to async evens (like a thread
            # throwing an exception)
            while True:
                try:
                    (code, args) = q.get(timeout=1)
                    break
                except Queue.Empty:
                    pass
                finally:
                    self.app.process_events()

            if code == progressQ.PROGRESS_CODE_INIT:
                # Text mode doesn't have a finite progress bar
                pass
            elif code == progressQ.PROGRESS_CODE_STEP:
                # Instead of updating a progress bar, we just print a pip
                # but print it without a new line.
                sys.stdout.write('.')
                sys.stdout.flush()
                # Use _stepped as an indication to if we need a newline before
                # the next message
                self._stepped = True
            elif code == progressQ.PROGRESS_CODE_MESSAGE:
                # This should already be translated
                if self._stepped:
                    # Get a new line in case we've done a step before
                    self._stepped = False
                    print('')
                print(args[0])
            elif code == progressQ.PROGRESS_CODE_COMPLETE:
                # There shouldn't be any more progress updates, so return
                q.task_done()

                if self._stepped:
                    print('')
                return True
            elif code == progressQ.PROGRESS_CODE_QUIT:
                sys.exit(args[0])

            q.task_done()
        return True

    def refresh(self, args=None):
        from pyanaconda.install import doInstall, doConfiguration
        from pyanaconda.threads import threadMgr, AnacondaThread

        # We print this here because we don't really use the window object
        print(_(self.title))

        threadMgr.add(
            AnacondaThread(name=THREAD_INSTALL,
                           target=doInstall,
                           args=(self.storage, self.payload, self.data,
                                 self.instclass)))

        # This will run until we're all done with the install thread.
        self._update_progress()

        threadMgr.add(
            AnacondaThread(name=THREAD_CONFIGURATION,
                           target=doConfiguration,
                           args=(self.storage, self.payload, self.data,
                                 self.instclass)))

        # This will run until we're all done with the configuration thread.
        self._update_progress()

        iutil.ipmi_report(IPMI_FINISHED)

        # kickstart install, continue automatically if reboot or shutdown selected
        if flags.automatedInstall and self.data.reboot.action in [
                KS_REBOOT, KS_SHUTDOWN
        ]:
            # Just pretend like we got input, and our input doesn't care
            # what it gets, it just quits.
            self.input(None, None)

        return True

    def prompt(self, args=None):
        return (_("\tInstallation complete.  Press return to quit"))

    def input(self, args, key):
        # There is nothing to do here, just raise to exit the spoke
        raise ExitAllMainLoops()

    # Override Spoke.apply
    def apply(self):
        pass
示例#6
0
from pyanaconda.i18n import _, N_, CN_
from pyanaconda.constants import DEFAULT_KEYBOARD, THREAD_KEYBOARD_INIT, THREAD_ADD_LAYOUTS_INIT
from pyanaconda.ui.communication import hubQ
from pyanaconda.iutil import strip_accents
from pyanaconda.threads import threadMgr, AnacondaThread
from pyanaconda.iutil import have_word_match

import locale as locale_mod

import logging
log = logging.getLogger("anaconda")

__all__ = ["KeyboardSpoke"]

# %s will be replaced by key combination like Alt+Shift
LAYOUT_SWITCHING_INFO = N_("%s to switch layouts.")

ADD_LAYOUTS_INITIALIZE_THREAD = "AnaAddLayoutsInitializeThread"


def _show_layout(column, renderer, model, itr, wrapper):
    return wrapper.get_layout_variant_description(model[itr][0])


def _show_description(column, renderer, model, itr, wrapper):
    value = wrapper.get_switch_opt_description(model[itr][0])
    if model[itr][1]:
        value = "<b>%s</b>" % escape_markup(value)
    return value

示例#7
0
文件: source.py 项目: yaneti/anaconda
class SourceSpoke(EditTUISpoke, SourceSwitchHandler):
    """ Spoke used to customize the install source repo.

       .. inheritance-diagram:: SourceSpoke
          :parts: 3
    """
    title = N_("Installation source")
    category = SoftwareCategory

    _protocols = (N_("Closest mirror"), "http://", "https://", "ftp://", "nfs")

    # default to 'closest mirror', as done in the GUI
    _selection = 1

    def __init__(self, app, data, storage, payload, instclass):
        EditTUISpoke.__init__(self, app, data, storage, payload, instclass)
        SourceSwitchHandler.__init__(self)
        self._ready = False
        self._error = False
        self._cdrom = None

    def initialize(self):
        EditTUISpoke.initialize(self)

        threadMgr.add(
            AnacondaThread(name=THREAD_SOURCE_WATCHER,
                           target=self._initialize))
        payloadMgr.addListener(payloadMgr.STATE_ERROR, self._payload_error)

    def _initialize(self):
        """ Private initialize. """
        threadMgr.wait(THREAD_PAYLOAD)
        # If we've previously set up to use a CD/DVD method, the media has
        # already been mounted by payload.setup.  We can't try to mount it
        # again.  So just use what we already know to create the selector.
        # Otherwise, check to see if there's anything available.
        if self.data.method.method == "cdrom":
            self._cdrom = self.payload.install_device
        elif not flags.automatedInstall:
            self._cdrom = opticalInstallMedia(self.storage.devicetree)

        self._ready = True

    def _payload_error(self):
        self._error = True

    def _repo_status(self):
        """ Return a string describing repo url or lack of one. """
        if self.data.method.method == "url":
            return self.data.method.url or self.data.method.mirrorlist
        elif self.data.method.method == "nfs":
            return _("NFS server %s") % self.data.method.server
        elif self.data.method.method == "cdrom":
            return _("Local media")
        elif self.data.method.method == "harddrive":
            if not self.data.method.dir:
                return _("Error setting up software source")
            return os.path.basename(self.data.method.dir)
        elif self.payload.baseRepo:
            return _("Closest mirror")
        else:
            return _("Nothing selected")

    @property
    def showable(self):
        return isinstance(self.payload, PackagePayload)

    @property
    def status(self):
        if self._error:
            return _("Error setting up software source")
        elif not self.ready:
            return _("Processing...")
        else:
            return self._repo_status()

    @property
    def completed(self):
        if flags.automatedInstall and self.ready and not self.payload.baseRepo:
            return False
        else:
            return not self._error and self.ready and (
                self.data.method.method or self.payload.baseRepo)

    def refresh(self, args=None):
        EditTUISpoke.refresh(self, args)

        threadMgr.wait(THREAD_PAYLOAD)

        _methods = [_("CD/DVD"), _("local ISO file"), _("Network")]

        if self.data.method.method == "harddrive" and \
           get_mount_device(DRACUT_ISODIR) == get_mount_device(DRACUT_REPODIR):
            message = _(
                "The installation source is in use by the installer and cannot be changed."
            )
            self._window += [TextWidget(message), ""]
            return True

        if args == 3:
            text = [TextWidget(_(p)) for p in self._protocols]
        else:
            self._window += [
                TextWidget(_("Choose an installation source type."))
            ]
            text = [TextWidget(m) for m in _methods]

        def _prep(i, w):
            """ Mangle our text to make it look pretty on screen. """
            number = TextWidget("%2d)" % (i + 1))
            return ColumnWidget([(4, [number]), (None, [w])], 1)

        # gnarl and mangle all of our widgets so things look pretty on screen
        choices = [_prep(i, w) for i, w in enumerate(text)]

        displayed = ColumnWidget([(78, choices)], 1)
        self._window.append(displayed)

        return True

    def input(self, args, key):
        """ Handle the input; this decides the repo source. """
        try:
            num = int(key)
        except ValueError:
            return key

        if args == 3:
            # network install
            self._selection = num
            if self._selection == 1:
                # closest mirror
                self.set_source_closest_mirror()
                self.apply()
                self.close()
                return INPUT_PROCESSED
            elif self._selection in range(2, 5):
                # preliminary URL source switch
                self.set_source_url()
                newspoke = SpecifyRepoSpoke(self.app, self.data, self.storage,
                                            self.payload, self.instclass,
                                            self._selection)
                self.app.switch_screen_modal(newspoke)
                self.apply()
                self.close()
                return INPUT_PROCESSED
            elif self._selection == 5:
                # nfs
                # preliminary NFS source switch
                self.set_source_nfs()
                newspoke = SpecifyNFSRepoSpoke(self.app, self.data,
                                               self.storage, self.payload,
                                               self.instclass, self._selection,
                                               self._error)
                self.app.switch_screen_modal(newspoke)
                self.apply()
                self.close()
                return INPUT_PROCESSED
        elif num == 2:
            # local ISO file (HDD ISO)
            self._selection = num
            newspoke = SelectDeviceSpoke(self.app, self.data, self.storage,
                                         self.payload, self.instclass)
            self.app.switch_screen_modal(newspoke)
            self.apply()
            self.close()
            return INPUT_PROCESSED
        else:
            # mounted ISO
            if num == 1:
                # iso selected, just set some vars and return to main hub
                self.set_source_cdrom()
                self.payload.install_device = self._cdrom
                self.apply()
                self.close()
                return INPUT_PROCESSED
            else:
                self.app.switch_screen(self, num)
        return INPUT_PROCESSED

    @property
    def ready(self):
        """ Check if the spoke is ready. """
        return (self._ready and not threadMgr.get(THREAD_PAYLOAD)
                and not threadMgr.get(THREAD_CHECK_SOFTWARE))

    def apply(self):
        """ Execute the selections made. """
        # If askmethod was provided on the command line, entering the source
        # spoke wipes that out.
        if flags.askmethod:
            flags.askmethod = False

        # if we had any errors, e.g. from a previous attempt to set the source,
        # clear them at this point
        self._error = False

        payloadMgr.restartThread(self.storage,
                                 self.data,
                                 self.payload,
                                 self.instclass,
                                 checkmount=False)
示例#8
0
文件: source.py 项目: yaneti/anaconda
class SelectISOSpoke(NormalTUISpoke, SourceSwitchHandler):
    """ Select an ISO to use as install source. """
    title = N_("Select an ISO to use as install source")
    category = SoftwareCategory

    def __init__(self, app, data, storage, payload, instclass, device):
        NormalTUISpoke.__init__(self, app, data, storage, payload, instclass)
        SourceSwitchHandler.__init__(self)
        self.selection = None
        self.args = self.data.method
        self._device = device
        self._mount_device()
        self._isos = self._getISOs()

    def refresh(self, args=None):
        NormalTUISpoke.refresh(self, args)

        if self._isos:
            isos = [TextWidget(iso) for iso in self._isos]

            def _prep(i, w):
                """ Mangle our text to make it look pretty on screen. """
                number = TextWidget("%2d)" % (i + 1))
                return ColumnWidget([(4, [number]), (None, [w])], 1)

            # gnarl and mangle all of our widgets so things look pretty on screen
            choices = [_prep(i, w) for i, w in enumerate(isos)]

            displayed = ColumnWidget([(78, choices)], 1)
            self._window.append(displayed)
        else:
            message = _("No *.iso files found in device root folder")
            self._window += [TextWidget(message), ""]

        return True

    def input(self, args, key):
        if key == "c":
            self.apply()
            self.close()
            return key
        try:
            num = int(key)
            # get the ISO path
            self._current_iso_path = self._isos[num - 1]
            self.apply()
            self.close()
            return True
        except (IndexError, ValueError):
            return key

    @property
    def indirect(self):
        return True

    def _mount_device(self):
        """ Mount the device so we can search it for ISOs. """
        mounts = get_mount_paths(self._device.path)
        # We have to check both ISO_DIR and the DRACUT_ISODIR because we
        # still reference both, even though /mnt/install is a symlink to
        # /run/install.  Finding mount points doesn't handle the symlink
        if ISO_DIR not in mounts and DRACUT_ISODIR not in mounts:
            # We're not mounted to either location, so do the mount
            self._device.format.mount(mountpoint=ISO_DIR)

    def _unmount_device(self):
        self._device.format.unmount()

    def _getISOs(self):
        """List all *.iso files in the root folder
        of the currently selected device.

        TODO: advanced ISO file selection
        :returns: a list of *.iso file paths
        :rtype: list
        """
        isos = []
        for filename in os.listdir(ISO_DIR):
            if fnmatch.fnmatch(filename.lower(), "*.iso"):
                isos.append(filename)
        return isos

    def apply(self):
        """ Apply all of our changes. """

        if self._current_iso_path:
            # If a hdd iso source has already been selected previously we need
            # to clear it now.
            # Otherwise we would get a crash if the same iso was selected again
            # as _unmount_device() would try to unmount a partition that is in use
            # due to the payload still holding on to the ISO file.
            if self.data.method.method == "harddrive":
                self.unset_source()
            self.set_source_hdd_iso(self._device, self._current_iso_path)
        # unmount the device - the payload will remount it anyway
        # (if it uses it)
        self._unmount_device()
示例#9
0
文件: source.py 项目: yaneti/anaconda
class SelectDeviceSpoke(NormalTUISpoke):
    """ Select device containing the install source ISO file. """
    title = N_("Select device containing the ISO file")
    category = SoftwareCategory

    def __init__(self, app, data, storage, payload, instclass):
        NormalTUISpoke.__init__(self, app, data, storage, payload, instclass)
        self._currentISOFile = None
        self._mountable_devices = self._get_mountable_devices()
        self._device = None

    @property
    def indirect(self):
        return True

    def _sanitize_model(self, model):
        return model.replace("_", " ")

    def _get_mountable_devices(self):
        disks = []
        fstring = "%(model)s %(path)s (%(size)s MB) %(format)s %(label)s"
        for dev in potentialHdisoSources(self.storage.devicetree):
            # path model size format type uuid of format
            dev_info = {
                "model": self._sanitize_model(dev.disk.model),
                "path": dev.path,
                "size": dev.size,
                "format": dev.format.name or "",
                "label": dev.format.label or dev.format.uuid or ""
            }
            disks.append([dev, fstring % dev_info])
        return disks

    def refresh(self, args=None):
        NormalTUISpoke.refresh(self, args)

        # check if the storage refresh thread is running
        if threadMgr.get(THREAD_STORAGE_WATCHER):
            # storage refresh is running - just report it
            # so that the user can refresh until it is done
            # TODO: refresh once the thread is done ?
            message = _(PAYLOAD_STATUS_PROBING_STORAGE)
            self._window += [TextWidget(message), ""]
            return True

        # check if there are any mountable devices
        if self._mountable_devices:

            def _prep(i, w):
                """ Mangle our text to make it look pretty on screen. """
                number = TextWidget("%2d)" % (i + 1))
                return ColumnWidget([(4, [number]), (None, [w])], 1)

            devices = [TextWidget(d[1]) for d in self._mountable_devices]

            # gnarl and mangle all of our widgets so things look pretty on
            # screen
            choices = [_prep(i, w) for i, w in enumerate(devices)]

            displayed = ColumnWidget([(78, choices)], 1)
            self._window.append(displayed)

        else:
            message = _("No mountable devices found")
            self._window += [TextWidget(message), ""]
        return True

    def input(self, args, key):
        try:
            # try to switch to one of the mountable devices
            # to look for ISOs
            num = int(key)
            device = self._mountable_devices[num -
                                             1][0]  # get the device object
            self._device = device
            newspoke = SelectISOSpoke(self.app, self.data, self.storage,
                                      self.payload, self.instclass, device)
            self.app.switch_screen_modal(newspoke)
            self.close()
            return True
        except (IndexError, ValueError):
            # either the input was not a number or
            # we don't have the disk for the given number
            return key

    # Override Spoke.apply
    def apply(self):
        pass