Show warning if bootloader installation fails
by Samantha N. Bueno
The following couple of patches amend error handling when anaconda fails
to install the bootloader. Previously, such a failure caused the installer
to crash, but a warning pop-up now gets displayed to users in such an
event.
This resolves rhbz#730023.
11 years, 4 months
[PATCH f18-branch] Fix Quit button in standalone network spoke (#892120)
by Radek Vykydal
---
pyanaconda/ui/gui/spokes/network.glade | 1 -
pyanaconda/ui/gui/spokes/network.py | 4 ----
2 files changed, 5 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/network.glade b/pyanaconda/ui/gui/spokes/network.glade
index f9221e8..891394a 100644
--- a/pyanaconda/ui/gui/spokes/network.glade
+++ b/pyanaconda/ui/gui/spokes/network.glade
@@ -35,7 +35,6 @@
<property name="can_focus">False</property>
<property name="startup_id">filler</property>
<property name="window_name" translatable="yes">NETWORK CONFIGURATION</property>
- <signal name="quit-clicked" handler="on_back_clicked" swapped="no"/>
<child internal-child="main_box">
<object class="GtkBox" id="AnacondaStandaloneWindow-main_box5">
<property name="can_focus">False</property>
diff --git a/pyanaconda/ui/gui/spokes/network.py b/pyanaconda/ui/gui/spokes/network.py
index 6cefb4a..1d0bce5 100644
--- a/pyanaconda/ui/gui/spokes/network.py
+++ b/pyanaconda/ui/gui/spokes/network.py
@@ -1147,10 +1147,6 @@ class NetworkStandaloneSpoke(StandaloneSpoke):
self.clear_info()
StandaloneSpoke._on_continue_clicked(self, cb)
- def on_back_clicked(self, window):
- self.window.hide()
- Gtk.main_quit()
-
# Use case: slow dhcp has connected when on spoke
def on_nm_state_changed(self, *args):
gtk_call_once(self._update_hostname)
--
1.7.11.7
11 years, 4 months
[PATCHES]
by Chris Lumens
Patch #2 should be for F18. All should go on master.
- Chris
11 years, 4 months
[master] [PATCH] Prefer country over language when returning default layout (#867110)
by Vratislav Podzimek
If there is no layout matching both language and country, prefer
country over language. E.g. the 'ch' (Swiss) layout is not listed for
the German language, but it is, of course, listed for the 'CH' as a
country.
Signed-off-by: Vratislav Podzimek <vpodzime(a)redhat.com>
---
pyanaconda/keyboard.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/pyanaconda/keyboard.py b/pyanaconda/keyboard.py
index e865f08..403d42e 100755
--- a/pyanaconda/keyboard.py
+++ b/pyanaconda/keyboard.py
@@ -476,7 +476,7 @@ class XklWrapper(object):
language_layouts = self.get_language_layouts(language)
country_layouts = self._country_keyboard_variants.get(country, None)
- if not language_layouts:
+ if not language_layouts and not country_layouts:
return None
matches_both = (layout for layout in language_layouts
@@ -485,7 +485,10 @@ class XklWrapper(object):
try:
return matches_both.next().name
except StopIteration:
- return language_layouts[0].name
+ if country_layouts:
+ return country_layouts[0].name
+ else:
+ return language_layouts[0].name
def get_current_layout_name(self):
"""
--
1.7.11.7
11 years, 4 months
[rhel6-branch] [PATCH] Limit the maximum swap size to 10 % of disk space
by Vratislav Podzimek
On e.g. virtual machines with smalls disks and high amount of
memory it doesn't make sense to create large swap space leaving
only a little for the system and user data.
Also change comment to a docstring and document parameters.
Related: rhbz#878907
Signed-off-by: Vratislav Podzimek <vpodzime(a)redhat.com>
---
iutil.py | 28 ++++++++++++++++++++++++----
kickstart.py | 20 +++++++++++++++++---
storage/__init__.py | 15 +++++++++++++++
3 files changed, 56 insertions(+), 7 deletions(-)
diff --git a/iutil.py b/iutil.py
index 3e3f903..3a9a583 100644
--- a/iutil.py
+++ b/iutil.py
@@ -40,6 +40,9 @@ import logging
log = logging.getLogger("anaconda")
program_log = logging.getLogger("program")
+# maximum ratio of swap size to disk size (10%)
+MAX_SWAP_DISK_RATIO = 0.1
+
#Python reimplementation of the shell tee process, so we can
#feed the pipe output into two places at the same time
class tee(threading.Thread):
@@ -450,10 +453,17 @@ def memInstalled():
return long(mem)
-## Suggest the size of the swap partition that will be created.
-# @param quiet Should size information be logged?
-# @return A tuple of the minimum and maximum swap size, in megabytes.
-def swapSuggestion(quiet=0, hibernation=False):
+def swapSuggestion(quiet=0, hibernation=False, disk_space=None):
+ """
+ Suggest the size of the swap partition that will be created.
+
+ @param quiet: Should size information be logged?
+ @param hibernation: Suggest size of the swap partition to support hibernation?
+ @param disk_space: Total disk space available
+ @return: A tuple of the minimum and maximum swap size, in megabytes.
+
+ """
+
mem = memInstalled()/1024
mem = ((mem/16)+1)*16
if not quiet:
@@ -479,6 +489,16 @@ def swapSuggestion(quiet=0, hibernation=False):
else:
log.info("Ignoring --hibernation option on systems with 64 GB of RAM or more")
+ if disk_space is not None:
+ max_swap = int(disk_space * MAX_SWAP_DISK_RATIO)
+ if swap > max_swap:
+ log.info("Suggested swap size (%(swap)d M) exceeds %(percent)d %% of "
+ "disk space, using %(percent)d %% of disk space (%(size)d M) "
+ "instead." % {"percent": MAX_SWAP_DISK_RATIO*100,
+ "swap": swap,
+ "size": max_swap})
+ swap = max_swap
+
if not quiet:
log.info("Swap attempt of %sM", swap)
diff --git a/kickstart.py b/kickstart.py
index e4b960a..4a4ce43 100644
--- a/kickstart.py
+++ b/kickstart.py
@@ -481,11 +481,18 @@ class LogVolData(commands.logvol.RHEL6_LogVolData):
# we might have truncated or otherwise changed the specified vg name
vgname = anaconda.id.ksdata.onPart.get(self.vgname, self.vgname)
+ disk_space = 0
+ for disk in storage.disks:
+ if not storage.clearPartDisks \
+ or disk.name in storage.clearPartDisks:
+ disk_space += disk.size
+
if self.mountpoint == "swap":
type = "swap"
self.mountpoint = ""
if self.recommended or self.hibernation:
- (self.size, self.maxSizeMB) = iutil.swapSuggestion(hibernation=self.hibernation)
+ (self.size, self.maxSizeMB) = \
+ iutil.swapSuggestion(hibernation=self.hibernation, disk_space=disk_space)
self.grow = True
else:
if self.fstype != "":
@@ -498,7 +505,7 @@ class LogVolData(commands.logvol.RHEL6_LogVolData):
raise KickstartValueError, formatErrorMsg(self.lineno, msg="The mount point \"%s\" is not valid." % (self.mountpoint,))
# Check that the VG this LV is a member of has already been specified.
- vg = devicetree.getDeviceByName(vgname)
+ vg = devicetree.getDeviceByName(self.vgname)
if not vg:
raise KickstartValueError, formatErrorMsg(self.lineno, msg="No volume group exists with the name \"%s\". Specify volume groups before logical volumes." % self.vgname)
@@ -752,11 +759,18 @@ class PartitionData(commands.partition.RHEL6_PartData):
if self.disk == "":
raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specified BIOS disk %s cannot be determined" % self.onbiosdisk)
+ disk_space = 0
+ for disk in storage.disks:
+ if not storage.clearPartDisks \
+ or disk.name in storage.clearPartDisks:
+ disk_space += disk.size
+
if self.mountpoint == "swap":
type = "swap"
self.mountpoint = ""
if self.recommended or self.hibernation:
- (self.size, self.maxSizeMB) = iutil.swapSuggestion(hibernation=self.hibernation)
+ (self.size, self.maxSizeMB) = \
+ iutil.swapSuggestion(hibernation=self.hibernation, disk_space=disk_space)
self.grow = True
# if people want to specify no mountpoint for some reason, let them
diff --git a/storage/__init__.py b/storage/__init__.py
index 1e32d9d..f9efb83 100644
--- a/storage/__init__.py
+++ b/storage/__init__.py
@@ -121,6 +121,21 @@ def storageInitialize(anaconda, examine_all=True):
else:
return storageInitialize(anaconda)
sys.exit(1)
+ else:
+ # otherwise get new swap suggestion now that we know the total
+ # disk space
+ disk_space = 0
+ for disk in storage.disks:
+ if not storage.clearPartDisks \
+ or disk.name in storage.clearPartDisks:
+ disk_space += disk.size
+
+ (min_size, max_size) = iutil.swapSuggestion(disk_space=disk_space)
+ for request in storage.autoPartitionRequests:
+ if request.fstype == "swap":
+ request.size = min_size
+ request.maxSize= max_size
+
# dispatch.py helper function
def storageComplete(anaconda):
--
1.7.11.7
11 years, 4 months
[PATCH] Time for yuminstall to retire
by Brian C. Lane
From: "Brian C. Lane" <bcl(a)redhat.com>
---
po/POTFILES.in | 1 -
pyanaconda/yuminstall.py | 1973 ---------------------------------
tests/pyanaconda_test/backend_test.py | 3 +-
3 files changed, 1 insertion(+), 1976 deletions(-)
delete mode 100644 pyanaconda/yuminstall.py
diff --git a/po/POTFILES.in b/po/POTFILES.in
index b202521..553dd2c 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -18,7 +18,6 @@ pyanaconda/platform.py
pyanaconda/product.py
pyanaconda/rescue.py
pyanaconda/vnc.py
-pyanaconda/yuminstall.py
# Install class definitions
pyanaconda/installclasses/fedora.py
diff --git a/pyanaconda/yuminstall.py b/pyanaconda/yuminstall.py
deleted file mode 100644
index aef7e8f..0000000
--- a/pyanaconda/yuminstall.py
+++ /dev/null
@@ -1,1973 +0,0 @@
-#
-# yuminstall.py
-#
-# Copyright (C) 2005, 2006, 2007 Red Hat, Inc. All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-
-import ConfigParser
-import sys
-import os
-import os.path
-import shutil
-import time
-import types
-import locale
-import glob
-import tempfile
-import itertools
-import re
-
-class NoSuchGroup(Exception):
- pass
-
-from flags import flags
-
-import anaconda_log
-import rpm
-import rpmUtils
-import urlgrabber.progress
-import urlgrabber.grabber
-from urlgrabber.grabber import URLGrabber, URLGrabError
-import yum
-import iniparse
-from yum.constants import *
-from yum.Errors import *
-from yum.misc import to_unicode
-from yum.yumRepo import YumRepository
-from product import isFinal, productName, productVersion, productStamp
-from constants import *
-from image import *
-import packages
-from backend import AnacondaBackend
-
-import gettext
-_ = lambda x: gettext.ldgettext("anaconda", x)
-P_ = lambda x, y, z: gettext.ldngettext("anaconda", x, y, z)
-
-import network
-
-# specspo stuff
-rpm.addMacro("_i18ndomains", "redhat-dist")
-
-import logging
-log = logging.getLogger("anaconda")
-
-import urlparse
-urlparse.uses_fragment.append('media')
-
-urlgrabber.grabber.default_grabber.opts.user_agent = "%s (anaconda)/%s" %(productName, productVersion)
-
-import iutil
-import isys
-
-class NoSuchGroup(Exception):
- pass
-
-def size_string (size):
- def number_format(s):
- return locale.format("%s", s, 1)
-
- retval = None
-
- if size > 1024 * 1024:
- size = size / (1024*1024)
- retval = _("%s MB") %(number_format(size),)
- elif size > 1024:
- size = size / 1024
- retval = _("%s KB") %(number_format(size),)
- else:
- retval = P_("%s Byte", "%s Bytes", size) % (number_format(size),)
-
- return to_unicode(retval)
-
-class AnacondaCallback:
-
- def __init__(self, ayum, anaconda, instLog, modeText):
- self.anaconda = anaconda
- self.repos = ayum.repos
- self.ts = ayum.ts
- self.ayum = ayum
-
- self.messageWindow = anaconda.intf.messageWindow
- self.progress = anaconda.intf.instProgress
- self.progressWindowClass = anaconda.intf.progressWindow
- self.rootPath = ROOT_PATH
-
- self.initWindow = None
-
- self.progressWindow = None
- self.lastprogress = 0
- self.incr = 20
-
- self.instLog = instLog
- self.modeText = modeText
-
- self.openfile = None
- self.inProgressPo = None
-
- def setSizes(self, numpkgs, totalSize, totalFiles):
- self.numpkgs = numpkgs
- self.totalSize = totalSize
- self.totalFiles = totalFiles
-
- self.donepkgs = 0
- self.doneSize = 0
-
- def callback(self, what, amount, total, h, user):
- if what == rpm.RPMCALLBACK_TRANS_START:
- # step 6 is the bulk of the ts processing time
- if amount == 6:
- self.progressWindow = \
- self.progressWindowClass (_("Preparing to install"),
- _("Preparing transaction from installation source"),
- total)
- self.incr = total / 10
-
- if what == rpm.RPMCALLBACK_TRANS_PROGRESS:
- if self.progressWindow and amount > self.lastprogress + self.incr:
- self.progressWindow.set(amount)
- self.lastprogress = amount
-
- if what == rpm.RPMCALLBACK_TRANS_STOP and self.progressWindow:
- self.progressWindow.pop()
-
- if what == rpm.RPMCALLBACK_INST_OPEN_FILE:
- # Old-style (hdr, path) callback
- if isinstance(h, types.TupleType):
- (hdr, rpmloc) = h
- # hate hate hate at epochs...
- epoch = hdr['epoch']
- if epoch is not None:
- epoch = str(epoch)
- txmbrs = self.ayum.tsInfo.matchNaevr(hdr['name'], hdr['arch'],
- epoch, hdr['version'],
- hdr['release'])
- if len(txmbrs) == 0:
- raise RuntimeError, "Unable to find package %s-%s-%s.%s" %(hdr['name'], hdr['version'], hdr['release'], hdr['arch'])
- po = txmbrs[0].po
- # New-style callback, h is our txmbr
- else:
- po = h.po
-
- repo = self.repos.getRepo(po.repoid)
-
- pkgStr = "%s-%s-%s.%s" % (po.name, po.version, po.release, po.arch)
-
- if self.anaconda.upgrade:
- s = to_unicode(_("<b>Upgrading %(pkgStr)s</b> (%(size)s)\n")) \
- % {'pkgStr': pkgStr, 'size': size_string(po.installedsize)}
- else:
- s = to_unicode(_("<b>Installing %(pkgStr)s</b> (%(size)s)\n")) \
- % {'pkgStr': pkgStr, 'size': size_string(po.installedsize)}
-
- summary = to_unicode(gettext.ldgettext("redhat-dist", po.summary) or "")
- s += summary.strip()
- self.progress.set_label(s)
-
- self.instLog.write(self.modeText % (time.strftime("%H:%M:%S"), str(pkgStr)))
-
- self.instLog.flush()
- self.openfile = None
-
- while self.openfile is None:
- try:
- fn = repo.getPackage(po)
-
- f = open(fn, 'r')
- self.openfile = f
- except (yum.Errors.NoMoreMirrorsRepoError, IOError):
- self.ayum._handleFailure(po)
- except yum.Errors.RepoError:
- continue
- self.inProgressPo = po
-
- return self.openfile.fileno()
-
- elif what == rpm.RPMCALLBACK_INST_CLOSE_FILE:
- if self.initWindow:
- self.initWindow.pop()
- self.initWindow = None
-
- fn = self.openfile.name
- self.openfile.close()
- self.openfile = None
-
- if os.path.dirname(fn).startswith("%s/var/cache/yum/" % self.rootPath):
- try:
- os.unlink(fn)
- except OSError as e:
- log.debug("unable to remove file %s" %(e.strerror,))
-
- self.donepkgs += 1
- self.doneSize += self.inProgressPo.returnSimple("installedsize") / 1024.0
-
- if self.donepkgs <= self.numpkgs:
- self.progress.set_text(P_("Packages completed: "
- "%(donepkgs)d of %(numpkgs)d",
- "Packages completed: "
- "%(donepkgs)d of %(numpkgs)d",
- self.numpkgs)
- % {'donepkgs': self.donepkgs,
- 'numpkgs': self.numpkgs})
- self.progress.set_fraction(float(self.doneSize / self.totalSize))
- self.progress.processEvents()
-
- self.inProgressPo = None
-
- elif what == rpm.RPMCALLBACK_UNINST_START:
- self.progress.set_text("")
- self.progress.set_label(_("<b>Cleaning up %s</b>" % h))
-
- elif what in (rpm.RPMCALLBACK_CPIO_ERROR,
- rpm.RPMCALLBACK_UNPACK_ERROR,
- rpm.RPMCALLBACK_SCRIPT_ERROR):
- # If this is a cleanup/remove, then h is just a string.
- # A tuple h means old-style (hdr, path) yum callback,
- # otherwise it's a new-style txmbr callback.
- if isinstance(h, basestring):
- name = h
- elif isinstance(h, types.TupleType):
- name = h[0]['name']
- else:
- name = h.name
-
- # Script errors store whether or not they're fatal in "total". So,
- # we should only error out for fatal script errors or the cpio and
- # unpack problems.
- if what != rpm.RPMCALLBACK_SCRIPT_ERROR or total:
- if what == rpm.RPMCALLBACK_CPIO_ERROR:
- error_type = _("cpio")
- elif what == rpm.RPMCALLBACK_UNPACK_ERROR:
- error_type = _("unpack")
- else:
- error_type = _("script")
- self.messageWindow(_("Error Installing Package"),
- _("A %s error occurred when installing the %s "
- "package. This could indicate errors when reading "
- "the installation media. Installation cannot "
- "continue.") % (error_type, name),
- type="custom", custom_icon="error",
- custom_buttons=[_("_Exit installer")])
- sys.exit(1)
-
- if self.initWindow is None:
- self.progress.processEvents()
-
-class AnacondaYumRepo(YumRepository):
- def __init__(self, *args, **kwargs):
- YumRepository.__init__(self, *args, **kwargs)
- self.enablegroups = True
- self.sslverify = True
- self._anacondaBaseURLs = []
- self.proxy_url = None
-
- def needsNetwork(self):
- def _isURL(s):
- return s.startswith("http") or s.startswith("ftp")
-
- if len(self.baseurl) > 0:
- return len(filter(lambda s: _isURL(s), self.baseurl)) > 0
- elif self.mirrorlist:
- return _isURL(self.mirrorlist)
- else:
- return False
-
- def dirCleanup(self):
- cachedir = self.getAttribute('cachedir')
-
- if os.path.isdir(cachedir):
- if not self.needsNetwork() or self.name == "Installation Repo" or self.id.startswith("anaconda-"):
- shutil.rmtree(cachedir)
- else:
- if os.path.exists("%s/headers" % cachedir):
- shutil.rmtree("%s/headers" % cachedir)
- if os.path.exists("%s/packages" % cachedir):
- shutil.rmtree("%s/packages" % cachedir)
-
- # needed to store nfs: repo url that yum doesn't know
- def _getAnacondaBaseURLs(self):
- return self._anacondaBaseURLs or self.baseurl or [self.mirrorlist]
-
- def _setAnacondaBaseURLs(self, value):
- self._anacondaBaseURLs = value
-
- anacondaBaseURLs = property(_getAnacondaBaseURLs, _setAnacondaBaseURLs,
- doc="Extends AnacondaYum.baseurl to store non-yum urls:")
-
-class AnacondaYum(yum.YumBase):
- def __init__(self, anaconda):
- yum.YumBase.__init__(self)
- self.anaconda = anaconda
- self._timestamp = None
-
- self.repoIDcounter = itertools.count()
-
- # Only needed for hard drive and nfsiso installs.
- self.isodir = None
-
- # Only needed for media installs.
- self.mediagrabber = None
-
- # Where is the source media mounted? This is the directory
- # where Packages/ is located.
- self.tree = "/mnt/install/source"
-
- if hasattr(self, "use_txmbr_in_callback"):
- log.debug("enabling new callback mode")
- self.use_txmbr_in_callback = True
-
- self.macros = {}
-
- if flags.selinux:
- for directory in ("/tmp/updates",
- "/etc/selinux/targeted/contexts/files",
- "/etc/security/selinux/src/policy/file_contexts",
- "/etc/security/selinux"):
- fn = "%s/file_contexts" %(directory,)
- if os.access(fn, os.R_OK):
- break
- self.macros["__file_context_path"] = fn
- else:
- self.macros["__file_context_path"] = "%{nil}"
-
- self.updates = []
- self.localPackages = []
-
- # Parse proxy values from anaconda
- self.proxy = None
- self.proxy_url = None
- self.proxy_username = None
- self.proxy_password = None
- if self.anaconda.proxy:
- self.setProxy(self.anaconda, self)
-
- def setup(self):
- # yum doesn't understand all our method URLs, so use this for all
- # except FTP and HTTP installs.
- self._baseRepoURL = "file://%s" % self.tree
-
- while True:
- try:
- self.configBaseURL()
- break
- except SystemError as exception:
- self.anaconda.methodstr = self.anaconda.intf.methodstrRepoWindow(self.anaconda.methodstr or "cdrom:",
- exception)
-
- self.doConfigSetup(root=ROOT_PATH)
- if not self.anaconda.bootloader.update_only:
- self.conf.installonlypkgs = []
-
- def _mountInstallCD(self):
- if os.access("%s/.discinfo" % self.tree, os.R_OK):
- f = open("%s/.discinfo" % self.tree)
- self._timestamp = f.readline().strip()
- f.close()
-
- dev = self.anaconda.storage.devicetree.getDeviceByName(self.anaconda.mediaDevice)
- dev.format.mountpoint = self.tree
-
- # See if there's any media mounted on self.tree before continuing.
- # This saves a useless eject and insert if the user has already put
- # the disc in the drive.
- if not self.anaconda.storage.fsset.mountpoints.has_key(self.tree):
- try:
- dev.format.mount()
-
- if verifyMedia(self.tree, None):
- return
-
- dev.format.unmount()
- except Exception:
- pass
- else:
- if verifyMedia(self.tree, None):
- return
-
- dev.format.unmount()
-
- log.error("Wrong disc found on %s" % (self.tree))
- if self.anaconda.intf:
- self.anaconda.intf.beep()
-
- self.messageWindow(_("Wrong Disc"),
- _("That's not the correct %s disc.") % (productName),
- type="custom", custom_icon="error",
- custom_buttons=[_("_Exit installer")])
- sys.exit(1)
-
- def _mountInstallImage(self):
- umountImage(self.tree)
-
- # mountDirectory checks before doing anything, so it's safe to
- # call this repeatedly.
- mountDirectory(self.anaconda.methodstr, self.anaconda.intf.messageWindow)
- mountImage(self.isodir, self.tree, self.anaconda.intf.messageWindow)
-
- def configBaseURL(self):
- # We only have a methodstr if method= or repo= was passed to
- # anaconda. No source for this base repo (the CD media, NFS,
- # whatever) is mounted yet since initramfs only mounts the source
- # for the stage2 image. We need to set up the source mount
- # now.
- # methodstr == cdrom is a special case, meaning the first cdrom found
- # by scanning or previously mounted as the install source.
- if flags.cmdline.has_key("preupgrade"):
- path = "/var/cache/yum/preupgrade"
- self.anaconda.methodstr = "hd::%s" % path
- self._baseRepoURL = "file:///mnt/sysimage/%s" % path
- elif self.anaconda.methodstr and self.anaconda.methodstr != "cdrom":
- m = self.anaconda.methodstr
-
- if m.startswith("hd:"):
- if m.count(":") == 2:
- (device, path) = m[3:].split(":")
- else:
- (device, fstype, path) = m[3:].split(":")
-
- self.isodir = "/mnt/install/isodir/%s" % path
-
- # This takes care of mounting /mnt/install/isodir first.
- self._mountInstallImage()
- self.mediagrabber = self.mediaHandler
- elif m.startswith("nfsiso:"):
- self.isodir = "/mnt/install/isodir"
-
- # Calling _mountInstallImage takes care of mounting /mnt/install/isodir first.
- if not network.hasActiveNetDev():
- if not self.anaconda.intf.enableNetwork():
- self._baseRepoURL = None
- return
-
- self._mountInstallImage()
- self.mediagrabber = self.mediaHandler
- elif m.startswith("http") or m.startswith("ftp:"):
- self._baseRepoURL = m
- elif m.startswith("nfs:"):
- if not network.hasActiveNetDev():
- if not self.anaconda.intf.enableNetwork():
- self._baseRepoURL = None
-
- (opts, server, path) = iutil.parseNfsUrl(m)
- isys.mount(server+":"+path, self.tree, "nfs", options=opts)
-
- # This really should be fixed in initrd instead but for now see
- # if there's images and if so go with this being an NFSISO
- # install instead.
- image = findFirstIsoImage(self.tree, self.anaconda.intf.messageWindow)
- if image:
- isys.umount(self.tree, removeDir=False)
- self.anaconda.methodstr = "nfsiso:%s" % m[4:]
- self.configBaseURL()
- return
- elif m.startswith("cdrom:"):
- self._mountInstallCD()
- self.mediagrabber = self.mediaHandler
- self._baseRepoURL = "file://%s" % self.tree
- elif os.path.isdir("/run/initramfs/live/repodata"):
- # No methodstr was given. In order to find an installation source
- # we first check to see if dracut has already mounted the source
- # on /run/initramfs/live/ and if not we check to see if there's a
- # CD/DVD with packages on it. If both those fail we default to the
- # mirrorlist URL. The user can always change the repo with the
- # repo editor later.
- isys.mount("/run/initramfs/live/", self.tree, bindMount=True)
- self.mediagrabber = self.mediaHandler
- self._baseRepoURL = "file://%s" % self.tree
- elif os.path.isdir("/run/install/repo/repodata"):
- # Same hack as above. FIXME: make scanForMedia do this, dammit
- isys.mount("/run/install/repo", self.tree, bindMount=True)
- self.mediagrabber = self.mediaHandler
- self._baseRepoURL = "file://%s" % self.tree
- else:
- # No methodstr was given. In order to find an installation source,
- # we should first check to see if there's a CD/DVD with packages
- # on it, and then default to the mirrorlist URL. The user can
- # always change the repo with the repo editor later.
- cdrs = opticalInstallMedia(self.anaconda.storage.devicetree, self.tree)
- if cdrs:
- self.mediagrabber = self.mediaHandler
- self.anaconda.mediaDevice = cdrs[0].name
- log.info("found installation media on %s" % cdrs[0].name)
- else:
- # No CD with media on it and no repo=/method= parameter, so
- # default to using whatever's enabled in /etc/yum.repos.d/
- self._baseRepoURL = None
-
- def configBaseRepo(self):
- # Create the "base" repo object, assuming there is one. Otherwise we
- # just skip all this and use the defaults from /etc/yum.repos.d.
- if not self._baseRepoURL:
- return
-
- # add default repos
- anacondabaseurl = (self.anaconda.methodstr or
- "cdrom:%s" % (self.anaconda.mediaDevice))
- anacondabasepaths = self.anaconda.instClass.getPackagePaths(anacondabaseurl)
- for (name, uri) in self.anaconda.instClass.getPackagePaths(self._baseRepoURL).items():
- repo = AnacondaYumRepo("anaconda-%s" % self.repoIDcounter.next())
- repo.baseurl = uri
- repo.anacondaBaseURLs = anacondabasepaths[name]
-
- repo.name = name
- repo.cost = 100
-
- if self.anaconda.mediaDevice or self.isodir:
- repo.mediaid = getMediaId(self.tree)
- log.info("set mediaid of repo %s to: %s" % (repo.name, repo.mediaid))
-
- if self.anaconda.proxy:
- self.setProxy(self.anaconda, repo)
-
- if flags.noverifyssl:
- repo.sslverify = False
-
- repo.enable()
- self.repos.add(repo)
-
- def mediaHandler(self, *args, **kwargs):
- relative = kwargs["relative"]
-
- ug = URLGrabber(checkfunc=kwargs["checkfunc"])
- ug.urlgrab("%s/%s" % (self.tree, kwargs["relative"]), kwargs["local"],
- text=kwargs["text"], range=kwargs["range"], copy_local=1)
- return kwargs["local"]
-
- # XXX: This is straight out of yum, but we need to override it here in
- # order to use our own repo class.
- def readRepoConfig(self, parser, section):
- '''Parse an INI file section for a repository.
-
- @param parser: ConfParser or similar to read INI file values from.
- @param section: INI file section to read.
- @return: YumRepository instance.
- '''
- repo = AnacondaYumRepo(section)
- repo.populate(parser, section, self.conf)
-
- # Ensure that the repo name is set
- if not repo.name:
- repo.name = section
- self.logger.error(_('Repository %r is missing name in configuration, '
- 'using id') % section)
-
- # Set attributes not from the config file
- repo.yumvar.update(self.conf.yumvar)
- repo.cfg = parser
-
- if "-source" in repo.id or "-debuginfo" in repo.id:
- name = repo.name
- del(repo)
- raise RepoError, "Repo %s contains -source or -debuginfo, excluding" % name
-
- # this is a little hard-coded, but it's effective
- if isFinal and ("rawhide" in repo.id or "development" in repo.id):
- name = repo.name
- del(repo)
- raise RepoError, "Excluding devel repo %s for non-devel anaconda" % name
-
- if not isFinal and not repo.enabled:
- name = repo.name
- del(repo)
- raise RepoError, "Excluding disabled repo %s for prerelease" % name
-
- # If repo=/method= was passed in, we want to default these extra
- # repos to off.
- if self._baseRepoURL:
- repo.enabled = False
-
- return repo
-
- def setProxy(self, src, dest):
- """
- Set the proxy settings from a string in src.proxy
- If the string includes un/pw use those, otherwise set the un/pw from
- src.proxyUsername and src.proxyPassword
-
- dest has dest.proxy set to the host and port (no un/pw)
- dest.proxy_username and dest.proxy_password are set if present in src
- """
- # NOTE: If this changes, update tests/regex/proxy.py
- #
- # proxy=[protocol://][username[:password]@]host[:port][path]
- pattern = re.compile("([A-Za-z]+://)?(([A-Za-z0-9]+)(:[^:@]+)?@)?([^:/]+)(:[0-9]+)?(/.*)?")
-
- m = pattern.match(src.proxy)
-
- if m and m.group(3):
- dest.proxy_username = m.group(3)
- elif getattr(src, "proxyUsername", None):
- dest.proxy_username = src.proxyUsername
-
- if m and m.group(4):
- # Skip the leading colon.
- dest.proxy_password = m.group(4)[1:]
- elif getattr(src, "proxyPassword", None):
- dest.proxy_password = src.proxyPassword
-
- if dest.proxy_username or dest.proxy_password:
- proxy_auth = "%s:%s@" % (dest.proxy_username or '',
- dest.proxy_password or '')
- else:
- proxy_auth = ""
-
- if m and m.group(5):
- # If both a host and port was found, just paste them
- # together using the colon at the beginning of the port
- # match as a separator. Otherwise, just use the host.
- if m.group(6):
- proxy = m.group(5) + m.group(6)
- else:
- proxy = m.group(5)
-
- # yum also requires a protocol. If none was given,
- # default to http.
- if m.group(1):
- dest.proxy_url = m.group(1) + proxy_auth + proxy
- proxy = m.group(1) + proxy
- else:
- dest.proxy_url = "http://" + proxy_auth + proxy
- proxy = "http://" + proxy
-
- # Set the repo proxy. NOTE: yum immediately parses this and
- # raises an error if it isn't correct
- dest.proxy = proxy
-
- def _getAddons(self, baseurl, proxy_url, sslverify):
- """
- Check the baseurl or mirrorlist for a repository, see if it has any
- valid addon repos and if so, return a list of (repo name, repo URL).
- """
- retval = []
- c = ConfigParser.ConfigParser()
-
- # If there's no .treeinfo for this repo, don't bother looking for addons.
- treeinfo = self._getTreeinfo(baseurl, proxy_url, sslverify)
- if not treeinfo:
- return retval
-
- # We need to know which variant is being installed so we know what addons
- # are valid options.
- try:
- ConfigParser.ConfigParser.read(c, treeinfo)
- variant = c.get("general", "variant")
- except ConfigParser.Error:
- return retval
-
- section = "variant-%s" % variant
- if c.has_section(section) and c.has_option(section, "addons"):
- validAddons = c.get(section, "addons").split(",")
- else:
- return retval
-
- for addon in validAddons:
- addonSection = "addon-%s" % addon
- if not c.has_section(addonSection) or not c.has_option(addonSection, "repository"):
- continue
-
- url = "%s/%s" % (baseurl, c.get(addonSection, "repository"))
- retval.append((addon, c.get(addonSection, "name"), url))
-
- return retval
-
- def _getTreeinfo(self, baseurl, proxy_url, sslverify):
- """
- Try to get .treeinfo file from baseurl, optionally using proxy_url
- Saves the file into /tmp/.treeinfo
- """
- if not baseurl:
- return None
- if baseurl.startswith("http") or baseurl.startswith("ftp"):
- if not network.hasActiveNetDev():
- if not self.anaconda.intf.enableNetwork():
- log.error("Error downloading %s/.treeinfo: network enablement failed" % (baseurl))
- return None
- ug = URLGrabber()
- ugopts = {
- "ssl_verify_peer" : sslverify,
- "ssl_verify_host" : sslverify
- }
-
- if proxy_url:
- proxies = { 'http' : proxy_url,
- 'https' : proxy_url }
- else:
- proxies = {}
-
- try:
- ug.urlgrab("%s/.treeinfo" % baseurl, "/tmp/.treeinfo",
- copy_local=1, proxies=proxies, **ugopts)
- except Exception as e:
- try:
- ug.urlgrab("%s/treeinfo" % baseurl, "/tmp/.treeinfo",
- copy_local=1, proxies=proxies)
- except Exception as e:
- log.info("Error downloading treeinfo: %s" % e)
- return None
-
- return "/tmp/.treeinfo"
-
- def _getReleasever(self):
- """
- We need to make sure $releasever gets set up before .repo files are
- read. Since there's no redhat-release package in /mnt/sysimage (and
- won't be for quite a while), we need to do our own substutition.
- """
- c = ConfigParser.ConfigParser()
-
- treeinfo = self._getTreeinfo(self._baseRepoURL,
- self.proxy_url,
- not flags.noverifyssl)
- if not treeinfo:
- return productVersion.split('-')[0]
-
- ConfigParser.ConfigParser.read(c, treeinfo)
- try:
- ver = c.get("general", "version")
- # Trim off any -Alpha or -Beta
- return ver.split('-')[0]
- except ConfigParser.Error:
- return productVersion
-
- # Override this method so yum doesn't nuke our existing logging config.
- def doLoggingSetup(self, *args, **kwargs):
-
- import yum.logginglevels
-
- file_handler = logging.FileHandler("/tmp/yum.log")
- file_formatter = logging.Formatter("[%(asctime)s] %(levelname)-8s: %(message)s")
- file_handler.setFormatter(file_formatter)
-
- tty3_handler = logging.FileHandler("/dev/tty3")
- tty3_formatter = logging.Formatter(anaconda_log.TTY_FORMAT,
- anaconda_log.DATE_FORMAT)
- tty3_handler.setFormatter(tty3_formatter)
-
- verbose = logging.getLogger("yum.verbose")
- verbose.setLevel(logging.DEBUG)
- verbose.propagate = False
- verbose.addHandler(file_handler)
-
- logger = logging.getLogger("yum")
- logger.propagate = False
- logger.setLevel(yum.logginglevels.INFO_2)
- logger.addHandler(file_handler)
- anaconda_log.autoSetLevel(tty3_handler, True)
- tty3_handler.setLevel(anaconda_log.logger.tty_loglevel)
- logger.addHandler(tty3_handler)
-
- # XXX filelogger is set in setFileLog - do we or user want it?
- filelogger = logging.getLogger("yum.filelogging")
- filelogger.setLevel(logging.INFO)
- filelogger.propagate = False
-
- def doFileLogSetup(self, uid, logfile):
- # don't do the file log as it can lead to open fds
- # being left and an inability to clean up after ourself
- pass
-
- def doConfigSetup(self, fn='/tmp/anaconda-yum.conf', root='/'):
- if hasattr(self, "preconf"):
- self.preconf.fn = fn
- self.preconf.root = root
- self.preconf.releasever = self._getReleasever()
- self.preconf.enabled_plugins = ["whiteout", "blacklist"]
- yum.YumBase._getConfig(self)
- else:
- yum.YumBase._getConfig(self, fn=fn, root=root,
- enabled_plugins=["whiteout", "blacklist"])
- self.configBaseRepo()
-
- extraRepos = []
-
- ddArch = os.uname()[4]
-
- #Add the Driver disc repos to Yum
- for d in glob.glob(DD_RPMS):
- dirname = os.path.basename(d)
-
- repo = AnacondaYumRepo("anaconda-%s" % self.repoIDcounter.next())
- repo.baseurl = [ "file://%s" % d ]
- repo.name = "Driver Disk %s" % dirname.split("-")[1]
- repo.enable()
- extraRepos.append(repo)
-
- if self.anaconda.ksdata:
- for ksrepo in self.anaconda.ksdata.repo.repoList:
- # If no location was given, this must be a repo pre-configured
- # through /etc/yum.repos.d that we just want to enable.
- if not ksrepo.baseurl and not ksrepo.mirrorlist:
- try:
- repo = self.repos.getRepo(ksrepo.name)
- repo.enable()
- log.info("enabled repository %s with URL %s" % (repo.name, repo.mirrorlist or repo.baseurl[0]))
- except RepoError:
- log.error("Could not find the pre-configured repo %s, skipping" % ksrepo.name)
-
- continue
-
- anacondaBaseURLs = [ksrepo.baseurl]
-
- # yum doesn't understand nfs:// and doesn't want to. We need
- # to first do the mount, then translate it into a file:// that
- # yum does understand.
- # "nfs:" and "nfs://" prefixes are accepted in ks repo --baseurl
- if ksrepo.baseurl and ksrepo.baseurl.startswith("nfs:"):
- if not network.hasActiveNetDev() and not self.anaconda.intf.enableNetwork():
- self.anaconda.intf.messageWindow(_("No Network Available"),
- _("Some of your software repositories require "
- "networking, but there was an error enabling the "
- "network on your system."),
- type="custom", custom_icon="error",
- custom_buttons=[_("_Exit installer")])
- sys.exit(1)
-
- dest = tempfile.mkdtemp("", ksrepo.name.replace(" ", ""), "/mnt")
-
- # handle "nfs://" prefix
- if ksrepo.baseurl[4:6] == '//':
- ksrepo.baseurl = ksrepo.baseurl.replace('//', '', 1)
- anacondaBaseURLs = [ksrepo.baseurl]
- try:
- isys.mount(ksrepo.baseurl[4:], dest, "nfs")
- except Exception as e:
- log.error("error mounting NFS repo: %s" % e)
-
- ksrepo.baseurl = "file://%s" % dest
-
- repo = AnacondaYumRepo(ksrepo.name)
- repo.yumvar.update(self.conf.yumvar)
- repo.mirrorlist = ksrepo.mirrorlist
- repo.name = ksrepo.name
-
- if not ksrepo.baseurl:
- repo.baseurl = []
- else:
- repo.baseurl = [ ksrepo.baseurl ]
- repo.anacondaBaseURLs = anacondaBaseURLs
-
- if ksrepo.cost:
- repo.cost = ksrepo.cost
-
- if ksrepo.excludepkgs:
- repo.exclude = ksrepo.excludepkgs
-
- if ksrepo.includepkgs:
- repo.includepkgs = ksrepo.includepkgs
-
- if ksrepo.noverifyssl:
- repo.sslverify = False
-
- if ksrepo.proxy:
- self.setProxy(ksrepo, repo)
-
- repo.enable()
- extraRepos.append(repo)
-
- initialRepos = self.repos.repos.values() + extraRepos
- for repo in filter(lambda r: r.isEnabled(), initialRepos):
- addons = self._getAddons(repo.mirrorlist or repo.baseurl[0],
- repo.proxy_url or self.proxy_url,
- repo.sslverify)
- for addon in addons:
- addonRepo = AnacondaYumRepo(addon[0])
- addonRepo.name = addon[1]
- addonRepo.baseurl = [ addon[2] ]
-
- addonRepo.enable()
-
- if self.anaconda.proxy:
- self.setProxy(self.anaconda, addonRepo)
-
- extraRepos.append(addonRepo)
-
- for repo in extraRepos:
- try:
- self.repos.add(repo)
- log.info("added repository %s with URL %s" % (repo.name, repo.mirrorlist or repo.baseurl[0]))
- except yum.Errors.DuplicateRepoError:
- log.warning("ignoring duplicate repository %s with URL %s" % (repo.name, repo.mirrorlist or repo.baseurl[0]))
-
- self.repos.setCacheDir(self.conf.cachedir)
-
- def downloadHeader(self, po):
- while True:
- # retrying version of download header
- try:
- yum.YumBase.downloadHeader(self, po)
- break
- except (yum.Errors.NoMoreMirrorsRepoError, IOError):
- self._handleFailure(po)
- except yum.Errors.RepoError:
- continue
-
- def _handleFailure(self, package):
- if package.repo.anacondaBaseURLs[0].startswith("cdrom:"):
- buttons = [_("Re_boot"), _("_Eject")]
- else:
- buttons = [_("Re_boot"), _("_Retry")]
-
- pkgFile = to_unicode(os.path.basename(package.remote_path))
- rc = self.anaconda.intf.messageWindow(_("Error"),
- _("The file %s cannot be opened. This is due to a missing "
- "file, a corrupt package or corrupt media. Please "
- "verify your installation source.\n\n"
- "If you exit, your system will be left in an inconsistent "
- "state that will likely require reinstallation.\n\n") %
- (pkgFile,),
- type="custom", custom_icon="error",
- custom_buttons=buttons)
-
- if rc == 0:
- sys.exit(0)
- else:
- if os.path.exists(package.localPkg()):
- os.unlink(package.localPkg())
-
- if package.repo.anacondaBaseURLs[0].startswith("cdrom:"):
- self._mountInstallCD()
- else:
- return
-
- def mirrorFailureCB (self, obj, *args, **kwargs):
- # This gets called when a mirror fails, but it cannot know whether
- # or not there are other mirrors left to try, since it cannot know
- # which mirror we were on when we started this particular download.
- # Whenever we have run out of mirrors the grabber's get/open/retrieve
- # method will raise a URLGrabError exception with errno 256.
- repo = self.repos.getRepo(kwargs["repo"])
- log.warning("Failed to get %s from mirror %d/%d, "
- "or downloaded file is corrupt" % (obj.url, repo.grab._next + 1,
- len(repo.grab.mirrors)))
-
- if repo.anacondaBaseURLs[0].startswith("cdrom:"):
- dev = self.anaconda.storage.devicetree.getDeviceByName(self.anaconda.mediaDevice)
- dev.format.mountpoint = self.tree
- unmountCD(dev, self.anaconda.intf.messageWindow)
-
- def urlgrabberFailureCB (self, obj, *args, **kwargs):
- if hasattr(obj, "exception"):
- log.warning("Try %s/%s for %s failed: %s" % (obj.tries, obj.retry, obj.url, obj.exception))
- else:
- log.warning("Try %s/%s for %s failed" % (obj.tries, obj.retry, obj.url))
-
- if obj.tries == obj.retry:
- return
-
- delay = 0.25*(2**(obj.tries-1))
- if delay > 1:
- w = self.anaconda.intf.waitWindow(_("Retrying"), _("Retrying download."))
- time.sleep(delay)
- w.pop()
- else:
- time.sleep(delay)
-
- def getDownloadPkgs(self):
- downloadpkgs = []
- totalSize = 0
- totalFiles = 0
- for txmbr in self.tsInfo.getMembersWithState(output_states=TS_INSTALL_STATES):
- if txmbr.po:
- totalSize += int(txmbr.po.returnSimple("installedsize")) / 1024
- for filetype in txmbr.po.returnFileTypes():
- totalFiles += len(txmbr.po.returnFileEntries(ftype=filetype))
- downloadpkgs.append(txmbr.po)
-
- return (downloadpkgs, totalSize, totalFiles)
-
- def setColor(self):
- if rpmUtils.arch.isMultiLibArch():
- self.ts.ts.setColor(3)
-
- def run(self, instLog, cb, intf):
- self.initActionTs()
- if self.anaconda.upgrade:
- self.ts.ts.setProbFilter(~rpm.RPMPROB_FILTER_DISKSPACE)
- self.setColor()
-
- try:
- self.dsCallback = DownloadHeaderProgress(intf, self)
- self.populateTs(keepold=0)
- self.dsCallback.pop()
- self.dsCallback = None
- except RepoError as e:
- msg = _("There was an error running your transaction for "
- "the following reason: %s\n") % str(e)
-
- if self.anaconda.upgrade or self.anaconda.ksdata:
- rc = intf.messageWindow(_("Error"), msg, type="custom",
- custom_icon="error",
- custom_buttons=[_("_Exit installer")])
- sys.exit(1)
- else:
- rc = intf.messageWindow(_("Error"), msg,
- type="custom", custom_icon="error",
- custom_buttons=[_("_Back"), _("_Exit installer")])
-
- if rc == 1:
- sys.exit(1)
- else:
- return DISPATCH_BACK
-
- self.ts.check()
- self.ts.order()
- self.ts.clean()
-
- self.anaconda.bootloader.trusted_boot = self.isPackageInstalled(name="tboot")
-
- if self._run(instLog, cb, intf) == DISPATCH_BACK:
- return DISPATCH_BACK
-
- self.ts.close()
-
- def _run(self, instLog, cb, intf):
- # set log fd. FIXME: this is ugly. see changelog entry from 2005-09-13
- self.ts.ts.scriptFd = instLog.fileno()
- rpm.setLogFile(instLog)
-
- uniqueProbs = {}
- spaceneeded = {}
- spaceprob = ""
- fileConflicts = []
- fileprob = ""
-
- try:
- self.runTransaction(cb=cb)
- except PackageSackError as e:
- log.error("AnacondaYum._run: PackageSackError: %s" % e)
- msg = _("There was an error running your transaction for "
- "the following reason: %s.\n") % str(e)
- intf.messageWindow(_("Error Running Transaction"),
- msg, type="custom",
- custom_icon="error", custom_buttons=[_("_Exit installer")])
- sys.exit(1)
- except YumBaseError as probs:
- # FIXME: we need to actually look at these problems...
- probTypes = { rpm.RPMPROB_NEW_FILE_CONFLICT : _('file conflicts'),
- rpm.RPMPROB_FILE_CONFLICT : _('file conflicts'),
- rpm.RPMPROB_OLDPACKAGE: _('older package(s)'),
- rpm.RPMPROB_DISKSPACE: _('insufficient disk space'),
- rpm.RPMPROB_DISKNODES: _('insufficient disk inodes'),
- rpm.RPMPROB_CONFLICT: _('package conflicts'),
- rpm.RPMPROB_PKG_INSTALLED: _('package already installed'),
- rpm.RPMPROB_REQUIRES: _('required package'),
- rpm.RPMPROB_BADARCH: _('package for incorrect arch'),
- rpm.RPMPROB_BADOS: _('package for incorrect os'),
- }
-
- for (descr, (ty, mount, need)) in probs.value: # FIXME: probs.value???
- log.error("%s: %s" %(probTypes[ty], descr))
- if not uniqueProbs.has_key(ty) and probTypes.has_key(ty):
- uniqueProbs[ty] = probTypes[ty]
-
- if ty == rpm.RPMPROB_DISKSPACE:
- spaceneeded[mount] = need
- elif ty in [rpm.RPMPROB_NEW_FILE_CONFLICT, rpm.RPMPROB_FILE_CONFLICT]:
- fileConflicts.append(descr)
-
- if spaceneeded:
- spaceprob = _("You need more space on the following "
- "file systems:\n")
-
- for (mount, need) in spaceneeded.items():
- log.info("(%s, %s)" %(mount, need))
-
- if mount.startswith("/mnt/sysimage/"):
- mount.replace("/mnt/sysimage", "")
- elif mount.startswith("/mnt/sysimage"):
- mount = "/" + mount.replace("/mnt/sysimage", "")
-
- spaceprob += "%d M on %s\n" % (need / (1024*1024), mount)
- elif fileConflicts:
- fileprob = _("There were file conflicts when checking the "
- "packages to be installed:\n%s\n") % ("\n".join(fileConflicts),)
-
- msg = _("There was an error running your transaction for "
- "the following reason(s): %s.\n") % ', '.join(uniqueProbs.values())
-
- spaceprob = to_unicode(spaceprob)
- fileprob = to_unicode(fileprob)
-
- if self.anaconda.upgrade or self.anaconda.ksdata:
- intf.detailedMessageWindow(_("Error Running Transaction"),
- msg, spaceprob + "\n" + fileprob, type="custom",
- custom_icon="error", custom_buttons=[_("_Exit installer")])
- sys.exit(1)
- else:
- rc = intf.detailedMessageWindow(_("Error Running Transaction"),
- msg, spaceprob + "\n" + fileprob, type="custom",
- custom_icon="error",
- custom_buttons=[_("_Back"), _("_Exit installer")])
-
- if rc == 1:
- sys.exit(1)
- else:
- self._undoDepInstalls()
- return DISPATCH_BACK
-
- def doMacros(self):
- for (key, val) in self.macros.items():
- rpm.addMacro(key, val)
-
- def simpleDBInstalled(self, name, arch=None):
- # FIXME: doing this directly instead of using self.rpmdb.installed()
- # speeds things up by 400%
- mi = self.ts.ts.dbMatch('name', name)
- if mi.count() == 0:
- return False
- if arch is None:
- return True
- if arch in map(lambda h: h['arch'], mi):
- return True
- return False
-
- def isPackageInstalled(self, name = None, epoch = None, version = None,
- release = None, arch = None, po = None):
- # FIXME: this sucks. we should probably suck it into yum proper
- # but it'll need a bit of cleanup first.
- if po is not None:
- (name, epoch, version, release, arch) = po.returnNevraTuple()
-
- installed = False
- if name and not (epoch or version or release or arch):
- installed = self.simpleDBInstalled(name)
- elif self.rpmdb.installed(name = name, epoch = epoch, ver = version,
- rel = release, arch = arch):
- installed = True
-
- lst = self.tsInfo.matchNaevr(name = name, epoch = epoch,
- ver = version, rel = release,
- arch = arch)
- for txmbr in lst:
- if txmbr.output_state in TS_INSTALL_STATES:
- return True
- if installed and len(lst) > 0:
- # if we get here, then it was installed, but it's in the tsInfo
- # for an erase or obsoleted --> not going to be installed at end
- return False
- return installed
-
- def isGroupInstalled(self, grp):
- if grp.selected:
- return True
- elif grp.installed and not grp.toremove:
- return True
- return False
-
- def _pkgExists(self, pkg):
- """Whether or not a given package exists in our universe."""
- try:
- pkgs = self.pkgSack.returnNewestByName(pkg)
- return True
- except yum.Errors.PackageSackError:
- pass
- try:
- pkgs = self.rpmdb.returnNewestByName(pkg)
- return True
- except (IndexError, yum.Errors.PackageSackError):
- pass
- return False
-
- def _groupHasPackages(self, grp):
- # this checks to see if the given group has any packages available
- # (ie, already installed or in the sack of available packages)
- # so that we don't show empty groups. also, if there are mandatory
- # packages and we have none of them, don't show
- for pkg in grp.mandatory_packages.keys():
- if self._pkgExists(pkg):
- return True
- if len(grp.mandatory_packages) > 0:
- return False
- for pkg in grp.default_packages.keys() + grp.optional_packages.keys() + \
- grp.conditional_packages.keys():
- if self._pkgExists(pkg):
- return True
- return False
-
-class YumBackend(AnacondaBackend):
- def __init__ (self, anaconda):
- AnacondaBackend.__init__(self, anaconda)
- self.supportsPackageSelection = True
-
- buf = """
-[main]
-installroot=%s
-cachedir=/var/cache/yum/$basearch/$releasever
-keepcache=0
-logfile=/tmp/yum.log
-metadata_expire=0
-obsoletes=True
-pluginpath=/usr/lib/yum-plugins,/tmp/updates/yum-plugins
-pluginconfpath=/etc/yum/pluginconf.d,/tmp/updates/pluginconf.d
-plugins=1
-reposdir=/etc/anaconda.repos.d,/tmp/updates/anaconda.repos.d,/tmp/product/anaconda.repos.d
-""" % (ROOT_PATH)
-
- if anaconda.proxy:
- buf += "proxy=%s\n" % anaconda.proxy
-
- if anaconda.proxyUsername:
- buf += "proxy_username=%s\n" % anaconda.proxyUsername
-
- if anaconda.proxyPassword:
- buf += "proxy_password=%s\n" % anaconda.proxyPassword
-
- fd = open("/tmp/anaconda-yum.conf", "w")
- fd.write(buf)
- fd.close()
-
- def complete(self, anaconda):
- if not anaconda.mediaDevice and os.path.ismount(self.ayum.tree):
- isys.umount(self.ayum.tree)
-
- # clean up rpmdb locks so that kickstart %post scripts aren't
- # unhappy (#496961)
- iutil.resetRpmDb()
-
- if os.access(ROOT_PATH + "/tmp/yum.log", os.R_OK):
- os.unlink(ROOT_PATH + "/tmp/yum.log")
-
- self.ayum.history.close()
-
- def doBackendSetup(self, anaconda):
- if anaconda.dir == DISPATCH_BACK:
- return DISPATCH_BACK
-
- if anaconda.upgrade:
- # FIXME: make sure that the rpmdb doesn't have stale locks :/
- iutil.resetRpmDb()
-
- self.ayum = AnacondaYum(anaconda)
- self.ayum.setup()
-
- self.ayum.doMacros()
-
- # If any enabled repositories require networking, go ahead and bring
- # it up now. No need to have people wait for the timeout when we
- # know this in advance.
- for repo in self.ayum.repos.listEnabled():
- if repo.needsNetwork() and not network.hasActiveNetDev():
- if not anaconda.intf.enableNetwork():
- anaconda.intf.messageWindow(_("No Network Available"),
- _("Some of your software repositories require "
- "networking, but there was an error enabling the "
- "network on your system."),
- type="custom", custom_icon="error",
- custom_buttons=[_("_Exit installer")])
- sys.exit(1)
- break
-
- self.doRepoSetup(anaconda)
- self.doSackSetup(anaconda)
- self.doGroupSetup(anaconda)
-
- self.ayum.doMacros()
-
- def doGroupSetup(self, anaconda):
- while True:
- try:
- self.ayum.doGroupSetup()
- except (GroupsError, NoSuchGroup, RepoError) as e:
- buttons = [_("_Exit installer"), _("_Retry")]
- log.error("Unable to read group information: %s" % e)
- else:
- break # success
-
- rc = anaconda.intf.messageWindow(_("Error"),
- _("Unable to read group information "
- "from repositories. This is "
- "a problem with the generation "
- "of your install tree."),
- type="custom", custom_icon="error",
- custom_buttons = buttons)
- if rc == 0:
- sys.exit(0)
- else:
- self.ayum._setGroups(None)
- continue
-
- def doRepoSetup(self, anaconda, thisrepo = None, fatalerrors = True):
- self.__withFuncDo(anaconda, lambda r: self.ayum.doRepoSetup(thisrepo=r.id),
- thisrepo=thisrepo, fatalerrors=fatalerrors,
- callback=RepoSetupPulseProgress(anaconda.intf))
-
- def doSackSetup(self, anaconda, thisrepo = None, fatalerrors = True):
- self.__withFuncDo(anaconda, lambda r: self.ayum.doSackSetup(thisrepo=r.id),
- thisrepo=thisrepo, fatalerrors=fatalerrors,
- callback=SackSetupProgress(anaconda.intf))
-
- def __withFuncDo(self, anaconda, fn, thisrepo=None, fatalerrors=True,
- callback=None):
- # Don't do this if we're being called as a dispatcher step (instead
- # of being called when a repo is added via the UI) and we're going
- # back.
- if thisrepo is None and anaconda.dir == DISPATCH_BACK:
- return
-
- # We want to call the function one repo at a time so we have some
- # concept of which repo didn't set up correctly.
- if thisrepo is not None:
- repos = [self.ayum.repos.getRepo(thisrepo)]
- else:
- repos = self.ayum.repos.listEnabled()
-
- for repo in repos:
- if callback:
- callback.connect(repo)
-
- while True:
- try:
- fn(repo)
- if callback:
- callback.disconnect()
- except RepoError as e:
- if callback:
- callback.disconnect()
- buttons = [_("_Exit installer"), _("Edit"), _("_Retry")]
- else:
- break # success
-
- if anaconda.ksdata:
- buttons.append(_("_Continue"))
-
- if not fatalerrors:
- raise RepoError, e
-
- rc = anaconda.intf.messageWindow(_("Error"),
- _("Unable to read package metadata. This may be "
- "due to a missing repodata directory. Please "
- "ensure that your install tree has been "
- "correctly generated.\n\n%s" % e),
- type="custom", custom_icon="error",
- custom_buttons=buttons)
- if rc == 0:
- # abort
- sys.exit(0)
- elif rc == 1:
- # edit
- anaconda.intf.editRepoWindow(repo)
- break
- elif rc == 2:
- # retry, but only if button is present
- continue
- else:
- # continue, but only if button is present
- self.ayum.repos.delete(repo.id)
- break
-
- # if we're in kickstart the repo may have been deleted just above
- try:
- self.ayum.repos.getRepo(repo.id)
- except RepoError:
- log.debug("repo %s has been removed" % (repo.id,))
- continue
-
- repo.setFailureObj(self.ayum.urlgrabberFailureCB)
- repo.setMirrorFailureObj((self.ayum.mirrorFailureCB, (),
- {"repo": repo.id}))
-
- self.ayum.repos.callback = None
-
- def getDefaultGroups(self, anaconda):
- langs = anaconda.instLanguage.getCurrentLangSearchList()
- rc = map(lambda x: x.groupid,
- filter(lambda x: x.default, self.ayum.comps.groups))
- for g in self.ayum.comps.groups:
- if g.langonly in langs:
- rc.append(g.groupid)
- return rc
-
- def resetPackageSelections(self):
- """Reset the package selection to an empty state."""
- for txmbr in self.ayum.tsInfo:
- self.ayum.tsInfo.remove(txmbr.pkgtup)
- self.ayum.tsInfo.conditionals.clear()
- for grp in self.ayum.comps.groups:
- grp.selected = False
-
- def selectModulePackages(self, anaconda, kernelPkgName):
- (base, sep, ext) = kernelPkgName.partition("-")
-
- moduleProvides = []
-
- for (path, name) in anaconda.extraModules:
- if ext != "":
- moduleProvides.append("dud-%s-%s" % (name, ext))
- else:
- moduleProvides.append("dud-%s" % name)
-
- #We need to install the packages which contain modules from DriverDiscs
- for modPath in isys.modulesWithPaths():
- log.debug("Checking for DUD module "+modPath)
- match = DD_EXTRACTED.match(modPath)
- if match:
- log.info("Requesting install of kmod-%s" % (match.group("modulename")))
- moduleProvides.append("kmod-"+match.group("modulename"))
- else:
- continue
-
- for module in moduleProvides:
- pkgs = self.ayum.returnPackagesByDep(module)
-
- if not pkgs:
- log.warning("Didn't find any package providing %s" % module)
-
- for pkg in pkgs:
- log.info("selecting package %s for %s" % (pkg.name, module))
- self.ayum.install(po=pkg)
-
- def selectBestKernel(self, anaconda):
- """Find the best kernel package which is available and select it."""
-
- def getBestKernelByArch(pkgname, ayum):
- """Convenience func to find the best arch of a kernel by name"""
- try:
- pkgs = ayum.pkgSack.returnNewestByName(pkgname)
- except yum.Errors.PackageSackError:
- return None
-
- pkgs = self.ayum.bestPackagesFromList(pkgs)
- if len(pkgs) == 0:
- return None
- return pkgs[0]
-
- def selectKernel(pkgname):
- try:
- pkg = getBestKernelByArch(pkgname, self.ayum)
- except PackageSackError:
- log.debug("no %s package" % pkgname)
- return False
-
- if not pkg:
- return False
-
- log.info("selected %s package for kernel" % pkg.name)
- self.ayum.install(po=pkg)
- self.selectModulePackages(anaconda, pkg.name)
-
- if len(self.ayum.tsInfo.matchNaevr(name="gcc")) > 0:
- log.debug("selecting %s-devel" % pkg.name)
- self.selectPackage("%s-devel.%s" % (pkg.name, pkg.arch))
-
- return True
-
- foundkernel = False
-
- if not foundkernel and isys.isPaeAvailable():
- if selectKernel("kernel-PAE"):
- foundkernel = True
-
- if not foundkernel and iutil.isARM():
- if anaconda.platform.armMachine is not None:
- selectKernel("kernel-%s" % anaconda.platform.armMachine)
- foundkernel = True
-
- if not foundkernel:
- selectKernel("kernel")
-
- def selectFSPackages(self, storage):
- for device in storage.fsset.devices:
- # this takes care of device and filesystem packages
- map(self.selectPackage, device.packages)
-
- # anaconda requires several programs on the installed system to complete
- # installation, but we have no guarantees that some of these will be
- # installed (they could have been removed in kickstart). So we'll force
- # it.
- def selectAnacondaNeeds(self):
- for pkg in ['authconfig', 'chkconfig', 'system-config-firewall-base']:
- self.selectPackage(pkg)
-
- def doPostSelection(self, anaconda):
- # Only solve dependencies on the way through the installer, not the way back.
- if anaconda.dir == DISPATCH_BACK:
- return
-
- dscb = YumDepSolveProgress(anaconda.intf, self.ayum)
- self.ayum.dsCallback = dscb
-
- # do some sanity checks for kernel and bootloader
- if not anaconda.upgrade:
- # New installs only - upgrades will already have all this stuff.
- self.selectBestKernel(anaconda)
- map(self.selectPackage, anaconda.platform.packages)
- map(self.selectPackage, anaconda.bootloader.packages)
- self.selectFSPackages(anaconda.storage)
- self.selectAnacondaNeeds()
- else:
- if not anaconda.bootloader.skip_bootloader:
- map(self.deselectPackage, anaconda.bootloader.obsoletes)
- map(self.selectPackage, anaconda.bootloader.packages)
-
- self.ayum.update()
-
- while True:
- try:
- (code, msgs) = self.ayum.buildTransaction()
-
- # If %packages --ignoremissing was given, don't bother
- # prompting for missing dependencies.
- if anaconda.ksdata and anaconda.ksdata.packages.handleMissing == KS_MISSING_IGNORE:
- break
-
- if code == 1 and not anaconda.upgrade:
- # resolveDeps returns 0 if empty transaction, 1 if error,
- # 2 if success
- depprob = "\n".join(msgs)
-
- for m in msgs:
- log.warning(m)
-
- custom_buttons = [_("_Exit installer"), _("_Continue")]
- if not anaconda.ksdata:
- custom_buttons.insert(1, _("_Back"))
-
- rc = anaconda.intf.detailedMessageWindow(_("Warning"),
- _("Some of the packages you have selected for "
- "install are missing dependencies. You can "
- "exit the installation, go back and change "
- "your package selections, or continue "
- "installing these packages without their "
- "dependencies. If you continue, these packages "
- "may not work correctly due to missing components."),
- depprob + "\n", type="custom", custom_icon="error",
- custom_buttons=custom_buttons)
- dscb.pop()
-
- if rc == 0:
- sys.exit(1)
- elif rc == 1 and not anaconda.ksdata:
- self.ayum._undoDepInstalls()
- return DISPATCH_BACK
-
- break
- except RepoError as e:
- log.critical(e)
-
- # FIXME: would be nice to be able to recover here
- rc = anaconda.intf.messageWindow(_("Error"),
- _("Unable to read package metadata. This may be "
- "due to a missing repodata directory. Please "
- "ensure that your install tree has been "
- "correctly generated.\n\n%s" % e),
- type="custom", custom_icon="error",
- custom_buttons=[_("_Exit installer"), _("_Retry")])
- dscb.pop()
-
- if rc == 0:
- sys.exit(0)
- else:
- continue
- else:
- break
-
- (self.dlpkgs, self.totalSize, self.totalFiles) = self.ayum.getDownloadPkgs()
-
- if not anaconda.upgrade:
- largePart = anaconda.storage.mountpoints.get("/usr", anaconda.storage.rootDevice)
-
- if largePart and largePart.size < self.totalSize / 1024:
- rc = anaconda.intf.messageWindow(_("Error"),
- _("Your selected packages require %d MB "
- "of free space for installation, but "
- "you do not have enough available. "
- "You can change your selections or "
- "exit the installer." % (self.totalSize / 1024)),
- type="custom", custom_icon="error",
- custom_buttons=[_("_Back"), _("_Exit installer")])
-
- dscb.pop()
-
- if rc == 1:
- sys.exit(1)
- else:
- self.ayum._undoDepInstalls()
- return DISPATCH_BACK
-
- dscb.pop()
- self.ayum.dsCallback = None
-
- def doPreInstall(self, anaconda):
- dirList = ['/var', '/var/lib', '/var/lib/rpm', '/tmp', '/dev', '/etc',
- '/etc/sysconfig', '/etc/sysconfig/network-scripts',
- '/etc/X11', '/root', '/var/tmp', '/etc/rpm', '/var/cache',
- '/var/cache/yum', '/etc/modprobe.d']
-
- # If there are any protected partitions we want to mount, create their
- # mount points now.
- for protected in anaconda.storage.protectedDevices:
- if getattr(protected.format, "mountpoint", None):
- dirList.append(protected.format.mountpoint)
-
- for i in dirList:
- try:
- os.mkdir(ROOT_PATH + i)
- except OSError:
- pass
-# log.error("Error making directory %s: %s" % (i, msg))
-
- self.initLog(ROOT_PATH)
-
- # write out the fstab
- if not anaconda.upgrade:
- anaconda.storage.fsset.write()
- if os.access("/etc/modprobe.d/anaconda.conf", os.R_OK):
- shutil.copyfile("/etc/modprobe.d/anaconda.conf",
- ROOT_PATH + "/etc/modprobe.d/anaconda.conf")
- network.write_sysconfig_network()
- network.disableIPV6()
- network.copyConfigToPath(ROOT_PATH)
- if not anaconda.ksdata:
- anaconda.instClass.setNetworkOnbootDefault()
- anaconda.storage.write()
- else:
- # ensure that /etc/mtab is a symlink to /proc/self/mounts
- anaconda.storage.makeMtab()
-
- def doInstall(self, anaconda):
- log.info("Preparing to install packages")
-
- if not anaconda.upgrade:
- rpm.addMacro("__dbi_htconfig",
- "hash nofsync %{__dbi_other} %{__dbi_perms}")
-
- if anaconda.ksdata and anaconda.ksdata.packages.excludeDocs:
- rpm.addMacro("_excludedocs", "1")
-
- cb = AnacondaCallback(self.ayum, anaconda,
- self.instLog, self.modeText)
- cb.setSizes(len(self.dlpkgs), self.totalSize, self.totalFiles)
-
- rc = self.ayum.run(self.instLog, cb, anaconda.intf)
-
- if cb.initWindow is not None:
- cb.initWindow.pop()
-
- self.instLog.write("*** FINISHED INSTALLING PACKAGES ***")
- self.instLog.close ()
-
- anaconda.intf.setInstallProgressClass(None)
-
- if rc == DISPATCH_BACK:
- return DISPATCH_BACK
-
- def doPostInstall(self, anaconda):
- if anaconda.upgrade:
- w = anaconda.intf.waitWindow(_("Post Upgrade"),
- _("Performing post-upgrade configuration"))
- else:
- w = anaconda.intf.waitWindow(_("Post Installation"),
- _("Performing post-installation configuration"))
-
- packages.rpmSetupGraphicalSystem(anaconda)
-
- for repo in self.ayum.repos.listEnabled():
- repo.dirCleanup()
-
- # expire yum caches on upgrade
- if anaconda.upgrade and os.path.exists("%s/var/cache/yum" %(ROOT_PATH,)):
- log.info("Expiring yum caches")
- try:
- iutil.execWithRedirect("yum", ["clean", "all"],
- stdout="/dev/tty5", stderr="/dev/tty5",
- root = ROOT_PATH)
- except RuntimeError:
- pass
-
- # nuke preupgrade
- if flags.cmdline.has_key("preupgrade") and os.path.exists("%s/var/cache/yum/anaconda-upgrade" %(ROOT_PATH,)):
- try:
- shutil.rmtree("%s/var/cache/yum/anaconda-upgrade" %(ROOT_PATH,))
- except (OSError, IOError):
- pass
-
- # XXX: write proper lvm config
-
- AnacondaBackend.doPostInstall(self, anaconda)
- w.pop()
-
- def kernelVersionList(self):
- # FIXME: using rpm here is a little lame, but otherwise, we'd
- # be pulling in filelists
- return packages.rpmKernelVersionList()
-
- def __getGroupId(self, group):
- """Get the groupid for the given name (english or translated)."""
- for g in self.ayum.comps.groups:
- if group == g.name:
- return g.groupid
- for trans in g.translated_name.values():
- if group == trans:
- return g.groupid
-
- def isGroupSelected(self, group):
- try:
- grp = self.ayum.comps.return_group(group)
- if grp.selected: return True
- except yum.Errors.GroupsError:
- pass
- return False
-
- def selectGroup(self, group, *args):
- if not self.ayum.comps.has_group(group):
- log.debug("no such group %s" % group)
- raise NoSuchGroup, group
-
- types = ["mandatory"]
-
- if args:
- if args[0][0]:
- types.append("default")
- if args[0][1]:
- types.append("optional")
- else:
- types.append("default")
-
- try:
- mbrs = self.ayum.selectGroup(group, group_package_types=types)
- if len(mbrs) == 0 and self.isGroupSelected(group):
- return
- except yum.Errors.GroupsError:
- # try to find out if it's the name or translated name
- gid = self.__getGroupId(group)
- if gid is not None:
- mbrs = self.ayum.selectGroup(gid, group_package_types=types)
- if len(mbrs) == 0 and self.isGroupSelected(gid):
- return
- else:
- log.debug("no such group %s" %(group,))
- raise NoSuchGroup, group
-
- def deselectGroup(self, group, *args):
- try:
- self.ayum.deselectGroup(group, force=True)
- except yum.Errors.GroupsError:
- # try to find out if it's the name or translated name
- gid = self.__getGroupId(group)
- if gid is not None:
- self.ayum.deselectGroup(gid, force=True)
- else:
- log.debug("no such group %s" %(group,))
-
- def selectPackage(self, pkg, *args):
- if self.ayum.tsInfo.matchNaevr(name=pkg):
- return 0
-
- try:
- mbrs = self.ayum.install(pattern=pkg)
- return len(mbrs)
- except yum.Errors.InstallError:
- log.debug("no package matching %s" %(pkg,))
- return 0
-
- def deselectPackage(self, pkg, *args):
- sp = pkg.rsplit(".", 2)
- txmbrs = []
- if len(sp) == 2:
- txmbrs = self.ayum.tsInfo.matchNaevr(name=sp[0], arch=sp[1])
-
- if len(txmbrs) == 0:
- exact, match, unmatch = yum.packages.parsePackages(self.ayum.pkgSack.returnPackages(), [pkg], casematch=1)
- for p in exact + match:
- txmbrs.append(p)
-
- if len(txmbrs) > 0:
- for x in txmbrs:
- self.ayum.tsInfo.remove(x.pkgtup)
- # we also need to remove from the conditionals
- # dict so that things don't get pulled back in as a result
- # of them. yes, this is ugly. conditionals should die.
- for req, pkgs in self.ayum.tsInfo.conditionals.iteritems():
- if x in pkgs:
- pkgs.remove(x)
- self.ayum.tsInfo.conditionals[req] = pkgs
- return len(txmbrs)
- else:
- log.debug("no such package %s to remove" %(pkg,))
- return 0
-
- def groupListExists(self, grps):
- """Returns bool of whether all of the given groups exist."""
- for gid in grps:
- g = self.ayum.comps.return_group(gid)
- if not g:
- log.debug("no such group %s" % (gid,))
- return False
- return True
-
- def groupListDefault(self, grps):
- """Returns bool of whether all of the given groups are default"""
- rc = False
- for gid in grps:
- g = self.ayum.comps.return_group(gid)
- if g and not g.default:
- return False
- elif g:
- rc = True
- return rc
-
- def writeConfiguration(self):
- return
-
- def postAction(self, anaconda):
- self.ayum.close()
- self.ayum.closeRpmDB()
- iutil.resetRpmDb()
-
-class DownloadHeaderProgress:
- def __init__(self, intf, ayum=None):
- window = intf.progressWindow(_("Installation Starting"),
- _("Starting installation process"),
- 1.0, 0.01)
- self.window = window
- self.ayum = ayum
- self.current = self.loopstart = 0
- self.incr = 1
-
- if self.ayum is not None and self.ayum.tsInfo is not None:
- self.numpkgs = len(self.ayum.tsInfo.getMembers())
- if self.numpkgs != 0:
- self.incr = (1.0 / self.numpkgs) * (1.0 - self.loopstart)
- else:
- self.numpkgs = 0
-
- self.refresh()
-
- self.restartLoop = self.downloadHeader = self.transactionPopulation = self.refresh
- self.procReq = self.procConflict = self.unresolved = self.noop
-
- def noop(self, *args, **kwargs):
- pass
-
- def pkgAdded(self, *args):
- if self.numpkgs:
- self.set(self.current + self.incr)
-
- def pop(self):
- self.window.pop()
-
- def refresh(self, *args):
- self.window.refresh()
-
- def set(self, value):
- self.current = value
- self.window.set(self.current)
-
-class YumDepSolveProgress:
- def __init__(self, intf, ayum = None):
- window = intf.progressWindow(_("Dependency Check"),
- _("Checking dependencies in packages selected for installation"),
- 1.0, 0.01)
- self.window = window
-
- self.numpkgs = None
- self.loopstart = None
- self.incr = None
- self.ayum = ayum
- self.current = 0
-
- self.restartLoop = self.downloadHeader = self.transactionPopulation = self.refresh
- self.procReq = self.procConflict = self.unresolved = self.noop
-
- def tscheck(self, num = None):
- self.refresh()
- if num is None and self.ayum is not None and self.ayum.tsInfo is not None:
- num = len(self.ayum.tsInfo.getMembers())
-
- if num:
- self.numpkgs = num
- self.loopstart = self.current
- self.incr = (1.0 / num) * ((1.0 - self.loopstart) / 2)
-
- def pkgAdded(self, *args):
- if self.numpkgs:
- self.set(self.current + self.incr)
-
- def noop(self, *args, **kwargs):
- pass
-
- def refresh(self, *args):
- self.window.refresh()
-
- def set(self, value):
- self.current = value
- self.window.set(self.current)
-
- def start(self):
- self.set(0.0)
- self.refresh()
-
- def end(self):
- self.window.set(1.0)
- self.window.refresh()
-
- def pop(self):
- self.window.pop()
-
-# We don't have reasonable hook for sackSetup, and it
-# is fairly fast, so we use just waitWindow here
-class SackSetupProgress:
- def __init__(self, intf):
- self.intf = intf
-
- def connect(self, repo):
- if repo.name is None:
- txt = _("Retrieving installation information.")
- else:
- txt = _("Retrieving installation information for %s.")%(repo.name)
- self.window = self.intf.waitWindow(_("Installation Progress"), txt)
-
- def disconnect(self):
- self.window.pop()
-
-class RepoSetupPulseProgress:
- def __init__(self, intf):
- self.intf = intf
- self.repo = None
-
- def connect(self, repo):
- self.repo = repo
- if repo.name is None:
- txt = _("Retrieving installation information.")
- else:
- txt = _("Retrieving installation information for %s.")%(repo.name)
- self.window = self.intf.progressWindow(_("Installation Progress"),
- txt,
- 1.0, pulse=True)
- repo.setCallback(self)
-
- def disconnect(self):
- self.window.pop()
- self.repo.setCallback(None)
-
- def refresh(self, *args):
- self.window.refresh()
-
- def set(self):
- self.window.pulse()
-
- def start(self, filename, url, basename, size, text):
- log.debug("Grabbing %s" % url)
- self.set()
- self.refresh()
-
- def update(self, read):
- self.set()
- self.refresh()
-
- def end(self, read):
- self.set()
- self.window.refresh()
diff --git a/tests/pyanaconda_test/backend_test.py b/tests/pyanaconda_test/backend_test.py
index b09ee69..227a73a 100644
--- a/tests/pyanaconda_test/backend_test.py
+++ b/tests/pyanaconda_test/backend_test.py
@@ -11,8 +11,7 @@ class BackendTest(mock.TestCase):
'pyanaconda.storage.formats', 'logging',
'logging.config',
'ConfigParser', 'pyanaconda.anaconda_log',
- 'pyanaconda.storage.storage_log',
- 'pyanaconda.yuminstall'])
+ 'pyanaconda.storage.storage_log'])
import pyanaconda
pyanaconda.anaconda_log = mock.Mock()
--
1.8.0.2
11 years, 4 months
[PATCH] Don't allow mountpoints to start with /dev (#891447).
by Chris Lumens
---
pyanaconda/ui/gui/spokes/custom.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/pyanaconda/ui/gui/spokes/custom.py b/pyanaconda/ui/gui/spokes/custom.py
index 5e90202..9d73c03 100644
--- a/pyanaconda/ui/gui/spokes/custom.py
+++ b/pyanaconda/ui/gui/spokes/custom.py
@@ -195,6 +195,8 @@ def validate_mountpoint(mountpoint, used_mountpoints, strict=True):
valid = MOUNTPOINT_IN_USE
elif not mountpoint:
valid = MOUNTPOINT_EMPTY
+ elif mountpoint.startswith("/dev"):
+ valid = MOUNTPOINT_INVALID
elif (mountpoint.lower() not in fake_mountpoints and
((len(mountpoint) > 1 and mountpoint.endswith("/")) or
not mountpoint.startswith("/") or
--
1.7.11.2
11 years, 4 months
[PATCH 1/2] Put both the space label and the percent bar into the same cell.
by Chris Lumens
---
pyanaconda/ui/gui/spokes/lib/resize.glade | 4 ----
1 file changed, 4 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/lib/resize.glade b/pyanaconda/ui/gui/spokes/lib/resize.glade
index 0794941..05f5ad3 100644
--- a/pyanaconda/ui/gui/spokes/lib/resize.glade
+++ b/pyanaconda/ui/gui/spokes/lib/resize.glade
@@ -166,10 +166,6 @@
<attribute name="markup">3</attribute>
</attributes>
</child>
- </object>
- </child>
- <child>
- <object class="GtkTreeViewColumn" id="percentColumn">
<child>
<object class="GtkCellRendererProgress" id="percentRenderer"/>
<attributes>
--
1.7.11.2
11 years, 4 months
[PATCH 1/3] Add keyboard accelerators to a whole lot of widgets (#864964).
by Chris Lumens
---
pyanaconda/ui/gui/spokes/custom.glade | 81 +++++++++++++++++++--------
pyanaconda/ui/gui/spokes/custom.py | 4 +-
pyanaconda/ui/gui/spokes/datetime_spoke.glade | 20 ++++---
pyanaconda/ui/gui/spokes/keyboard.glade | 5 +-
pyanaconda/ui/gui/spokes/lib/accordion.py | 3 +-
pyanaconda/ui/gui/spokes/lib/cart.glade | 1 +
pyanaconda/ui/gui/spokes/lib/cart.py | 4 +-
pyanaconda/ui/gui/spokes/lib/passphrase.glade | 13 ++++-
pyanaconda/ui/gui/spokes/lib/resize.glade | 12 +++-
pyanaconda/ui/gui/spokes/network.glade | 43 +-------------
pyanaconda/ui/gui/spokes/password.glade | 9 ++-
pyanaconda/ui/gui/spokes/source.glade | 35 +++++++-----
pyanaconda/ui/gui/spokes/storage.glade | 12 ++--
13 files changed, 139 insertions(+), 103 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/custom.glade b/pyanaconda/ui/gui/spokes/custom.glade
index 59eb541..72d06ca 100644
--- a/pyanaconda/ui/gui/spokes/custom.glade
+++ b/pyanaconda/ui/gui/spokes/custom.glade
@@ -137,8 +137,10 @@
<property name="can_focus">False</property>
<property name="margin_top">6</property>
<property name="xalign">1</property>
- <property name="label" translatable="yes"><b>Desired Capacity:</b></property>
+ <property name="label" translatable="yes"><b>_Desired Capacity:</b></property>
<property name="use_markup">True</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">sizeEntry</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -152,8 +154,10 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes"><b>Mount Point:</b></property>
+ <property name="label" translatable="yes"><b>M_ount Point:</b></property>
<property name="use_markup">True</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">addMountPointEntry</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -320,10 +324,11 @@ use. Try something else?</property>
</child>
<child>
<object class="GtkCheckButton" id="removeAllCheckbox">
- <property name="label" translatable="yes">Delete all other filesystems in the %s root as well.</property>
+ <property name="label" translatable="yes">Delete _all other filesystems in the %s root as well.</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
+ <property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
</object>
@@ -556,8 +561,10 @@ you'll be able to view their details here.</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes"><b>Mount Point:</b></property>
+ <property name="label" translatable="yes"><b>M_ount Point:</b></property>
<property name="use_markup">True</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">mountPointEntry</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -586,8 +593,10 @@ you'll be able to view their details here.</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes"><b>Label:</b></property>
+ <property name="label" translatable="yes"><b>_Label:</b></property>
<property name="use_markup">True</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">labelEntry</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -602,8 +611,10 @@ you'll be able to view their details here.</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes"><b>Desired Capacity (MB):</b></property>
+ <property name="label" translatable="yes"><b>_Desired Capacity (MB):</b></property>
<property name="use_markup">True</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">sizeSpinner</property>
</object>
<packing>
<property name="left_attach">2</property>
@@ -649,7 +660,9 @@ you'll be able to view their details here.</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">Name:</property>
+ <property name="label" translatable="yes">_Name:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">nameEntry</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
@@ -710,8 +723,10 @@ you'll be able to view their details here.</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes"><b>Device Type:</b></property>
+ <property name="label" translatable="yes"><b>Device _Type:</b></property>
<property name="use_markup">True</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">deviceTypeCombo</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -725,8 +740,10 @@ you'll be able to view their details here.</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes"><b>File System:</b></property>
+ <property name="label" translatable="yes"><b>File _System:</b></property>
<property name="use_markup">True</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">fileSystemTypeCombo</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -804,10 +821,11 @@ you'll be able to view their details here.</property>
<property name="can_focus">False</property>
<child>
<object class="GtkCheckButton" id="lvmRedundancyCheckbox">
- <property name="label" translatable="yes">Redundancy (mirror)</property>
+ <property name="label" translatable="yes">Redundancy (_mirror)</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
+ <property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_raid_feature_toggled" swapped="no"/>
@@ -848,10 +866,11 @@ you'll be able to view their details here.</property>
<property name="can_focus">False</property>
<child>
<object class="GtkCheckButton" id="lvmPerformanceCheckbox">
- <property name="label" translatable="yes">Optimized performance (stripe)</property>
+ <property name="label" translatable="yes">Optimi_zed performance (stripe)</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
+ <property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_raid_feature_toggled" swapped="no"/>
@@ -901,10 +920,11 @@ you'll be able to view their details here.</property>
<property name="can_focus">False</property>
<child>
<object class="GtkCheckButton" id="raidRedundancyCheckbox">
- <property name="label" translatable="yes">Redundancy (mirror)</property>
+ <property name="label" translatable="yes">Redundancy (_mirror)</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
+ <property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_raid_feature_toggled" swapped="no"/>
@@ -945,10 +965,11 @@ you'll be able to view their details here.</property>
<property name="can_focus">False</property>
<child>
<object class="GtkCheckButton" id="raidPerformanceCheckbox">
- <property name="label" translatable="yes">Optimized performance (stripe)</property>
+ <property name="label" translatable="yes">Optimi_zed performance (stripe)</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
+ <property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_raid_feature_toggled" swapped="no"/>
@@ -988,10 +1009,11 @@ you'll be able to view their details here.</property>
<property name="can_focus">False</property>
<child>
<object class="GtkCheckButton" id="raidErrorCheckbox">
- <property name="label" translatable="yes">Error detection (parity)</property>
+ <property name="label" translatable="yes">Error detection (_parity)</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
+ <property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_raid_feature_toggled" swapped="no"/>
@@ -1032,10 +1054,11 @@ you'll be able to view their details here.</property>
<property name="margin_left">12</property>
<child>
<object class="GtkCheckButton" id="raidDistErrorCheckbox">
- <property name="label" translatable="yes">Distributed</property>
+ <property name="label" translatable="yes">D_istributed</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
+ <property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_raid_feature_toggled" swapped="no"/>
@@ -1063,11 +1086,12 @@ you'll be able to view their details here.</property>
</child>
<child>
<object class="GtkCheckButton" id="raidRedundantErrorCheckbox">
- <property name="label" translatable="yes">Redundant</property>
+ <property name="label" translatable="yes">Red_undant</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="margin_left">6</property>
+ <property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_raid_feature_toggled" swapped="no"/>
@@ -1142,10 +1166,11 @@ you'll be able to view their details here.</property>
<property name="can_focus">False</property>
<child>
<object class="GtkCheckButton" id="btrfsRedundancyCheckbox">
- <property name="label" translatable="yes">Redundancy (mirror)</property>
+ <property name="label" translatable="yes">Redundancy (_mirror)</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
+ <property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_raid_feature_toggled" swapped="no"/>
@@ -1186,10 +1211,11 @@ you'll be able to view their details here.</property>
<property name="can_focus">False</property>
<child>
<object class="GtkCheckButton" id="btrfsPerformanceCheckbox">
- <property name="label" translatable="yes">Optimized performance (stripe)</property>
+ <property name="label" translatable="yes">Optimi_zed performance (stripe)</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
+ <property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_raid_feature_toggled" swapped="no"/>
@@ -1241,10 +1267,11 @@ you'll be able to view their details here.</property>
</child>
<child>
<object class="GtkCheckButton" id="reformatCheckbox">
- <property name="label" translatable="yes">Reformat</property>
+ <property name="label" translatable="yes">_Reformat</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
+ <property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_reformat_toggled" swapped="no"/>
@@ -1260,7 +1287,9 @@ you'll be able to view their details here.</property>
<object class="GtkLabel" id="volumeGroupLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">Volume Group:</property>
+ <property name="label" translatable="yes">_Volume Group:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">volumeGroupCombo</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
@@ -1289,10 +1318,11 @@ you'll be able to view their details here.</property>
</child>
<child>
<object class="GtkButton" id="modifyVGButton">
- <property name="label" translatable="yes">Modify ...</property>
+ <property name="label" translatable="yes">Modif_y...</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
+ <property name="use_underline">True</property>
<signal name="clicked" handler="on_modify_vg_clicked" swapped="no"/>
</object>
<packing>
@@ -1433,7 +1463,8 @@ you'll be able to view their details here.</property>
<object class="GtkLabel" id="passphraseLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">Passphrase:</property>
+ <property name="label" translatable="yes">_Passphrase:</property>
+ <property name="use_underline">True</property>
<attributes>
<attribute name="font-desc" value="Cantarell 11"/>
</attributes>
@@ -1450,6 +1481,7 @@ you'll be able to view their details here.</property>
<property name="can_focus">True</property>
<property name="visibility">False</property>
<property name="invisible_char">●</property>
+ <accelerator key="p" signal="grab-focus" modifiers="GDK_MOD1_MASK"/>
</object>
<packing>
<property name="expand">False</property>
@@ -2034,7 +2066,9 @@ you'll be able to view their details here.</property>
<object class="GtkLabel" id="label15">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">Name:</property>
+ <property name="label" translatable="yes">_Name:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">vg_name_entry</property>
</object>
<packing>
<property name="expand">False</property>
@@ -2047,6 +2081,7 @@ you'll be able to view their details here.</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">●</property>
+ <accelerator key="n" signal="grab-focus" modifiers="GDK_MOD1_MASK"/>
</object>
<packing>
<property name="expand">False</property>
diff --git a/pyanaconda/ui/gui/spokes/custom.py b/pyanaconda/ui/gui/spokes/custom.py
index 95a4398..e7b47e5 100644
--- a/pyanaconda/ui/gui/spokes/custom.py
+++ b/pyanaconda/ui/gui/spokes/custom.py
@@ -633,8 +633,8 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
summaryLabel = self._summaryButton.get_children()[0]
count = len(self.data.clearpart.drives)
- summary = P_("%d storage device selected",
- "%d storage devices selected",
+ summary = P_("%d _storage device selected",
+ "%d _storage devices selected",
count) % count
summaryLabel.set_use_markup(True)
diff --git a/pyanaconda/ui/gui/spokes/datetime_spoke.glade b/pyanaconda/ui/gui/spokes/datetime_spoke.glade
index d302645..d2b9825 100644
--- a/pyanaconda/ui/gui/spokes/datetime_spoke.glade
+++ b/pyanaconda/ui/gui/spokes/datetime_spoke.glade
@@ -84,7 +84,9 @@
<object class="GtkLabel" id="regionLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">Region:</property>
+ <property name="label" translatable="yes">_Region:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">regionCombobox</property>
</object>
<packing>
<property name="expand">False</property>
@@ -117,7 +119,9 @@
<object class="GtkLabel" id="cityLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">City:</property>
+ <property name="label" translatable="yes">_City:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">cityCombobox</property>
</object>
<packing>
<property name="expand">False</property>
@@ -161,7 +165,9 @@
<object class="GtkLabel" id="networkTimeLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">Network Time</property>
+ <property name="label" translatable="yes">_Network Time</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">networkTimeSwitch</property>
</object>
<packing>
<property name="expand">False</property>
@@ -458,11 +464,11 @@
<property name="orientation">vertical</property>
<child>
<object class="GtkRadioButton" id="timeFormatRB">
- <property name="label" translatable="yes">24-hour</property>
+ <property name="label" translatable="yes">24-_hour</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
- <property name="use_action_appearance">False</property>
+ <property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
@@ -476,11 +482,11 @@
</child>
<child>
<object class="GtkRadioButton" id="timeFormatRB2">
- <property name="label" translatable="yes">AM/PM</property>
+ <property name="label" translatable="yes">_AM/PM</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
- <property name="use_action_appearance">False</property>
+ <property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
<property name="group">timeFormatRB</property>
diff --git a/pyanaconda/ui/gui/spokes/keyboard.glade b/pyanaconda/ui/gui/spokes/keyboard.glade
index 0eb063c..d48c1c9 100644
--- a/pyanaconda/ui/gui/spokes/keyboard.glade
+++ b/pyanaconda/ui/gui/spokes/keyboard.glade
@@ -187,6 +187,7 @@
<property name="orientation">vertical</property>
<child internal-child="nav_box">
<object class="GtkEventBox" id="AnacondaSpokeWindow-nav_box1">
+ <property name="can_focus">False</property>
<child internal-child="nav_area">
<object class="GtkGrid" id="AnacondaSpokeWindow-nav_area1">
<property name="can_focus">False</property>
@@ -450,7 +451,9 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
- <property name="label" translatable="yes">Test the layout configuration below:</property>
+ <property name="label" translatable="yes">_Test the layout configuration below:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">layoutTextView</property>
<attributes>
<attribute name="font-desc" value="Cantarell 10"/>
</attributes>
diff --git a/pyanaconda/ui/gui/spokes/lib/accordion.py b/pyanaconda/ui/gui/spokes/lib/accordion.py
index af10a1e..2b1f217 100644
--- a/pyanaconda/ui/gui/spokes/lib/accordion.py
+++ b/pyanaconda/ui/gui/spokes/lib/accordion.py
@@ -237,9 +237,10 @@ class CreateNewPage(Page):
label.set_line_wrap(True)
self._createBox.add(label)
- self._createNewButton = Gtk.LinkButton("", label=_("Click here to create them automatically."))
+ self._createNewButton = Gtk.LinkButton("", label=_("_Click here to create them automatically."))
label = self._createNewButton.get_children()[0]
label.set_line_wrap(True)
+ label.set_use_underline(True)
self._createNewButton.set_has_tooltip(False)
self._createNewButton.set_halign(Gtk.Align.START)
diff --git a/pyanaconda/ui/gui/spokes/lib/cart.glade b/pyanaconda/ui/gui/spokes/lib/cart.glade
index a51d1b2..0743a9f 100644
--- a/pyanaconda/ui/gui/spokes/lib/cart.glade
+++ b/pyanaconda/ui/gui/spokes/lib/cart.glade
@@ -234,6 +234,7 @@
<property name="xalign">0</property>
<property name="label" translatable="yes">Disk summary goes here</property>
<property name="use_markup">True</property>
+ <property name="use_underline">True</property>
</object>
<packing>
<property name="expand">False</property>
diff --git a/pyanaconda/ui/gui/spokes/lib/cart.py b/pyanaconda/ui/gui/spokes/lib/cart.py
index ea3cac2..76d3649 100644
--- a/pyanaconda/ui/gui/spokes/lib/cart.py
+++ b/pyanaconda/ui/gui/spokes/lib/cart.py
@@ -135,9 +135,9 @@ class SelectedDisksDialog(GUIObject):
size = str(Size(bytes=long(size))).upper()
free = str(Size(bytes=long(free))).upper()
- text = P_("<b>%d disk; %s capacity; %s free space</b> "
+ text = P_("<b>%d d_isk; %s capacity; %s free space</b> "
"(unpartitioned and in filesystems)",
- "<b>%d disks; %s capacity; %s free space</b> "
+ "<b>%d d_isks; %s capacity; %s free space</b> "
"(unpartitioned and in filesystems)",
count) % (count, size, free)
self._summary_label.set_markup(text)
diff --git a/pyanaconda/ui/gui/spokes/lib/passphrase.glade b/pyanaconda/ui/gui/spokes/lib/passphrase.glade
index ca912f5..cb08899 100644
--- a/pyanaconda/ui/gui/spokes/lib/passphrase.glade
+++ b/pyanaconda/ui/gui/spokes/lib/passphrase.glade
@@ -49,10 +49,11 @@
</child>
<child>
<object class="GtkButton" id="passphrase_save_button">
- <property name="label" translatable="yes">Save Passphrase</property>
+ <property name="label" translatable="yes">_Save Passphrase</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
+ <property name="use_underline">True</property>
<signal name="clicked" handler="on_save_clicked" swapped="no"/>
</object>
<packing>
@@ -94,7 +95,10 @@
<object class="GtkLabel" id="passphrase_entry_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">Passphrase:</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Passphrase:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">passphrase_entry</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -124,7 +128,10 @@
<object class="GtkLabel" id="confirm_entry_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">Confirm:</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Confirm:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">confirm_entry</property>
</object>
<packing>
<property name="left_attach">0</property>
diff --git a/pyanaconda/ui/gui/spokes/lib/resize.glade b/pyanaconda/ui/gui/spokes/lib/resize.glade
index c7074ba..05f5ad3 100644
--- a/pyanaconda/ui/gui/spokes/lib/resize.glade
+++ b/pyanaconda/ui/gui/spokes/lib/resize.glade
@@ -209,7 +209,9 @@
<object class="GtkToolButton" id="preserveButton">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">Preserve</property>
+ <property name="label" translatable="yes">_Preserve</property>
+ <property name="use_underline">True</property>
+ <accelerator key="p" signal="clicked" modifiers="GDK_MOD1_MASK"/>
<signal name="clicked" handler="on_preserve_clicked" swapped="no"/>
</object>
<packing>
@@ -221,7 +223,9 @@
<object class="GtkToolButton" id="shrinkButton">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">Shrink</property>
+ <property name="label" translatable="yes">_Shrink</property>
+ <property name="use_underline">True</property>
+ <accelerator key="s" signal="clicked" modifiers="GDK_MOD1_MASK"/>
<signal name="clicked" handler="on_shrink_clicked" swapped="no"/>
</object>
<packing>
@@ -233,7 +237,9 @@
<object class="GtkToolButton" id="deleteButton">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">Delete</property>
+ <property name="label" translatable="yes">_Delete</property>
+ <property name="use_underline">True</property>
+ <accelerator key="d" signal="clicked" modifiers="GDK_MOD1_MASK"/>
<signal name="clicked" handler="on_delete_clicked" swapped="no"/>
</object>
<packing>
diff --git a/pyanaconda/ui/gui/spokes/network.glade b/pyanaconda/ui/gui/spokes/network.glade
index 5fc0613..4d8042f 100644
--- a/pyanaconda/ui/gui/spokes/network.glade
+++ b/pyanaconda/ui/gui/spokes/network.glade
@@ -575,27 +575,6 @@ updates available for you.</property>
<child>
<placeholder/>
</child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
</object>
<packing>
<property name="expand">True</property>
@@ -1083,24 +1062,6 @@ updates available for you.</property>
<property name="height">1</property>
</packing>
</child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
</object>
<packing>
<property name="expand">True</property>
@@ -2200,11 +2161,11 @@ updates available for you.</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="button_unlock">
- <property name="label" translatable="yes">Unlock</property>
+ <property name="label" translatable="yes">Unloc_k</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
- <property name="use_action_appearance">False</property>
+ <property name="use_underline">True</property>
</object>
<packing>
<property name="expand">False</property>
diff --git a/pyanaconda/ui/gui/spokes/password.glade b/pyanaconda/ui/gui/spokes/password.glade
index 043f0ad..75ac957 100644
--- a/pyanaconda/ui/gui/spokes/password.glade
+++ b/pyanaconda/ui/gui/spokes/password.glade
@@ -15,6 +15,7 @@
<property name="spacing">6</property>
<child internal-child="nav_box">
<object class="GtkEventBox" id="AnacondaSpokeWindow-nav_box1">
+ <property name="can_focus">False</property>
<child internal-child="nav_area">
<object class="GtkGrid" id="AnacondaSpokeWindow-nav_area1">
<property name="can_focus">False</property>
@@ -49,8 +50,10 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">Root Password:</property>
+ <property name="label" translatable="yes">_Root Password:</property>
<property name="use_markup">True</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">pw</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -64,8 +67,10 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">Confirm:</property>
+ <property name="label" translatable="yes">_Confirm:</property>
<property name="use_markup">True</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">confirm</property>
</object>
<packing>
<property name="left_attach">0</property>
diff --git a/pyanaconda/ui/gui/spokes/source.glade b/pyanaconda/ui/gui/spokes/source.glade
index 07fc23d..78cc901 100644
--- a/pyanaconda/ui/gui/spokes/source.glade
+++ b/pyanaconda/ui/gui/spokes/source.glade
@@ -186,7 +186,8 @@
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">Fedora People Repositories</property>
+ <property name="label" translatable="yes">_Fedora People Repositories</property>
+ <property name="use_underline">True</property>
</object>
</child>
</object>
@@ -303,7 +304,8 @@
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">Standard YUM repository:</property>
+ <property name="label" translatable="yes">_Standard YUM repository:</property>
+ <property name="use_underline">True</property>
</object>
</child>
</object>
@@ -665,8 +667,10 @@ TeXlive 2012 repository</col>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes"><b>Proxy URL</b></property>
+ <property name="label" translatable="yes"><b>_Proxy URL</b></property>
<property name="use_markup">True</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">proxyURLEntry</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -740,8 +744,10 @@ TeXlive 2012 repository</col>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes"><b>Username</b></property>
+ <property name="label" translatable="yes"><b>User_name</b></property>
<property name="use_markup">True</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">proxyUsernameEntry</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -755,8 +761,10 @@ TeXlive 2012 repository</col>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes"><b>Password</b></property>
+ <property name="label" translatable="yes"><b>Pass_word</b></property>
<property name="use_markup">True</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">proxyPasswordEntry</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -832,6 +840,7 @@ TeXlive 2012 repository</col>
<property name="orientation">vertical</property>
<child internal-child="nav_box">
<object class="GtkEventBox" id="AnacondaSpokeWindow-nav_box1">
+ <property name="can_focus">False</property>
<child internal-child="nav_area">
<object class="GtkGrid" id="AnacondaSpokeWindow-nav_area1">
<property name="can_focus">False</property>
@@ -985,7 +994,9 @@ TeXlive 2012 repository</col>
<object class="GtkLabel" id="label6">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">Device:</property>
+ <property name="label" translatable="yes">D_evice:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">isoPartitionCombo</property>
</object>
<packing>
<property name="expand">False</property>
@@ -1083,12 +1094,6 @@ TeXlive 2012 repository</col>
<property name="row_spacing">6</property>
<property name="column_spacing">6</property>
<child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
<object class="GtkComboBoxText" id="protocolComboBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -1179,7 +1184,9 @@ TeXlive 2012 repository</col>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">NFS mount options:</property>
+ <property name="label" translatable="yes">NFS mount _options:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">nfsOptsEntry</property>
</object>
<packing>
<property name="expand">False</property>
@@ -1237,7 +1244,7 @@ TeXlive 2012 repository</col>
</child>
<child>
<object class="GtkCheckButton" id="noUpdatesCheckbox">
- <property name="label" translatable="yes">D_on't install the latest available software updates. Install the default versions provided by the install source above.</property>
+ <property name="label" translatable="yes">Don't install the latest available software _updates. Install the default versions provided by the install source above.</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
diff --git a/pyanaconda/ui/gui/spokes/storage.glade b/pyanaconda/ui/gui/spokes/storage.glade
index 27f5e61..43e2791 100644
--- a/pyanaconda/ui/gui/spokes/storage.glade
+++ b/pyanaconda/ui/gui/spokes/storage.glade
@@ -152,7 +152,8 @@
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">Partition scheme configuration</property>
+ <property name="label" translatable="yes">Partition _scheme configuration</property>
+ <property name="use_underline">True</property>
<attributes>
<attribute name="font-desc" value="Cantarell 11"/>
</attributes>
@@ -507,7 +508,8 @@
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">Partition scheme configuration</property>
+ <property name="label" translatable="yes">Partition _scheme configuration</property>
+ <property name="use_underline">True</property>
<attributes>
<attribute name="font-desc" value="Cantarell 11"/>
</attributes>
@@ -853,6 +855,7 @@
<property name="spacing">6</property>
<child internal-child="nav_box">
<object class="GtkEventBox" id="AnacondaSpokeWindow-nav_box1">
+ <property name="can_focus">False</property>
<child internal-child="nav_area">
<object class="GtkGrid" id="AnacondaSpokeWindow-nav_area1">
<property name="can_focus">False</property>
@@ -969,7 +972,7 @@
</child>
<child>
<object class="GtkButton" id="summary_button">
- <property name="label" translatable="yes">Full disk summary and options...</property>
+ <property name="label" translatable="yes">_Full disk summary and options...</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -1008,13 +1011,14 @@
</child>
<child>
<object class="GtkCheckButton" id="encryption_checkbutton">
- <property name="label" translatable="yes">Encrypt my data. I'll set a passphrase later.</property>
+ <property name="label" translatable="yes">_Encrypt my data. I'll set a passphrase later.</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="halign">end</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
+ <property name="use_underline">True</property>
</object>
<packing>
<property name="left_attach">1</property>
--
1.7.11.2
11 years, 4 months
[f18-branch/master 1/2] protect getDirSize from vanishing files (#891759)
by Brian C. Lane
From: "Brian C. Lane" <bcl(a)redhat.com>
Now that we're threaded things can get ugly. While examing the
filesystem things can vanish, causing an error. This ignores files that
go missing while getting the size of a directory.
---
pyanaconda/iutil.py | 34 ++++++++++++++++++++++++----------
1 file changed, 24 insertions(+), 10 deletions(-)
diff --git a/pyanaconda/iutil.py b/pyanaconda/iutil.py
index 9ac0da7..c86c63b 100644
--- a/pyanaconda/iutil.py
+++ b/pyanaconda/iutil.py
@@ -420,18 +420,34 @@ def execConsole():
except OSError as e:
raise RuntimeError, "Error running /bin/sh: " + e.strerror
-## Get the size of a directory and all its subdirectories.
-# @param dir The name of the directory to find the size of.
-# @return The size of the directory in kilobytes.
def getDirSize(dir):
+ """ Get the size of a directory and all its subdirectories.
+ @param dir The name of the directory to find the size of.
+ @return The size of the directory in kilobytes.
+ """
def getSubdirSize(dir):
- # returns size in bytes
- mydev = os.lstat(dir)[stat.ST_DEV]
+ # returns size in bytes
+ try:
+ mydev = os.lstat(dir)[stat.ST_DEV]
+ except OSError as e:
+ log.debug("failed to stat %s: %s" % (dir, e))
+ return 0
+
+ try:
+ dirlist = os.listdir(dir)
+ except OSError as e:
+ log.debug("failed to listdir %s: %s" % (dir, e))
+ return 0
dsize = 0
- for f in os.listdir(dir):
- curpath = '%s/%s' % (dir, f)
- sinfo = os.lstat(curpath)
+ for f in dirlist:
+ curpath = '%s/%s' % (dir, f)
+ try:
+ sinfo = os.lstat(curpath)
+ except OSError as e:
+ log.debug("failed to stat %s/%s: %s" % (dir, f, e))
+ continue
+
if stat.S_ISDIR(sinfo[stat.ST_MODE]):
if os.path.ismount(curpath):
continue
@@ -439,8 +455,6 @@ def getDirSize(dir):
dsize += getSubdirSize(curpath)
elif stat.S_ISREG(sinfo[stat.ST_MODE]):
dsize += sinfo[stat.ST_SIZE]
- else:
- pass
return dsize
return getSubdirSize(dir)/1024
--
1.8.0.2
11 years, 4 months