2014-04-07 12:38:09 +00:00
|
|
|
# Software selection text spoke
|
|
|
|
#
|
|
|
|
# Copyright (C) 2013 Red Hat, Inc.
|
|
|
|
#
|
|
|
|
# This copyrighted material is made available to anyone wishing to use,
|
|
|
|
# modify, copy, or redistribute it subject to the terms and conditions of
|
|
|
|
# the GNU General Public License v.2, or (at your option) any later version.
|
|
|
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
# ANY WARRANTY expressed or implied, including the implied warranties of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
|
|
|
# Public License for more details. You should have received a copy of the
|
|
|
|
# GNU General Public License along with this program; if not, write to the
|
|
|
|
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
|
|
# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
|
|
|
|
# source code or documentation are not subject to the GNU General Public
|
|
|
|
# License and may only be used or replicated with the express permission of
|
|
|
|
# Red Hat, Inc.
|
|
|
|
#
|
|
|
|
# Red Hat Author(s): Samantha N. Bueno <sbueno@redhat.com>
|
|
|
|
#
|
|
|
|
|
|
|
|
from pyanaconda.flags import flags
|
2015-03-23 11:36:12 +00:00
|
|
|
from pyanaconda.ui.categories.software import SoftwareCategory
|
2014-04-07 12:38:09 +00:00
|
|
|
from pyanaconda.ui.tui.spokes import NormalTUISpoke
|
|
|
|
from pyanaconda.ui.tui.simpleline import TextWidget, ColumnWidget, CheckboxWidget
|
|
|
|
from pyanaconda.threads import threadMgr, AnacondaThread
|
2015-05-30 11:20:59 +00:00
|
|
|
from pyanaconda.packaging import DependencyError, PackagePayload, payloadMgr
|
|
|
|
from pyanaconda.i18n import N_, _, C_
|
2014-04-07 12:38:09 +00:00
|
|
|
|
2015-03-23 11:36:12 +00:00
|
|
|
from pyanaconda.constants import THREAD_PAYLOAD
|
|
|
|
from pyanaconda.constants import THREAD_CHECK_SOFTWARE
|
2015-05-30 11:20:59 +00:00
|
|
|
from pyanaconda.constants import THREAD_SOFTWARE_WATCHER
|
2014-04-07 12:38:09 +00:00
|
|
|
from pyanaconda.constants_text import INPUT_PROCESSED
|
|
|
|
|
|
|
|
__all__ = ["SoftwareSpoke"]
|
|
|
|
|
|
|
|
|
|
|
|
class SoftwareSpoke(NormalTUISpoke):
|
|
|
|
""" Spoke used to read new value of text to represent source repo. """
|
2015-03-23 11:36:12 +00:00
|
|
|
title = N_("Software selection")
|
|
|
|
category = SoftwareCategory
|
2014-04-07 12:38:09 +00:00
|
|
|
|
|
|
|
def __init__(self, app, data, storage, payload, instclass):
|
|
|
|
NormalTUISpoke.__init__(self, app, data, storage, payload, instclass)
|
|
|
|
self.errors = []
|
|
|
|
self._tx_id = None
|
2015-05-30 11:20:59 +00:00
|
|
|
self._selection = None
|
2014-04-07 12:38:09 +00:00
|
|
|
self.environment = None
|
|
|
|
|
|
|
|
# for detecting later whether any changes have been made
|
|
|
|
self._origEnv = None
|
|
|
|
|
|
|
|
# are we taking values (package list) from a kickstart file?
|
|
|
|
self._kickstarted = flags.automatedInstall and self.data.packages.seen
|
|
|
|
|
2015-05-30 11:20:59 +00:00
|
|
|
# Register event listeners to update our status on payload events
|
|
|
|
payloadMgr.addListener(payloadMgr.STATE_START, self._payload_start)
|
|
|
|
payloadMgr.addListener(payloadMgr.STATE_FINISHED, self._payload_finished)
|
|
|
|
payloadMgr.addListener(payloadMgr.STATE_ERROR, self._payload_error)
|
|
|
|
|
|
|
|
def initialize(self):
|
|
|
|
# Start a thread to wait for the payload and run the first, automatic
|
|
|
|
# dependency check
|
|
|
|
super(SoftwareSpoke, self).initialize()
|
|
|
|
threadMgr.add(AnacondaThread(name=THREAD_SOFTWARE_WATCHER,
|
|
|
|
target=self._initialize))
|
|
|
|
|
|
|
|
def _initialize(self):
|
|
|
|
threadMgr.wait(THREAD_PAYLOAD)
|
|
|
|
|
|
|
|
if not self._kickstarted:
|
|
|
|
# If an environment was specified in the instclass, use that.
|
|
|
|
# Otherwise, select the first environment.
|
|
|
|
if self.payload.environments:
|
|
|
|
environments = self.payload.environments
|
|
|
|
instclass = self.payload.instclass
|
|
|
|
|
|
|
|
if instclass and instclass.defaultPackageEnvironment and \
|
|
|
|
instclass.defaultPackageEnvironment in environments:
|
|
|
|
self._selection = environments.index(instclass.defaultPackageEnvironment)
|
|
|
|
else:
|
|
|
|
self._selection = 0
|
|
|
|
|
|
|
|
# Apply the initial selection
|
|
|
|
self._apply()
|
|
|
|
|
|
|
|
def _payload_start(self):
|
|
|
|
# Source is changing, invalidate the software selection and clear the
|
|
|
|
# errors
|
|
|
|
self._selection = None
|
|
|
|
self.errors = []
|
|
|
|
|
|
|
|
def _payload_finished(self):
|
|
|
|
self.environment = self.data.packages.environment
|
|
|
|
|
|
|
|
def _payload_error(self):
|
|
|
|
self.errors = [payloadMgr.error]
|
|
|
|
|
2015-03-23 11:36:12 +00:00
|
|
|
@property
|
|
|
|
def showable(self):
|
|
|
|
return isinstance(self.payload, PackagePayload)
|
2014-04-07 12:38:09 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def status(self):
|
|
|
|
""" Where we are in the process """
|
|
|
|
if self.errors:
|
|
|
|
return _("Error checking software selection")
|
|
|
|
if not self.ready:
|
|
|
|
return _("Processing...")
|
|
|
|
if not self.payload.baseRepo:
|
|
|
|
return _("Installation source not set up")
|
|
|
|
if not self.txid_valid:
|
|
|
|
return _("Source changed - please verify")
|
|
|
|
|
|
|
|
if not self.environment:
|
|
|
|
# Ks installs with %packages will have an env selected, unless
|
|
|
|
# they did an install without a desktop environment. This should
|
|
|
|
# catch that one case.
|
|
|
|
if self._kickstarted:
|
|
|
|
return _("Custom software selected")
|
|
|
|
return _("Nothing selected")
|
|
|
|
|
|
|
|
return self.payload.environmentDescription(self.environment)[0]
|
|
|
|
|
|
|
|
@property
|
|
|
|
def completed(self):
|
2015-03-23 11:36:12 +00:00
|
|
|
""" Make sure our threads are done running and vars are set.
|
|
|
|
|
|
|
|
WARNING: This can be called before the spoke is finished initializing
|
|
|
|
if the spoke starts a thread. It should make sure it doesn't access
|
|
|
|
things until they are completely setup.
|
|
|
|
"""
|
|
|
|
processingDone = self.ready and not self.errors and self.txid_valid
|
2014-04-07 12:38:09 +00:00
|
|
|
|
|
|
|
if flags.automatedInstall:
|
|
|
|
return processingDone and self.payload.baseRepo and self.data.packages.seen
|
|
|
|
else:
|
2015-03-23 11:36:12 +00:00
|
|
|
return processingDone and self.payload.baseRepo and self.environment is not None
|
2014-04-07 12:38:09 +00:00
|
|
|
|
|
|
|
def refresh(self, args=None):
|
|
|
|
""" Refresh screen. """
|
|
|
|
NormalTUISpoke.refresh(self, args)
|
|
|
|
|
2015-05-30 11:20:59 +00:00
|
|
|
threadMgr.wait(THREAD_PAYLOAD)
|
|
|
|
|
2014-04-07 12:38:09 +00:00
|
|
|
if not self.payload.baseRepo:
|
|
|
|
message = TextWidget(_("Installation source needs to be set up first."))
|
|
|
|
self._window.append(message)
|
|
|
|
|
|
|
|
# add some more space below
|
|
|
|
self._window.append(TextWidget(""))
|
|
|
|
return True
|
|
|
|
|
|
|
|
threadMgr.wait(THREAD_CHECK_SOFTWARE)
|
|
|
|
|
|
|
|
# put a title above the list and some space below it
|
|
|
|
self._window.append(TextWidget(_("Base environment")))
|
|
|
|
self._window.append(TextWidget(""))
|
|
|
|
|
|
|
|
environments = self.payload.environments
|
|
|
|
|
|
|
|
displayed = []
|
|
|
|
for env in environments:
|
|
|
|
name = self.payload.environmentDescription(env)[0]
|
|
|
|
|
|
|
|
displayed.append(CheckboxWidget(title="%s" % name, completed=(environments.index(env) == self._selection)))
|
|
|
|
|
|
|
|
def _prep(i, w):
|
|
|
|
""" Do some format magic for display. """
|
|
|
|
num = TextWidget("%2d)" % (i + 1))
|
|
|
|
return ColumnWidget([(4, [num]), (None, [w])], 1)
|
|
|
|
|
|
|
|
# split list of DE's into two columns
|
|
|
|
mid = len(environments) / 2
|
|
|
|
left = [_prep(i, w) for i, w in enumerate(displayed) if i <= mid]
|
|
|
|
right = [_prep(i, w) for i, w in enumerate(displayed) if i > mid]
|
|
|
|
|
|
|
|
cw = ColumnWidget([(38, left), (38, right)], 2)
|
|
|
|
self._window.append(cw)
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
def input(self, args, key):
|
|
|
|
""" Handle the input; this chooses the desktop environment. """
|
|
|
|
try:
|
|
|
|
keyid = int(key) - 1
|
|
|
|
except ValueError:
|
2015-05-30 11:20:59 +00:00
|
|
|
# TRANSLATORS: 'c' to continue
|
|
|
|
if key.lower() == C_("TUI|Spoke Navigation", "c") and \
|
|
|
|
0 <= self._selection < len(self.payload.environments):
|
2014-04-07 12:38:09 +00:00
|
|
|
self.apply()
|
|
|
|
self.close()
|
|
|
|
return INPUT_PROCESSED
|
|
|
|
else:
|
|
|
|
return key
|
|
|
|
|
|
|
|
if 0 <= keyid < len(self.payload.environments):
|
|
|
|
self._selection = keyid
|
|
|
|
return INPUT_PROCESSED
|
|
|
|
|
|
|
|
@property
|
|
|
|
def ready(self):
|
|
|
|
""" If we're ready to move on. """
|
2015-03-23 11:36:12 +00:00
|
|
|
return (not threadMgr.get(THREAD_PAYLOAD) and
|
2015-05-30 11:20:59 +00:00
|
|
|
not threadMgr.get(THREAD_CHECK_SOFTWARE) and
|
|
|
|
not threadMgr.get(THREAD_SOFTWARE_WATCHER))
|
2014-04-07 12:38:09 +00:00
|
|
|
|
|
|
|
def apply(self):
|
|
|
|
""" Apply our selections """
|
|
|
|
self._apply()
|
|
|
|
|
|
|
|
# no longer using values from kickstart
|
|
|
|
self._kickstarted = False
|
|
|
|
self.data.packages.seen = True
|
|
|
|
|
|
|
|
def _apply(self):
|
|
|
|
""" Private apply. """
|
2015-05-30 11:20:59 +00:00
|
|
|
if 0 <= self._selection < len(self.payload.environments):
|
|
|
|
self.environment = self.payload.environments[self._selection]
|
2014-04-07 12:38:09 +00:00
|
|
|
else:
|
2015-05-30 11:20:59 +00:00
|
|
|
self.environment = None
|
2014-04-07 12:38:09 +00:00
|
|
|
return
|
|
|
|
|
2015-05-30 11:20:59 +00:00
|
|
|
changed = False
|
|
|
|
|
|
|
|
# Not a kickstart with packages, setup the selected environment
|
|
|
|
if not self._kickstarted:
|
|
|
|
if not self._origEnv:
|
|
|
|
# nothing selected before, select the environment
|
|
|
|
self.payload.selectEnvironment(self.environment)
|
|
|
|
changed = True
|
|
|
|
elif self._origEnv != self.environment:
|
|
|
|
# environment changed, clear the list of packages and select the new
|
|
|
|
# one
|
|
|
|
self.payload.data.packages.groupList = []
|
|
|
|
self.payload.selectEnvironment(self.environment)
|
|
|
|
changed = True
|
|
|
|
|
|
|
|
self._origEnv = self.environment
|
|
|
|
|
|
|
|
# Check the software selection
|
|
|
|
if changed:
|
|
|
|
threadMgr.add(AnacondaThread(name=THREAD_CHECK_SOFTWARE,
|
|
|
|
target=self.checkSoftwareSelection))
|
|
|
|
|
2014-04-07 12:38:09 +00:00
|
|
|
|
|
|
|
def checkSoftwareSelection(self):
|
|
|
|
""" Depsolving """
|
|
|
|
try:
|
|
|
|
self.payload.checkSoftwareSelection()
|
2015-05-30 11:20:59 +00:00
|
|
|
except DependencyError as e:
|
|
|
|
self.errors = [e.message]
|
2014-04-07 12:38:09 +00:00
|
|
|
self._tx_id = None
|
|
|
|
else:
|
|
|
|
self._tx_id = self.payload.txID
|
|
|
|
|
|
|
|
@property
|
|
|
|
def txid_valid(self):
|
|
|
|
""" Whether we have a valid yum tx id. """
|
|
|
|
return self._tx_id == self.payload.txID
|