/[smeserver]/cdrom.image/sme9/updates/yuminstall.py
ViewVC logotype

Annotation of /cdrom.image/sme9/updates/yuminstall.py

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1 - (hide annotations) (download) (as text)
Mon Mar 11 18:03:05 2013 UTC (11 years, 5 months ago) by slords
Branch: MAIN
Content type: text/x-python
New sme9 tree

1 slords 1.1 #
2     # yuminstall.py
3     #
4     # Copyright (C) 2005, 2006, 2007 Red Hat, Inc. All rights reserved.
5     #
6     # This program is free software; you can redistribute it and/or modify
7     # it under the terms of the GNU General Public License as published by
8     # the Free Software Foundation; either version 2 of the License, or
9     # (at your option) any later version.
10     #
11     # This program is distributed in the hope that it will be useful,
12     # but WITHOUT ANY WARRANTY; without even the implied warranty of
13     # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     # GNU General Public License for more details.
15     #
16     # You should have received a copy of the GNU General Public License
17     # along with this program. If not, see <http://www.gnu.org/licenses/>.
18     #
19    
20     from flags import flags
21     from errors import *
22    
23     from ConfigParser import ConfigParser
24     import sys
25     import os
26     import os.path
27     import shutil
28     import time
29     import warnings
30     import types
31     import locale
32     import glob
33     import tempfile
34     import itertools
35     import re
36    
37    
38     import anaconda_log
39     import rpm
40     import rpmUtils
41     import urlgrabber.progress
42     import urlgrabber.grabber
43     from urlgrabber.grabber import URLGrabber, URLGrabError
44     import yum
45     import iniparse
46     from yum.constants import *
47     from yum.Errors import *
48     from yum.misc import to_unicode
49     from yum.yumRepo import YumRepository
50     from backend import AnacondaBackend
51     from product import *
52     from sortedtransaction import SplitMediaTransactionData
53     from constants import *
54     from image import *
55     from compssort import *
56     import packages
57     import iutil
58    
59     import gettext
60     _ = lambda x: gettext.ldgettext("anaconda", x)
61     P_ = lambda x, y, z: gettext.ldngettext("anaconda", x, y, z)
62    
63     import network
64    
65     # specspo stuff
66     rpm.addMacro("_i18ndomains", "redhat-dist")
67    
68     import logging
69     log = logging.getLogger("anaconda")
70    
71     import urlparse
72     urlparse.uses_fragment.append('media')
73    
74     urlgrabber.grabber.default_grabber.opts.user_agent = "%s (anaconda)/%s" %(productName, productVersion)
75    
76     import iutil
77     import isys
78    
79     def size_string (size):
80     def number_format(s):
81     return locale.format("%s", s, 1)
82    
83     retval = None
84    
85     if size > 1024 * 1024:
86     size = size / (1024*1024)
87     retval = _("%s MB") %(number_format(size),)
88     elif size > 1024:
89     size = size / 1024
90     retval = _("%s KB") %(number_format(size),)
91     else:
92     retval = P_("%s Byte", "%s Bytes", size) % (number_format(size),)
93    
94     return to_unicode(retval)
95    
96     class AnacondaCallback:
97    
98     def __init__(self, ayum, anaconda, instLog, modeText):
99     self.repos = ayum.repos
100     self.ts = ayum.ts
101     self.ayum = ayum
102    
103     self.messageWindow = anaconda.intf.messageWindow
104     self.pulseWindow = anaconda.intf.progressWindow
105     self.progress = anaconda.id.instProgress
106     self.progressWindowClass = anaconda.intf.progressWindow
107     self.rootPath = anaconda.rootPath
108    
109     self.initWindow = None
110    
111     self.progressWindow = None
112     self.lastprogress = 0
113     self.incr = 20
114    
115     self.instLog = instLog
116     self.modeText = modeText
117    
118     self.openfile = None
119     self.inProgressPo = None
120    
121     def setSizes(self, numpkgs, totalSize, totalFiles):
122     self.numpkgs = numpkgs
123     self.totalSize = totalSize
124     self.totalFiles = totalFiles
125    
126     self.donepkgs = 0
127     self.doneSize = 0
128     self.doneFiles = 0
129    
130    
131     def callback(self, what, amount, total, h, user):
132     if what == rpm.RPMCALLBACK_TRANS_START:
133     # step 6 is the bulk of the ts processing time
134     if amount == 6:
135     self.progressWindow = \
136     self.progressWindowClass (_("Preparing to install"),
137     _("Preparing transaction from installation source"),
138     total)
139     self.incr = total / 10
140    
141     if what == rpm.RPMCALLBACK_TRANS_PROGRESS:
142     if self.progressWindow and amount > self.lastprogress + self.incr:
143     self.progressWindow.set(amount)
144     self.lastprogress = amount
145    
146     if what == rpm.RPMCALLBACK_TRANS_STOP and self.progressWindow:
147     self.progressWindow.pop()
148    
149     if what == rpm.RPMCALLBACK_INST_OPEN_FILE:
150     (hdr, rpmloc) = h
151     # hate hate hate at epochs...
152     epoch = hdr['epoch']
153     if epoch is not None:
154     epoch = str(epoch)
155     txmbrs = self.ayum.tsInfo.matchNaevr(hdr['name'], hdr['arch'],
156     epoch, hdr['version'],
157     hdr['release'])
158     if len(txmbrs) == 0:
159     raise RuntimeError, "Unable to find package %s-%s-%s.%s" %(hdr['name'], hdr['version'], hdr['release'], hdr['arch'])
160     po = txmbrs[0].po
161    
162     repo = self.repos.getRepo(po.repoid)
163    
164     pkgStr = "%s-%s-%s.%s" % (po.name, po.version, po.release, po.arch)
165     s = to_unicode(_("<b>Installing %(pkgStr)s</b> (%(size)s)\n")) \
166     % {'pkgStr': pkgStr, 'size': size_string(hdr['size'])}
167     summary = to_unicode(gettext.ldgettext("redhat-dist", hdr['summary'] or ""))
168     s += summary.strip()
169     self.progress.set_label(s)
170    
171     self.instLog.write(self.modeText % str(pkgStr))
172    
173     self.instLog.flush()
174     self.openfile = None
175    
176     trynumber = 0
177     while self.openfile is None:
178     trynumber += 1
179     try:
180     # checkfunc gets passed to yum's use of URLGrabber which
181     # then calls it with the file being fetched. verifyPkg
182     # makes sure the checksum matches the one in the metadata.
183     #
184     # From the URLGrab documents:
185     # checkfunc=(function, ('arg1', 2), {'kwarg': 3})
186     # results in a callback like:
187     # function(obj, 'arg1', 2, kwarg=3)
188     # obj.filename = '/tmp/stuff'
189     # obj.url = 'http://foo.com/stuff'
190     checkfunc = (self.ayum.verifyPkg, (po, 1), {})
191     fn = repo.getPackage(po, checkfunc=checkfunc)
192    
193     f = open(fn, 'r')
194     self.openfile = f
195     except yum.Errors.NoMoreMirrorsRepoError:
196     self.ayum._handleFailure(po, trynumber)
197     except IOError:
198     self.ayum._handleFailure(po, trynumber)
199     except URLGrabError as e:
200     log.error("URLGrabError: %s" % (e,))
201     self.ayum._handleFailure(po, trynumber)
202     except yum.Errors.RepoError, e:
203     continue
204     self.inProgressPo = po
205    
206     return self.openfile.fileno()
207    
208     elif what == rpm.RPMCALLBACK_INST_CLOSE_FILE:
209     if self.initWindow:
210     self.initWindow.pop()
211     self.initWindow = None
212    
213     (hdr, rpmloc) = h
214    
215     fn = self.openfile.name
216     self.openfile.close()
217     self.openfile = None
218    
219     if os.path.dirname(fn).startswith("%s/var/cache/yum/" % self.rootPath):
220     try:
221     os.unlink(fn)
222     except OSError as e:
223     log.debug("unable to remove file %s" %(e.strerror,))
224    
225     self.donepkgs += 1
226     self.doneSize += self.inProgressPo.returnSimple("installedsize") / 1024.0
227     self.doneFiles += len(hdr[rpm.RPMTAG_BASENAMES])
228    
229     if self.donepkgs <= self.numpkgs:
230     self.progress.set_text(P_("Packages completed: "
231     "%(donepkgs)d of %(numpkgs)d",
232     "Packages completed: "
233     "%(donepkgs)d of %(numpkgs)d",
234     self.numpkgs)
235     % {'donepkgs': self.donepkgs,
236     'numpkgs': self.numpkgs})
237     if self.totalSize > 0:
238     self.progress.set_fraction(float(self.doneSize / self.totalSize))
239     else:
240     self.progress.set_fraction(0.0)
241     self.progress.processEvents()
242    
243     self.inProgressPo = None
244    
245     elif what in (rpm.RPMCALLBACK_UNINST_START,
246     rpm.RPMCALLBACK_UNINST_STOP):
247     if self.initWindow is None:
248     self.initWindow = self.pulseWindow(_("Finishing upgrade"),
249     _("Finishing upgrade process. This may take a little while."),
250     0, pulse=True)
251     else:
252     self.initWindow.pulse()
253    
254     elif what in (rpm.RPMCALLBACK_CPIO_ERROR,
255     rpm.RPMCALLBACK_UNPACK_ERROR,
256     rpm.RPMCALLBACK_SCRIPT_ERROR):
257     if not isinstance(h, types.TupleType):
258     h = (h, None)
259    
260     (hdr, rpmloc) = h
261    
262     # Script errors store whether or not they're fatal in "total". So,
263     # we should only error out for fatal script errors or the cpio and
264     # unpack problems.
265     if what != rpm.RPMCALLBACK_SCRIPT_ERROR or total:
266     self.messageWindow(_("Error Installing Package"),
267     _("A fatal error occurred when installing the %s "
268     "package. This could indicate errors when reading "
269     "the installation media. Installation cannot "
270     "continue.") % hdr['name'],
271     type="custom", custom_icon="error",
272     custom_buttons=[_("_Exit installer")])
273     sys.exit(1)
274    
275     if self.initWindow is None:
276     self.progress.processEvents()
277    
278     class AnacondaYumRepo(YumRepository):
279     def __init__(self, *args, **kwargs):
280     YumRepository.__init__(self, *args, **kwargs)
281     self.enablegroups = True
282     self.sslverify = True
283     self._anacondaBaseURLs = []
284     self.proxy_url = None
285    
286     def needsNetwork(self):
287     def _isURL(s):
288     return s.startswith("http") or s.startswith("ftp")
289    
290     if len(self.baseurl) > 0:
291     return len(filter(lambda s: _isURL(s), self.baseurl)) > 0
292     elif self.mirrorlist:
293     return _isURL(self.mirrorlist)
294     else:
295     return False
296    
297     def dirCleanup(self, upgrade=False):
298     cachedir = self.getAttribute('cachedir')
299    
300     if os.path.isdir(cachedir):
301     if upgrade:
302     log.debug("Removing contents of %s" % (cachedir))
303     for f in filter(os.path.isfile, glob.glob("%s/*" % (cachedir))):
304     try:
305     os.unlink(f)
306     except Exception, e:
307     log.debug("error %s removing: %s" %(e,f))
308     elif not self.needsNetwork() or self.name == "Installation Repo" or self.id.startswith("anaconda-"):
309     log.debug("Removing cachedir: %s" % (cachedir))
310     shutil.rmtree(cachedir)
311     else:
312     log.debug("Removing headers and packages from %s" % (cachedir))
313     if os.path.exists("%s/headers" % cachedir):
314     shutil.rmtree("%s/headers" % cachedir)
315     if os.path.exists("%s/packages" % cachedir):
316     shutil.rmtree("%s/packages" % cachedir)
317    
318     # needed to store nfs: repo url that yum doesn't know
319     def _getAnacondaBaseURLs(self):
320     return self._anacondaBaseURLs or self.baseurl or [self.mirrorlist]
321    
322     def _setAnacondaBaseURLs(self, value):
323     self._anacondaBaseURLs = value
324    
325     anacondaBaseURLs = property(_getAnacondaBaseURLs, _setAnacondaBaseURLs,
326     doc="Extends AnacondaYum.baseurl to store non-yum urls:")
327    
328     class YumSorter(yum.YumBase):
329     def _transactionDataFactory(self):
330     return SplitMediaTransactionData()
331    
332     class AnacondaYum(YumSorter):
333     def __init__(self, anaconda):
334     YumSorter.__init__(self)
335     self.anaconda = anaconda
336     self._timestamp = None
337    
338     self.repoIDcounter = itertools.count()
339    
340     # Only needed for hard drive and nfsiso installs.
341     self._discImages = {}
342     self.isodir = None
343    
344     # Only needed for media installs.
345     self.currentMedia = None
346     self.mediagrabber = None
347    
348     # Where is the source media mounted? This is the directory
349     # where Packages/ is located.
350     self.tree = "/mnt/source"
351    
352     self.macros = {}
353    
354     if flags.selinux:
355     for directory in ("/tmp/updates",
356     "/etc/selinux/targeted/contexts/files",
357     "/etc/security/selinux/src/policy/file_contexts",
358     "/etc/security/selinux"):
359     fn = "%s/file_contexts" %(directory,)
360     if os.access(fn, os.R_OK):
361     break
362     self.macros["__file_context_path"] = fn
363     else:
364     self.macros["__file_context_path"] = "%{nil}"
365    
366     self.updates = []
367     self.localPackages = []
368    
369     # Parse proxy values from anaconda
370     self.proxy = None
371     self.proxy_url = None
372     self.proxy_username = None
373     self.proxy_password = None
374     if self.anaconda.proxy:
375     self.setProxy(self.anaconda, self)
376    
377     def setup(self):
378     # yum doesn't understand all our method URLs, so use this for all
379     # except FTP and HTTP installs.
380     self._baseRepoURL = "file://%s" % self.tree
381    
382     while True:
383     try:
384     self.configBaseURL()
385     break
386     except SystemError as exception:
387     self.anaconda.methodstr = self.anaconda.intf.methodstrRepoWindow(self.anaconda.methodstr or "cdrom:",
388     exception)
389    
390     self.doConfigSetup(root=self.anaconda.rootPath)
391     if not self.anaconda.id.getUpgrade():
392     self.conf.installonlypkgs = []
393    
394     def _switchCD(self, discnum):
395     if os.access("%s/.discinfo" % self.tree, os.R_OK):
396     f = open("%s/.discinfo" % self.tree)
397     self._timestamp = f.readline().strip()
398     f.close()
399    
400     dev = self.anaconda.id.storage.devicetree.getDeviceByName(self.anaconda.mediaDevice)
401     dev.format.mountpoint = self.tree
402    
403     # If self.currentMedia is None, then there shouldn't be anything
404     # mounted. Before going further, see if the correct disc is already
405     # in the drive. This saves a useless eject and insert if the user
406     # has for some reason already put the disc in the drive.
407     if self.currentMedia is None:
408     try:
409     dev.format.mount()
410    
411     if verifyMedia(self.tree, discnum, None):
412     self.currentMedia = discnum
413     return
414    
415     dev.format.unmount()
416     except:
417     pass
418     else:
419     unmountCD(dev, self.anaconda.intf.messageWindow)
420     self.currentMedia = None
421    
422     dev.eject()
423    
424     while True:
425     if self.anaconda.intf:
426     self.anaconda.intf.beep()
427    
428     self.anaconda.intf.messageWindow(_("Change Disc"),
429     _("Please insert %(productName)s disc %(discnum)d to continue.")
430     % {'productName': productName, 'discnum': discnum})
431    
432     try:
433     dev.format.mount()
434    
435     if verifyMedia(self.tree, discnum, self._timestamp):
436     self.currentMedia = discnum
437     break
438    
439     self.anaconda.intf.messageWindow(_("Wrong Disc"),
440     _("That's not the correct %s disc.")
441     % (productName,))
442    
443     dev.format.unmount()
444     dev.eject()
445     except:
446     self.anaconda.intf.messageWindow(_("Error"),
447     _("Unable to access the disc."))
448    
449     def _switchImage(self, discnum):
450     umountImage(self.tree, self.currentMedia)
451     self.currentMedia = None
452    
453     # mountDirectory checks before doing anything, so it's safe to
454     # call this repeatedly.
455     mountDirectory(self.anaconda.methodstr,
456     self.anaconda.intf.messageWindow)
457    
458     self._discImages = mountImage(self.isodir, self.tree, discnum,
459     self.anaconda.intf.messageWindow,
460     discImages=self._discImages)
461     self.currentMedia = discnum
462    
463     def configBaseURL(self):
464     # We only have a methodstr if method= or repo= was passed to
465     # anaconda. No source for this base repo (the CD media, NFS,
466     # whatever) is mounted yet since loader only mounts the source
467     # for the stage2 image. We need to set up the source mount
468     # now.
469     if flags.cmdline.has_key("preupgrade"):
470     path = "/var/cache/yum/preupgrade"
471     self.anaconda.methodstr = "hd::%s" % path
472     self._baseRepoURL = "file:///mnt/sysimage/%s" % path
473     elif self.anaconda.methodstr:
474     m = self.anaconda.methodstr
475    
476     if m.startswith("hd:"):
477     if m.count(":") == 2:
478     (device, path) = m[3:].split(":")
479     else:
480     (device, fstype, path) = m[3:].split(":")
481    
482     self.isodir = "/mnt/isodir/%s" % path
483    
484     # This takes care of mounting /mnt/isodir first.
485     self._switchImage(1)
486     self.mediagrabber = self.mediaHandler
487     elif m.startswith("nfsiso:"):
488     self.isodir = "/mnt/isodir"
489    
490     # Calling _switchImage takes care of mounting /mnt/isodir first.
491     if not network.hasActiveNetDev():
492     if not self.anaconda.intf.enableNetwork():
493     self._baseRepoURL = None
494     return
495    
496     urlgrabber.grabber.reset_curl_obj()
497    
498     self._switchImage(1)
499     self.mediagrabber = self.mediaHandler
500     elif m.startswith("http") or m.startswith("ftp:"):
501     self._baseRepoURL = m
502     elif m.startswith("nfs:"):
503     if not network.hasActiveNetDev():
504     if not self.anaconda.intf.enableNetwork():
505     self._baseRepoURL = None
506    
507     urlgrabber.grabber.reset_curl_obj()
508    
509     (opts, server, path) = iutil.parseNfsUrl(m)
510     isys.mount(server+":"+path, self.tree, "nfs", options=opts)
511    
512     # This really should be fixed in loader instead but for now see
513     # if there's images and if so go with this being an NFSISO
514     # install instead.
515     images = findIsoImages(self.tree, self.anaconda.intf.messageWindow)
516     if images != {}:
517     isys.umount(self.tree, removeDir=False)
518     self.anaconda.methodstr = "nfsiso:%s" % m[4:]
519     self.configBaseURL()
520     return
521     elif m.startswith("cdrom:"):
522     self._switchCD(1)
523     self.mediagrabber = self.mediaHandler
524     self._baseRepoURL = "file://%s" % self.tree
525     else:
526     # No methodstr was given. In order to find an installation source,
527     # we should first check to see if there's a CD/DVD with packages
528     # on it, and then default to the mirrorlist URL. The user can
529     # always change the repo with the repo editor later.
530     cdr = scanForMedia(self.tree, self.anaconda.id.storage)
531     if cdr:
532     self.mediagrabber = self.mediaHandler
533     self.anaconda.mediaDevice = cdr
534     self.currentMedia = 1
535     log.info("found installation media on %s" % cdr)
536     else:
537     # No CD with media on it and no repo=/method= parameter, so
538     # default to using whatever's enabled in /etc/yum.repos.d/
539     self._baseRepoURL = None
540    
541     def configBaseRepo(self, root='/'):
542     # Create the "base" repo object, assuming there is one. Otherwise we
543     # just skip all this and use the defaults from /etc/yum.repos.d.
544     if not self._baseRepoURL:
545     return
546    
547     # add default repos
548     anacondabaseurl = (self.anaconda.methodstr or
549     "cdrom:%s" % (self.anaconda.mediaDevice))
550     anacondabasepaths = self.anaconda.id.instClass.getPackagePaths(anacondabaseurl)
551     for (name, uri) in self.anaconda.id.instClass.getPackagePaths(self._baseRepoURL).items():
552     rid = name.replace(" ", "")
553    
554     repo = AnacondaYumRepo("anaconda-%s-%s" % (rid, productStamp))
555     repo.baseurl = uri
556     repo.anacondaBaseURLs = anacondabasepaths[name]
557    
558     repo.name = name
559     repo.cost = 100
560    
561     if self.anaconda.mediaDevice or self.isodir:
562     repo.mediaid = getMediaId(self.tree)
563     log.info("set mediaid of repo %s to: %s" % (rid, repo.mediaid))
564    
565     if self.anaconda.proxy:
566     self.setProxy(self.anaconda, repo)
567    
568     if flags.noverifyssl:
569     repo.sslverify = False
570    
571     repo.enable()
572     self.repos.add(repo)
573    
574     def mediaHandler(self, *args, **kwargs):
575     mediaid = kwargs["mediaid"]
576     discnum = kwargs["discnum"]
577     relative = kwargs["relative"]
578    
579     # The package exists on media other than what's mounted right now.
580     if discnum != self.currentMedia:
581     log.info("switching from media #%s to #%s for %s" %
582     (self.currentMedia, discnum, relative))
583    
584     # Unmount any currently mounted ISO images and mount the one
585     # containing the requested packages.
586     if self.isodir:
587     self._switchImage(discnum)
588     else:
589     self._switchCD(discnum)
590    
591     ug = URLGrabber(checkfunc=kwargs["checkfunc"])
592     ug.urlgrab("%s/%s" % (self.tree, kwargs["relative"]), kwargs["local"],
593     text=kwargs["text"], range=kwargs["range"], copy_local=1)
594     return kwargs["local"]
595    
596     # XXX: This is straight out of yum, but we need to override it here in
597     # order to use our own repo class.
598     def readRepoConfig(self, parser, section):
599     '''Parse an INI file section for a repository.
600    
601     @param parser: ConfParser or similar to read INI file values from.
602     @param section: INI file section to read.
603     @return: YumRepository instance.
604     '''
605     repo = AnacondaYumRepo(section)
606     repo.populate(parser, section, self.conf)
607    
608     # Ensure that the repo name is set
609     if not repo.name:
610     repo.name = section
611     self.logger.error(_('Repository %r is missing name in configuration, '
612     'using id') % section)
613    
614     # Set attributes not from the config file
615     repo.yumvar.update(self.conf.yumvar)
616     repo.cfg = parser
617    
618     if "-source" in repo.id or "-debuginfo" in repo.id:
619     name = repo.name
620     del(repo)
621     raise RepoError, "Repo %s contains -source or -debuginfo, excluding" % name
622    
623     # this is a little hard-coded, but it's effective
624     if productIsFinal and ("rawhide" in repo.id or "development" in repo.id):
625     name = repo.name
626     del(repo)
627     raise RepoError, "Excluding devel repo %s for non-devel anaconda" % name
628    
629     if not productIsFinal and not repo.enabled:
630     name = repo.name
631     del(repo)
632     raise RepoError, "Excluding disabled repo %s for prerelease" % name
633    
634     # If repo=/method= was passed in, we want to default these extra
635     # repos to off.
636     if self._baseRepoURL:
637     repo.enabled = False
638    
639     return repo
640    
641     def setProxy(self, src, dest):
642     """
643     Set the proxy settings from a string in src.proxy
644     If the string includes un/pw use those, otherwise set the un/pw from
645     src.proxyUsername and src.proxyPassword
646    
647     dest has dest.proxy set to the host and port (no un/pw)
648     dest.proxy_username and dest.proxy_password are set if present in src
649     """
650     # This is the same pattern as from loader/urls.c:splitProxyParam
651     # except that the POSIX classes have been replaced with character
652     # ranges
653     # NOTE: If this changes, update tests/regex/proxy.py
654     #
655     # proxy=[protocol://][username[:password]@]host[:port][path]
656     pattern = re.compile("([A-Za-z]+://)?(([A-Za-z0-9]+)(:[^:@]+)?@)?([^:/]+)(:[0-9]+)?(/.*)?")
657    
658     m = pattern.match(src.proxy)
659    
660     if m and m.group(3):
661     dest.proxy_username = m.group(3)
662     elif getattr(src, "proxyUsername", None):
663     dest.proxy_username = src.proxyUsername
664    
665     if m and m.group(4):
666     # Skip the leading colon.
667     dest.proxy_password = m.group(4)[1:]
668     elif getattr(src, "proxyPassword", None):
669     dest.proxy_password = src.proxyPassword
670    
671     if dest.proxy_username or dest.proxy_password:
672     proxy_auth = "%s:%s@" % (dest.proxy_username or '',
673     dest.proxy_password or '')
674     else:
675     proxy_auth = ""
676    
677     if m and m.group(5):
678     # If both a host and port was found, just paste them
679     # together using the colon at the beginning of the port
680     # match as a separator. Otherwise, just use the host.
681     if m.group(6):
682     proxy = m.group(5) + m.group(6)
683     else:
684     proxy = m.group(5)
685    
686     # yum also requires a protocol. If none was given,
687     # default to http.
688     if m.group(1):
689     dest.proxy_url = m.group(1) + proxy_auth + proxy
690     proxy = m.group(1) + proxy
691     else:
692     dest.proxy_url = "http://" + proxy_auth + proxy
693     proxy = "http://" + proxy
694    
695     # Set the repo proxy. NOTE: yum immediately parses this and
696     # raises an error if it isn't correct
697     dest.proxy = proxy
698    
699     def _getAddons(self, repo):
700     """
701     Check the baseurl or mirrorlist for a repository, see if it has any
702     valid addon repos and if so, return a list of (repo name, repo URL).
703     """
704     baseurl = repo.mirrorlist or repo.baseurl[0]
705     retval = []
706     c = ConfigParser()
707    
708     # If there's no .treeinfo for this repo, don't bother looking for addons.
709     treeinfo = self._getTreeinfo(baseurl, repo.proxy_url, repo.sslverify)
710     if not treeinfo:
711     return retval
712    
713     # We need to know which variant is being installed so we know what addons
714     # are valid options.
715     try:
716     ConfigParser.read(c, treeinfo)
717     variant = c.get("general", "variant")
718     except:
719     return retval
720    
721     section = "variant-%s" % variant
722     if c.has_section(section) and c.has_option(section, "addons"):
723     validAddons = c.get(section, "addons").split(",")
724     else:
725     return retval
726    
727     for addon in validAddons:
728     addonSection = "addon-%s" % addon
729     if not c.has_section(addonSection) or not c.has_option(addonSection, "repository"):
730     continue
731    
732     url = "%s/%s" % (baseurl, c.get(addonSection, "repository"))
733     retval.append((addon, c.get(addonSection, "name"), url))
734    
735     return retval
736    
737     def _getTreeinfo(self, baseurl, proxy_url, sslverify):
738     """
739     Try to get .treeinfo file from baseurl, optionally using proxy_url
740     Saves the file into /tmp/.treeinfo
741     """
742     if not baseurl:
743     return None
744     if baseurl.startswith("http") or baseurl.startswith("ftp"):
745     if not network.hasActiveNetDev():
746     if not self.anaconda.intf.enableNetwork():
747     log.error("Error downloading %s/.treeinfo: network enablement failed" % (baseurl))
748     return None
749     urlgrabber.grabber.reset_curl_obj()
750    
751     ug = URLGrabber()
752     ugopts = {
753     "ssl_verify_peer" : sslverify,
754     "ssl_verify_host" : sslverify
755     }
756    
757     if proxy_url and proxy_url.startswith("http"):
758     proxies = { 'http' : proxy_url,
759     'https' : proxy_url }
760     elif proxy_url and proxy_url.startswith("ftp"):
761     proxies = { 'ftp' : proxy_url }
762     else:
763     proxies = {}
764    
765     try:
766     ug.urlgrab("%s/.treeinfo" % baseurl, "/tmp/.treeinfo",
767     copy_local=1, proxies=proxies, **ugopts)
768     except Exception as e:
769     try:
770     ug.urlgrab("%s/treeinfo" % baseurl, "/tmp/.treeinfo",
771     copy_local=1, proxies=proxies)
772     except Exception as e:
773     log.error("Error downloading treeinfo file: %s" % e)
774     return None
775    
776     return "/tmp/.treeinfo"
777    
778     def _getReleasever(self):
779     """
780     We need to make sure $releasever gets set up before .repo files are
781     read. Since there's no redhat-release package in /mnt/sysimage (and
782     won't be for quite a while), we need to do our own substutition.
783     """
784     c = ConfigParser()
785    
786     treeinfo = self._getTreeinfo(self._baseRepoURL,
787     self.proxy_url,
788     not flags.noverifyssl)
789     if not treeinfo:
790     return productVersion
791    
792     ConfigParser.read(c, treeinfo)
793     try:
794     return c.get("general", "version")
795     except:
796     return productVersion
797    
798     # Override this method so yum doesn't nuke our existing logging config.
799     def doLoggingSetup(self, *args, **kwargs):
800    
801     import yum.logginglevels
802    
803     file_handler = logging.FileHandler("/tmp/yum.log")
804     file_formatter = logging.Formatter("[%(asctime)s] %(levelname)-8s: %(message)s")
805     file_handler.setFormatter(file_formatter)
806    
807     tty3_handler = logging.FileHandler("/dev/tty3")
808     tty3_formatter = logging.Formatter("%(asctime)s %(levelname)-8s: %(name)s: %(message)s", "%H:%M:%S")
809     tty3_handler.setFormatter(tty3_formatter)
810    
811     verbose = logging.getLogger("yum.verbose")
812     verbose.setLevel(logging.DEBUG)
813     verbose.propagate = False
814     verbose.addHandler(file_handler)
815    
816     logger = logging.getLogger("yum")
817     logger.propagate = False
818     logger.setLevel(yum.logginglevels.INFO_2)
819     logger.addHandler(file_handler)
820     anaconda_log.autoSetLevel(tty3_handler, True)
821     tty3_handler.setLevel(anaconda_log.logger.loglevel)
822     logger.addHandler(tty3_handler)
823    
824     # XXX filelogger is set in setFileLog - do we or user want it?
825     filelogger = logging.getLogger("yum.filelogging")
826     filelogger.setLevel(logging.INFO)
827     filelogger.propagate = False
828    
829    
830     def doConfigSetup(self, fn='/tmp/anaconda-yum.conf', root='/'):
831     if hasattr(self, "preconf"):
832     self.preconf.fn = fn
833     self.preconf.root = root
834     self.preconf.releasever = self._getReleasever()
835     self.preconf.enabled_plugins = ["whiteout", "blacklist", "pidplugin"]
836     YumSorter._getConfig(self)
837     else:
838     YumSorter._getConfig(self, fn=fn, root=root,
839     enabled_plugins=["whiteout", "blacklist", "pidplugin"])
840     self.configBaseRepo(root=root)
841    
842     extraRepos = []
843    
844     ddArch = os.uname()[4]
845    
846     #Add the Driver disc repos to Yum
847     for d in glob.glob(DD_RPMS):
848     dirname = os.path.basename(d)
849     rid = "anaconda-%s" % dirname
850    
851     repo = AnacondaYumRepo(rid)
852     repo.baseurl = [ "file://%s" % d ]
853     repo.name = "Driver Disk %s" % dirname.split("-")[1]
854     repo.enable()
855     extraRepos.append(repo)
856    
857     if self.anaconda.isKickstart:
858     for ksrepo in self.anaconda.id.ksdata.repo.repoList:
859     anacondaBaseURLs = [ksrepo.baseurl]
860    
861     # yum doesn't understand nfs:// and doesn't want to. We need
862     # to first do the mount, then translate it into a file:// that
863     # yum does understand.
864     # "nfs:" and "nfs://" prefixes are accepted in ks repo --baseurl
865     if ksrepo.baseurl and ksrepo.baseurl.startswith("nfs:"):
866     dest = tempfile.mkdtemp("", ksrepo.name.replace(" ", ""), "/mnt")
867    
868     # handle "nfs://" prefix
869     if ksrepo.baseurl[4:6] == '//':
870     ksrepo.baseurl = ksrepo.baseurl.replace('//', '', 1)
871     anacondaBaseURLs = [ksrepo.baseurl]
872     try:
873     isys.mount(ksrepo.baseurl[4:], dest, "nfs")
874     except Exception as e:
875     log.error("error mounting NFS repo: %s" % e)
876    
877     ksrepo.baseurl = "file://%s" % dest
878    
879     repo = AnacondaYumRepo(ksrepo.name)
880     repo.mirrorlist = ksrepo.mirrorlist
881     repo.name = ksrepo.name
882    
883     if not ksrepo.baseurl:
884     repo.baseurl = []
885     else:
886     repo.baseurl = [ ksrepo.baseurl ]
887     repo.anacondaBaseURLs = anacondaBaseURLs
888    
889     if ksrepo.cost:
890     repo.cost = ksrepo.cost
891    
892     if ksrepo.excludepkgs:
893     repo.exclude = ksrepo.excludepkgs
894    
895     if ksrepo.includepkgs:
896     repo.includepkgs = ksrepo.includepkgs
897    
898     if ksrepo.noverifyssl:
899     repo.sslverify = False
900    
901     if ksrepo.proxy:
902     self.setProxy(ksrepo, repo)
903     elif self.anaconda.proxy:
904     log.debug("%s will use the global proxy configuration", repo.name)
905     self.setProxy(self.anaconda, repo)
906    
907     repo.enable()
908     extraRepos.append(repo)
909    
910     initialRepos = self.repos.repos.values() + extraRepos
911     for repo in initialRepos:
912     addons = self._getAddons(repo)
913     for addon in addons:
914     addonRepo = AnacondaYumRepo(addon[0])
915     addonRepo.name = addon[1]
916     addonRepo.baseurl = [ addon[2] ]
917    
918     if self.anaconda.proxy:
919     self.setProxy(self.anaconda, addonRepo)
920    
921     extraRepos.append(addonRepo)
922    
923     for repo in extraRepos:
924     try:
925     self.repos.add(repo)
926     log.info("added repository %s with URL %s" % (repo.name, repo.mirrorlist or repo.baseurl[0]))
927     except:
928     log.warning("ignoring duplicate repository %s with URL %s" % (repo.name, repo.mirrorlist or repo.baseurl[0]))
929    
930     self.repos.setCacheDir(self.conf.cachedir)
931    
932     # When upgrading cleanup the yum cache and enable the addons
933     # This has to be called after setCacheDir
934     if self.anaconda.id.getUpgrade():
935     for repo in extraRepos:
936     repo.dirCleanup(upgrade=True)
937     repo.enable()
938     log.info("enabled %s for upgrade" % (repo.name))
939    
940     if os.path.exists("%s/boot/upgrade/install.img" % self.anaconda.rootPath):
941     log.info("REMOVING stage2 image from %s /boot/upgrade" % self.anaconda.rootPath )
942     try:
943     os.unlink("%s/boot/upgrade/install.img" % self.anaconda.rootPath)
944     except:
945     log.warning("failed to clean /boot/upgrade")
946    
947     def downloadHeader(self, po):
948     trynumber = 0
949     while True:
950     # retrying version of download header
951     trynumber += 1
952     try:
953     YumSorter.downloadHeader(self, po)
954     break
955     except yum.Errors.NoMoreMirrorsRepoError:
956     self._handleFailure(po, trynumber)
957     except IOError:
958     self._handleFailure(po, trynumber)
959     except yum.Errors.RepoError, e:
960     continue
961    
962     def _handleFailure(self, package, trynumber=YUM_DOWNLOAD_RETRIES):
963     if not self.isodir and self.currentMedia:
964     buttons = [_("Re_boot"), _("_Eject")]
965     else:
966     buttons = [_("Re_boot"), _("_Retry")]
967    
968     pkgFile = to_unicode(os.path.basename(package.remote_path))
969    
970     if package.repo.needsNetwork() and not network.hasActiveNetDev():
971     if not self.anaconda.intf.enableNetwork():
972     return
973    
974     urlgrabber.grabber.reset_curl_obj()
975    
976     # only show the retry window after 3 tries
977     if trynumber < YUM_DOWNLOAD_RETRIES:
978     log.warning('package download failure, retrying automatically')
979     time.sleep(YUM_DOWNLOAD_DELAY * trynumber)
980     rc = 1
981     else:
982     rc = self.anaconda.intf.messageWindow(_("Error"),
983     _("The file %s cannot be opened. This is due to a missing "
984     "file, a corrupt package or corrupt media. Please "
985     "verify your installation source.\n\n"
986     "If you exit, your system will be left in an inconsistent "
987     "state that will likely require reinstallation.\n\n") %
988     (pkgFile,),
989     type="custom", custom_icon="error",
990     custom_buttons=buttons)
991    
992     if rc == 0:
993     sys.exit(0)
994     else:
995     if os.path.exists(package.localPkg()):
996     os.unlink(package.localPkg())
997    
998     if not self.isodir and self.currentMedia:
999     self._switchCD(self.currentMedia)
1000     else:
1001     return
1002    
1003     def mirrorFailureCB (self, obj, *args, **kwargs):
1004     # This gets called when a mirror fails, but it cannot know whether
1005     # or not there are other mirrors left to try, since it cannot know
1006     # which mirror we were on when we started this particular download.
1007     # Whenever we have run out of mirrors the grabber's get/open/retrieve
1008     # method will raise a URLGrabError exception with errno 256.
1009     grab = self.repos.getRepo(kwargs["repo"]).grab
1010     log.warning("Failed to get %s from mirror %d/%d, "
1011     "or downloaded file is corrupt" % (obj.url, grab._next + 1,
1012     len(grab.mirrors)))
1013    
1014     if self.currentMedia:
1015     dev = self.anaconda.id.storage.devicetree.getDeviceByName(self.anaconda.mediaDevice)
1016     dev.format.mountpoint = self.tree
1017     unmountCD(dev, self.anaconda.intf.messageWindow)
1018     self.currentMedia = None
1019    
1020     def urlgrabberFailureCB (self, obj, *args, **kwargs):
1021     if hasattr(obj, "exception"):
1022     log.warning("Try %s/%s for %s failed: %s" % (obj.tries, obj.retry, obj.url, obj.exception))
1023     else:
1024     log.warning("Try %s/%s for %s failed" % (obj.tries, obj.retry, obj.url))
1025    
1026     if obj.tries == obj.retry:
1027     return
1028    
1029     delay = 0.25*(2**(obj.tries-1))
1030     if delay > 1:
1031     w = self.anaconda.intf.waitWindow(_("Retrying"), _("Retrying download."))
1032     time.sleep(delay)
1033     w.pop()
1034     else:
1035     time.sleep(delay)
1036    
1037     def getDownloadPkgs(self):
1038     downloadpkgs = []
1039     totalSize = 0
1040     totalFiles = 0
1041     for txmbr in self.tsInfo.getMembersWithState(output_states=TS_INSTALL_STATES):
1042     if txmbr.po:
1043     totalSize += int(txmbr.po.returnSimple("installedsize")) / 1024
1044     for filetype in txmbr.po.returnFileTypes():
1045     totalFiles += len(txmbr.po.returnFileEntries(ftype=filetype))
1046     downloadpkgs.append(txmbr.po)
1047    
1048     return (downloadpkgs, totalSize, totalFiles)
1049    
1050     def setColor(self):
1051     if rpmUtils.arch.isMultiLibArch():
1052     self.ts.ts.setColor(3)
1053    
1054     def run(self, instLog, cb, intf, id):
1055     def mediasort(a, b):
1056     # sort so that first CD comes first, etc. -99 is a magic number
1057     # to tell us that the cd should be last
1058     if a == -99:
1059     return 1
1060     elif b == -99:
1061     return -1
1062     if a < b:
1063     return -1
1064     elif a > b:
1065     return 1
1066     return 0
1067    
1068     self.initActionTs()
1069     if id.getUpgrade():
1070     self.ts.ts.setProbFilter(~rpm.RPMPROB_FILTER_DISKSPACE)
1071     self.setColor()
1072    
1073     # If we don't have any required media assume single disc
1074     if self.tsInfo.reqmedia == {}:
1075     self.tsInfo.reqmedia[0] = None
1076     mkeys = self.tsInfo.reqmedia.keys()
1077     mkeys.sort(mediasort)
1078    
1079     if os.path.ismount("/mnt/stage2"):
1080     isys.umount("/mnt/stage2")
1081    
1082     for i in mkeys:
1083     self.tsInfo.curmedia = i
1084     if i > 0:
1085     pkgtup = self.tsInfo.reqmedia[i][0]
1086    
1087     try:
1088     self.dsCallback = DownloadHeaderProgress(intf, self)
1089     self.populateTs(keepold=0)
1090     self.dsCallback.pop()
1091     self.dsCallback = None
1092     except RepoError, e:
1093     msg = _("There was an error running your transaction for "
1094     "the following reason: %s\n") % str(e)
1095    
1096     if self.anaconda.id.upgrade or self.anaconda.isKickstart:
1097     rc = intf.messageWindow(_("Error"), msg, type="custom",
1098     custom_icon="error",
1099     custom_buttons=[_("_Exit installer")])
1100     sys.exit(1)
1101     else:
1102     rc = intf.messageWindow(_("Error"), msg,
1103     type="custom", custom_icon="error",
1104     custom_buttons=[_("_Back"), _("_Exit installer")])
1105    
1106     if rc == 1:
1107     sys.exit(1)
1108     else:
1109     self.tsInfo.curmedia = None
1110     return DISPATCH_BACK
1111    
1112     self.ts.check()
1113     self.ts.order()
1114    
1115     self.anaconda.id.bootloader.trusted_boot = self.isPackageInstalled(name="tboot") and not iutil.inXen()
1116    
1117     if self._run(instLog, cb, intf) == DISPATCH_BACK:
1118     self.tsInfo.curmedia = None
1119     return DISPATCH_BACK
1120    
1121     self.ts.close()
1122    
1123     def _run(self, instLog, cb, intf):
1124     # set log fd. FIXME: this is ugly. see changelog entry from 2005-09-13
1125     self.ts.ts.scriptFd = instLog.fileno()
1126     rpm.setLogFile(instLog)
1127    
1128     uniqueProbs = {}
1129     spaceneeded = {}
1130     spaceprob = ""
1131     fileConflicts = []
1132     fileprob = ""
1133    
1134     try:
1135     self.runTransaction(cb=cb)
1136     except YumBaseError, probs:
1137     # FIXME: we need to actually look at these problems...
1138     probTypes = { rpm.RPMPROB_NEW_FILE_CONFLICT : _('file conflicts'),
1139     rpm.RPMPROB_FILE_CONFLICT : _('file conflicts'),
1140     rpm.RPMPROB_OLDPACKAGE: _('older package(s)'),
1141     rpm.RPMPROB_DISKSPACE: _('insufficient disk space'),
1142     rpm.RPMPROB_DISKNODES: _('insufficient disk inodes'),
1143     rpm.RPMPROB_CONFLICT: _('package conflicts'),
1144     rpm.RPMPROB_PKG_INSTALLED: _('package already installed'),
1145     rpm.RPMPROB_REQUIRES: _('required package'),
1146     rpm.RPMPROB_BADARCH: _('package for incorrect arch'),
1147     rpm.RPMPROB_BADOS: _('package for incorrect os'),
1148     }
1149    
1150     for (descr, (ty, mount, need)) in probs.value: # FIXME: probs.value???
1151     log.error("%s: %s" %(probTypes[ty], descr))
1152     if not uniqueProbs.has_key(ty) and probTypes.has_key(ty):
1153     uniqueProbs[ty] = probTypes[ty]
1154    
1155     if ty == rpm.RPMPROB_DISKSPACE:
1156     spaceneeded[mount] = need
1157     elif ty in [rpm.RPMPROB_NEW_FILE_CONFLICT, rpm.RPMPROB_FILE_CONFLICT]:
1158     fileConflicts.append(descr)
1159    
1160     if spaceneeded:
1161     spaceprob = _("You need more space on the following "
1162     "file systems:\n")
1163    
1164     for (mount, need) in spaceneeded.items():
1165     log.info("(%s, %s)" %(mount, need))
1166    
1167     if mount.startswith("/mnt/sysimage/"):
1168     mount.replace("/mnt/sysimage", "")
1169     elif mount.startswith("/mnt/sysimage"):
1170     mount = "/" + mount.replace("/mnt/sysimage", "")
1171    
1172     spaceprob += "%d M on %s\n" % (need / (1024*1024), mount)
1173     elif fileConflicts:
1174     fileprob = _("There were file conflicts when checking the "
1175     "packages to be installed:\n%s\n") % ("\n".join(fileConflicts),)
1176    
1177     msg = _("There was an error running your transaction for "
1178     "the following reason(s): %s.\n") % ', '.join(uniqueProbs.values())
1179    
1180     spaceprob = to_unicode(spaceprob)
1181     fileprob = to_unicode(fileprob)
1182    
1183     if len(self.anaconda.backend.getRequiredMedia()) > 1 or \
1184     self.anaconda.id.upgrade or self.anaconda.isKickstart:
1185     intf.detailedMessageWindow(_("Error Running Transaction"),
1186     msg, spaceprob + "\n" + fileprob, type="custom",
1187     custom_icon="error", custom_buttons=[_("_Exit installer")])
1188     sys.exit(1)
1189     else:
1190     rc = intf.detailedMessageWindow(_("Error Running Transaction"),
1191     msg, spaceprob + "\n" + fileprob, type="custom",
1192     custom_icon="error",
1193     custom_buttons=[_("_Back"), _("_Exit installer")])
1194    
1195     if rc == 1:
1196     sys.exit(1)
1197     else:
1198     self._undoDepInstalls()
1199     return DISPATCH_BACK
1200    
1201     def doMacros(self):
1202     for (key, val) in self.macros.items():
1203     rpm.addMacro(key, val)
1204    
1205     def simpleDBInstalled(self, name, arch=None):
1206     # FIXME: doing this directly instead of using self.rpmdb.installed()
1207     # speeds things up by 400%
1208     mi = self.ts.ts.dbMatch('name', name)
1209     if mi.count() == 0:
1210     return False
1211     if arch is None:
1212     return True
1213     if arch in map(lambda h: h['arch'], mi):
1214     return True
1215     return False
1216    
1217     def isPackageInstalled(self, name = None, epoch = None, version = None,
1218     release = None, arch = None, po = None):
1219     # FIXME: this sucks. we should probably suck it into yum proper
1220     # but it'll need a bit of cleanup first.
1221     if po is not None:
1222     (name, epoch, version, release, arch) = po.returnNevraTuple()
1223    
1224     installed = False
1225     if name and not (epoch or version or release or arch):
1226     installed = self.simpleDBInstalled(name)
1227     elif self.rpmdb.installed(name = name, epoch = epoch, ver = version,
1228     rel = release, arch = arch):
1229     installed = True
1230    
1231     lst = self.tsInfo.matchNaevr(name = name, epoch = epoch,
1232     ver = version, rel = release,
1233     arch = arch)
1234     for txmbr in lst:
1235     if txmbr.output_state in TS_INSTALL_STATES:
1236     return True
1237     if installed and len(lst) > 0:
1238     # if we get here, then it was installed, but it's in the tsInfo
1239     # for an erase or obsoleted --> not going to be installed at end
1240     return False
1241     return installed
1242    
1243     def isGroupInstalled(self, grp):
1244     if grp.selected:
1245     return True
1246     elif grp.installed and not grp.toremove:
1247     return True
1248     return False
1249    
1250     def _pkgExists(self, pkg):
1251     """Whether or not a given package exists in our universe."""
1252     try:
1253     pkgs = self.pkgSack.returnNewestByName(pkg)
1254     return True
1255     except yum.Errors.PackageSackError:
1256     pass
1257     try:
1258     pkgs = self.rpmdb.returnNewestByName(pkg)
1259     return True
1260     except (IndexError, yum.Errors.PackageSackError):
1261     pass
1262     return False
1263    
1264     def _groupHasPackages(self, grp):
1265     # this checks to see if the given group has any packages available
1266     # (ie, already installed or in the sack of available packages)
1267     # so that we don't show empty groups. also, if there are mandatory
1268     # packages and we have none of them, don't show
1269     for pkg in grp.mandatory_packages.keys():
1270     if self._pkgExists(pkg):
1271     return True
1272     if len(grp.mandatory_packages) > 0:
1273     return False
1274     for pkg in grp.default_packages.keys() + grp.optional_packages.keys() + \
1275     grp.conditional_packages.keys():
1276     if self._pkgExists(pkg):
1277     return True
1278     return False
1279    
1280     class YumBackend(AnacondaBackend):
1281     def __init__ (self, anaconda):
1282     AnacondaBackend.__init__(self, anaconda)
1283     self.supportsPackageSelection = True
1284    
1285     buf = """
1286     [main]
1287     installroot=%s
1288     cachedir=/var/cache/yum
1289     keepcache=0
1290     logfile=/tmp/yum.log
1291     metadata_expire=0
1292     obsoletes=True
1293     pluginpath=/usr/lib/yum-plugins,/tmp/updates/yum-plugins
1294     pluginconfpath=/etc/yum/pluginconf.d,/tmp/updates/pluginconf.d
1295     plugins=1
1296     reposdir=/etc/anaconda.repos.d,/tmp/updates/anaconda.repos.d,/tmp/product/anaconda.repos.d
1297     debuglevel=6
1298     """ % (anaconda.rootPath)
1299    
1300     if anaconda.proxy:
1301     buf += "proxy=%s\n" % anaconda.proxy
1302    
1303     if anaconda.proxyUsername:
1304     buf += "proxy_username=%s\n" % anaconda.proxyUsername
1305    
1306     if anaconda.proxyPassword:
1307     buf += "proxy_password=%s\n" % anaconda.proxyPassword
1308    
1309     fd = open("/tmp/anaconda-yum.conf", "w")
1310     fd.write(buf)
1311     fd.close()
1312    
1313     def complete(self, anaconda):
1314     if not anaconda.mediaDevice and os.path.ismount(self.ayum.tree):
1315     isys.umount(self.ayum.tree)
1316    
1317     # clean up rpmdb locks so that kickstart %post scripts aren't
1318     # unhappy (#496961)
1319     iutil.resetRpmDb(anaconda.rootPath)
1320    
1321     def doBackendSetup(self, anaconda):
1322     if anaconda.dir == DISPATCH_BACK:
1323     return DISPATCH_BACK
1324    
1325     if anaconda.id.getUpgrade():
1326     # FIXME: make sure that the rpmdb doesn't have stale locks :/
1327     iutil.resetRpmDb(anaconda.rootPath)
1328    
1329     iutil.writeRpmPlatform()
1330     self.ayum = AnacondaYum(anaconda)
1331     self.ayum.setup()
1332     self.ayum.doMacros()
1333    
1334     # If any enabled repositories require networking, go ahead and bring
1335     # it up now. No need to have people wait for the timeout when we
1336     # know this in advance.
1337     if len(filter(lambda r: r.needsNetwork(), self.ayum.repos.listEnabled())) > 0 and \
1338     not network.hasActiveNetDev():
1339     if not anaconda.intf.enableNetwork():
1340     anaconda.intf.messageWindow(_("No Network Available"),
1341     _("Some of your software repositories require "
1342     "networking, but there was an error enabling the "
1343     "network on your system."),
1344     type="custom", custom_icon="error",
1345     custom_buttons=[_("_Exit installer")])
1346     sys.exit(1)
1347    
1348     urlgrabber.grabber.reset_curl_obj()
1349    
1350     self.doRepoSetup(anaconda)
1351     self.doSackSetup(anaconda)
1352     self.doGroupSetup(anaconda)
1353    
1354     self.ayum.doMacros()
1355    
1356     def doGroupSetup(self, anaconda):
1357     while True:
1358     try:
1359     # FIXME: this is a pretty ugly hack to make it so that we don't lose
1360     # groups being selected (#237708)
1361     sel = filter(lambda g: g.selected, self.ayum.comps.get_groups())
1362     self.ayum.doGroupSetup()
1363     # now we'll actually reselect groups..
1364     map(lambda g: self.selectGroup(g.groupid), sel)
1365    
1366     # and now, to add to the hacks, we'll make sure that packages don't
1367     # have groups double-listed. this avoids problems with deselecting
1368     # groups later
1369     for txmbr in self.ayum.tsInfo.getMembers():
1370     txmbr.groups = yum.misc.unique(txmbr.groups)
1371     except (GroupsError, NoSuchGroup, RepoError), e:
1372     buttons = [_("_Exit installer"), _("_Retry")]
1373     else:
1374     break # success
1375    
1376     rc = anaconda.intf.messageWindow(_("Error"),
1377     _("Unable to read group information "
1378     "from repositories. This is "
1379     "a problem with the generation "
1380     "of your install tree."),
1381     type="custom", custom_icon="error",
1382     custom_buttons = buttons)
1383     if rc == 0:
1384     sys.exit(0)
1385     else:
1386     self.ayum._setGroups(None)
1387     continue
1388    
1389     def doRepoSetup(self, anaconda, thisrepo = None, fatalerrors = True):
1390     self.__withFuncDo(anaconda, lambda r: self.ayum.doRepoSetup(thisrepo=r.id),
1391     thisrepo=thisrepo, fatalerrors=fatalerrors,
1392     callback=RepoSetupPulseProgress(anaconda.intf))
1393    
1394     def doSackSetup(self, anaconda, thisrepo = None, fatalerrors = True):
1395     self.__withFuncDo(anaconda, lambda r: self.ayum.doSackSetup(thisrepo=r.id),
1396     thisrepo=thisrepo, fatalerrors=fatalerrors,
1397     callback=SackSetupProgress(anaconda.intf))
1398    
1399     def __withFuncDo(self, anaconda, fn, thisrepo=None, fatalerrors=True,
1400     callback=None):
1401     # Don't do this if we're being called as a dispatcher step (instead
1402     # of being called when a repo is added via the UI) and we're going
1403     # back.
1404     if thisrepo is None and anaconda.dir == DISPATCH_BACK:
1405     return
1406    
1407     # We want to call the function one repo at a time so we have some
1408     # concept of which repo didn't set up correctly.
1409     if thisrepo is not None:
1410     repos = [self.ayum.repos.getRepo(thisrepo)]
1411     else:
1412     repos = self.ayum.repos.listEnabled()
1413    
1414     for repo in repos:
1415     if callback:
1416     callback.connect(repo)
1417    
1418     while True:
1419     try:
1420     fn(repo)
1421     if callback:
1422     callback.disconnect()
1423     except RepoError, e:
1424     if callback:
1425     callback.disconnect()
1426     if repo.needsNetwork() and not network.hasActiveNetDev():
1427     if anaconda.intf.enableNetwork():
1428     repo.mirrorlistparsed = False
1429     continue
1430    
1431     urlgrabber.grabber.reset_curl_obj()
1432    
1433     buttons = [_("_Exit installer"), _("Edit"), _("_Retry")]
1434     else:
1435     break # success
1436    
1437     if anaconda.isKickstart:
1438     buttons.append(_("_Continue"))
1439    
1440     if not fatalerrors:
1441     raise RepoError, e
1442    
1443     rc = anaconda.intf.messageWindow(_("Error"),
1444     _("Unable to read package metadata. This may be "
1445     "due to a missing repodata directory. Please "
1446     "ensure that your install tree has been "
1447     "correctly generated.\n\n%s" % e),
1448     type="custom", custom_icon="error",
1449     custom_buttons=buttons)
1450     if rc == 0:
1451     # abort
1452     sys.exit(0)
1453     elif rc == 1:
1454     # edit
1455     anaconda.intf.editRepoWindow(repo)
1456     break
1457     elif rc == 2:
1458     # retry, but only if button is present
1459     continue
1460     else:
1461     # continue, but only if button is present
1462     self.ayum.repos.delete(repo.id)
1463     break
1464    
1465     # if we're in kickstart the repo may have been deleted just above
1466     try:
1467     self.ayum.repos.getRepo(repo.id)
1468     except RepoError:
1469     log.debug("repo %s has been removed" % (repo.id,))
1470     continue
1471    
1472     repo.setFailureObj(self.ayum.urlgrabberFailureCB)
1473     repo.setMirrorFailureObj((self.ayum.mirrorFailureCB, (),
1474     {"repo": repo.id}))
1475    
1476     self.ayum.repos.callback = None
1477    
1478     def getDefaultGroups(self, anaconda):
1479     langs = anaconda.id.instLanguage.getCurrentLangSearchList()
1480     rc = map(lambda x: x.groupid,
1481     filter(lambda x: x.default, self.ayum.comps.groups))
1482     for g in self.ayum.comps.groups:
1483     if g.langonly in langs:
1484     rc.append(g.groupid)
1485     return rc
1486    
1487     def resetPackageSelections(self):
1488     """Reset the package selection to an empty state."""
1489     for txmbr in self.ayum.tsInfo:
1490     self.ayum.tsInfo.remove(txmbr.pkgtup)
1491     self.ayum.tsInfo.conditionals.clear()
1492     for grp in self.ayum.comps.groups:
1493     grp.selected = False
1494    
1495     def selectModulePackages(self, anaconda, kernelPkgName):
1496     (base, sep, ext) = kernelPkgName.partition("-")
1497    
1498     moduleProvides = []
1499    
1500     for (path, name) in anaconda.id.extraModules:
1501     if ext != "":
1502     moduleProvides.append("dud-%s-%s" % (name, ext))
1503     else:
1504     moduleProvides.append("dud-%s" % name)
1505    
1506     #We need to install the packages which contain modules from DriverDiscs
1507     for modPath in isys.modulesWithPaths():
1508     log.debug("Checking for DUD module "+modPath)
1509     match = DD_EXTRACTED.match(modPath)
1510     if match:
1511     log.info("Requesting install of kmod-%s" % (match.group("modulename")))
1512     moduleProvides.append("kmod-"+match.group("modulename"))
1513     else:
1514     continue
1515    
1516     for module in moduleProvides:
1517     pkgs = self.ayum.returnPackagesByDep(module)
1518    
1519     if not pkgs:
1520     log.warning("Didn't find any package providing %s" % module)
1521    
1522     for pkg in pkgs:
1523     log.info("selecting package %s for %s" % (pkg.name, module))
1524     self.ayum.install(po=pkg)
1525    
1526     def selectBestKernel(self, anaconda):
1527     """Find the best kernel package which is available and select it."""
1528    
1529     def getBestKernelByArch(pkgname, ayum):
1530     """Convenience func to find the best arch of a kernel by name"""
1531     try:
1532     pkgs = ayum.pkgSack.returnNewestByName(pkgname)
1533     except yum.Errors.PackageSackError:
1534     return None
1535    
1536     pkgs = self.ayum.bestPackagesFromList(pkgs)
1537     if len(pkgs) == 0:
1538     return None
1539     return pkgs[0]
1540    
1541     def selectKernel(pkgname):
1542     try:
1543     pkg = getBestKernelByArch(pkgname, self.ayum)
1544     except PackageSackError:
1545     log.debug("no %s package" % pkgname)
1546     return False
1547    
1548     if not pkg:
1549     return False
1550    
1551     log.info("selected %s package for kernel" % pkg.name)
1552     self.ayum.install(po=pkg)
1553     self.selectModulePackages(anaconda, pkg.name)
1554    
1555     if len(self.ayum.tsInfo.matchNaevr(name="gcc")) > 0:
1556     log.debug("selecting %s-devel" % pkg.name)
1557     self.selectPackage("%s-devel.%s" % (pkg.name, pkg.arch))
1558    
1559     return True
1560    
1561     foundkernel = False
1562    
1563     if not foundkernel and isys.isPaeAvailable():
1564     if selectKernel("kernel-PAE"):
1565     foundkernel = True
1566    
1567     if not foundkernel:
1568     selectKernel("kernel")
1569    
1570     def selectFSPackages(self, storage):
1571     for device in storage.fsset.devices:
1572     # this takes care of device and filesystem packages
1573     map(self.selectPackage, device.packages)
1574    
1575     # anaconda requires several programs on the installed system to complete
1576     # installation, but we have no guarantees that some of these will be
1577     # installed (they could have been removed in kickstart). So we'll force
1578     # it.
1579     def selectAnacondaNeeds(self):
1580     for pkg in ['authconfig', 'chkconfig', 'system-config-firewall-base']:
1581     self.selectPackage(pkg)
1582    
1583     def doPostSelection(self, anaconda):
1584     # Only solve dependencies on the way through the installer, not the way back.
1585     if anaconda.dir == DISPATCH_BACK:
1586     return
1587    
1588     dscb = YumDepSolveProgress(anaconda.intf, self.ayum)
1589     self.ayum.dsCallback = dscb
1590    
1591     # do some sanity checks for kernel and bootloader
1592     if not anaconda.id.getUpgrade():
1593     # New installs only - upgrades will already have all this stuff.
1594     self.selectBestKernel(anaconda)
1595     map(self.selectPackage, anaconda.platform.packages)
1596     self.selectFSPackages(anaconda.id.storage)
1597     if anaconda.id.network.hasActiveIPoIBDevice():
1598     self.selectPackage("rdma")
1599     self.selectAnacondaNeeds()
1600     else:
1601     self.ayum.update()
1602    
1603     while True:
1604     try:
1605     (code, msgs) = self.ayum.buildTransaction()
1606    
1607     # If %packages --ignoremissing was given, don't bother
1608     # prompting for missing dependencies.
1609     if anaconda.isKickstart and anaconda.id.ksdata.packages.handleMissing == KS_MISSING_IGNORE:
1610     break
1611    
1612     if code == 1 and not anaconda.id.upgrade:
1613     # resolveDeps returns 0 if empty transaction, 1 if error,
1614     # 2 if success
1615     depprob = "\n".join(msgs)
1616    
1617     custom_buttons = [_("_Exit installer"), _("_Continue")]
1618     if not anaconda.isKickstart:
1619     custom_buttons.insert(1, _("_Back"))
1620    
1621     rc = anaconda.intf.detailedMessageWindow(_("Warning"),
1622     _("Some of the packages you have selected for "
1623     "install are missing dependencies. You can "
1624     "exit the installation, go back and change "
1625     "your package selections, or continue "
1626     "installing these packages without their "
1627     "dependencies."),
1628     depprob + "\n", type="custom", custom_icon="error",
1629     custom_buttons=custom_buttons)
1630     dscb.pop()
1631    
1632     if rc == 0:
1633     sys.exit(1)
1634     elif rc == 1 and not anaconda.isKickstart:
1635     self.ayum._undoDepInstalls()
1636     return DISPATCH_BACK
1637    
1638     break
1639     except RepoError, e:
1640     # FIXME: would be nice to be able to recover here
1641     rc = anaconda.intf.messageWindow(_("Error"),
1642     _("Unable to read package metadata. This may be "
1643     "due to a missing repodata directory. Please "
1644     "ensure that your install tree has been "
1645     "correctly generated.\n\n%s" % e),
1646     type="custom", custom_icon="error",
1647     custom_buttons=[_("_Exit installer"), _("_Retry")])
1648     dscb.pop()
1649    
1650     if rc == 0:
1651     sys.exit(0)
1652     else:
1653     continue
1654     else:
1655     break
1656    
1657     (self.dlpkgs, self.totalSize, self.totalFiles) = self.ayum.getDownloadPkgs()
1658    
1659     if not anaconda.id.upgrade:
1660     largePart = anaconda.id.storage.mountpoints.get("/usr", anaconda.id.storage.rootDevice)
1661    
1662     if largePart and largePart.size < self.totalSize / 1024:
1663     rc = anaconda.intf.messageWindow(_("Error"),
1664     _("Your selected packages require %d MB "
1665     "of free space for installation, but "
1666     "you do not have enough available. "
1667     "You can change your selections or "
1668     "exit the installer." % (self.totalSize / 1024)),
1669     type="custom", custom_icon="error",
1670     custom_buttons=[_("_Back"), _("_Exit installer")])
1671    
1672     dscb.pop()
1673    
1674     if rc == 1:
1675     sys.exit(1)
1676     else:
1677     self.ayum._undoDepInstalls()
1678     return DISPATCH_BACK
1679    
1680     dscb.pop()
1681    
1682     if anaconda.mediaDevice and not anaconda.isKickstart:
1683     rc = presentRequiredMediaMessage(anaconda)
1684     if rc == 0:
1685     rc2 = anaconda.intf.messageWindow(_("Reboot?"),
1686     _("The system will be rebooted now."),
1687     type="custom", custom_icon="warning",
1688     custom_buttons=[_("_Back"), _("_Reboot")])
1689     if rc2 == 1:
1690     sys.exit(0)
1691     else:
1692     return DISPATCH_BACK
1693     elif rc == 1: # they asked to go back
1694     return DISPATCH_BACK
1695    
1696     self.ayum.dsCallback = None
1697    
1698     def doPreInstall(self, anaconda):
1699     if anaconda.dir == DISPATCH_BACK:
1700     for d in ("/selinux", "/dev", "/proc/bus/usb"):
1701     try:
1702     isys.umount(anaconda.rootPath + d, removeDir = False)
1703     except Exception, e:
1704     log.error("unable to unmount %s: %s" %(d, e))
1705     return
1706    
1707     # shorthand
1708     upgrade = anaconda.id.getUpgrade()
1709    
1710     if upgrade:
1711     # An old mtab can cause confusion (esp if loop devices are
1712     # in it). Be extra special careful and delete any mtab first,
1713     # in case the user has done something funny like make it into
1714     # a symlink.
1715     if os.access(anaconda.rootPath + "/etc/mtab", os.F_OK):
1716     os.remove(anaconda.rootPath + "/etc/mtab")
1717    
1718     f = open(anaconda.rootPath + "/etc/mtab", "w+")
1719     f.close()
1720    
1721     # we really started writing modprobe.conf out before things were
1722     # all completely ready. so now we need to nuke old modprobe.conf's
1723     # if you're upgrading from a 2.4 dist so that we can get the
1724     # transition right
1725     if (os.path.exists(anaconda.rootPath + "/etc/modules.conf") and
1726     os.path.exists(anaconda.rootPath + "/etc/modprobe.conf") and
1727     not os.path.exists(anaconda.rootPath + "/etc/modprobe.conf.anacbak")):
1728     log.info("renaming old modprobe.conf -> modprobe.conf.anacbak")
1729     os.rename(anaconda.rootPath + "/etc/modprobe.conf",
1730     anaconda.rootPath + "/etc/modprobe.conf.anacbak")
1731    
1732     dirList = ['/var', '/var/lib', '/var/lib/rpm', '/tmp', '/dev', '/etc',
1733     '/etc/sysconfig', '/etc/sysconfig/network-scripts',
1734     '/etc/X11', '/root', '/var/tmp', '/etc/rpm', '/var/cache',
1735     '/var/cache/yum', '/etc/modprobe.d']
1736    
1737     # If there are any protected partitions we want to mount, create their
1738     # mount points now.
1739     for protected in anaconda.id.storage.protectedDevices:
1740     if getattr(protected.format, "mountpoint", None):
1741     dirList.append(protected.format.mountpoint)
1742    
1743     for i in dirList:
1744     try:
1745     os.mkdir(anaconda.rootPath + i)
1746     except os.error, (errno, msg):
1747     pass
1748     # log.error("Error making directory %s: %s" % (i, msg))
1749    
1750     self.initLog(anaconda.id, anaconda.rootPath)
1751    
1752     # setup /etc/rpm/ for the post-install environment
1753     iutil.writeRpmPlatform(anaconda.rootPath)
1754    
1755     try:
1756     # FIXME: making the /var/lib/rpm symlink here is a hack to
1757     # workaround db->close() errors from rpm
1758     iutil.mkdirChain("/var/lib")
1759     for path in ("/var/tmp", "/var/lib/rpm"):
1760     if os.path.exists(path) and not os.path.islink(path):
1761     shutil.rmtree(path)
1762     if not os.path.islink(path):
1763     os.symlink("%s/%s" %(anaconda.rootPath, path), "%s" %(path,))
1764     else:
1765     log.warning("%s already exists as a symlink to %s" %(path, os.readlink(path),))
1766     except Exception, e:
1767     # how this could happen isn't entirely clear; log it in case
1768     # it does and causes problems later
1769     log.error("error creating symlink, continuing anyway: %s" %(e,))
1770    
1771     # SELinux hackery (#121369)
1772     if flags.selinux:
1773     try:
1774     os.mkdir(anaconda.rootPath + "/selinux")
1775     except Exception, e:
1776     pass
1777     try:
1778     isys.mount("/selinux", anaconda.rootPath + "/selinux", "selinuxfs")
1779     except Exception, e:
1780     log.error("error mounting selinuxfs: %s" %(e,))
1781    
1782     # For usbfs
1783     try:
1784     isys.mount("/proc/bus/usb", anaconda.rootPath + "/proc/bus/usb", "usbfs")
1785     except Exception, e:
1786     log.error("error mounting usbfs: %s" %(e,))
1787    
1788     # write out the fstab
1789     if not upgrade:
1790     anaconda.id.storage.fsset.write(anaconda.rootPath)
1791     if os.access("/etc/modprobe.d/anaconda.conf", os.R_OK):
1792     shutil.copyfile("/etc/modprobe.d/anaconda.conf",
1793     anaconda.rootPath + "/etc/modprobe.d/anaconda.conf")
1794     anaconda.id.network.write()
1795     anaconda.id.network.copyConfigToPath(instPath=anaconda.rootPath)
1796     anaconda.id.storage.write(anaconda.rootPath)
1797     if not anaconda.id.isHeadless:
1798     anaconda.id.keyboard.write(anaconda.rootPath)
1799    
1800     # make a /etc/mtab so mkinitrd can handle certain hw (usb) correctly
1801     f = open(anaconda.rootPath + "/etc/mtab", "w+")
1802     f.write(anaconda.id.storage.mtab)
1803     f.close()
1804    
1805     def checkSupportedUpgrade(self, anaconda):
1806     if anaconda.dir == DISPATCH_BACK:
1807     return
1808     self._checkUpgradeVersion(anaconda)
1809     self._checkUpgradeArch(anaconda)
1810    
1811     def _checkUpgradeVersion(self, anaconda):
1812     # Figure out current version for upgrade nag and for determining weird
1813     # upgrade cases
1814     supportedUpgradeVersion = -1
1815     for pkgtup in self.ayum.rpmdb.whatProvides('redhat-release', None, None):
1816     n, a, e, v, r = pkgtup
1817     if supportedUpgradeVersion <= 0:
1818     val = rpmUtils.miscutils.compareEVR((None, '9.0', '1'),
1819     (e, v,r))
1820     if val > 0:
1821     supportedUpgradeVersion = 0
1822     else:
1823     supportedUpgradeVersion = 1
1824     break
1825    
1826     if "SME Server" not in productName:
1827     supportedUpgradeVersion = 1
1828    
1829     if supportedUpgradeVersion == 0:
1830     rc = anaconda.intf.messageWindow(_("Warning"),
1831     _("You appear to be upgrading from a system "
1832     "which is too old to upgrade to this "
1833     "version of %s. Are you sure you wish to "
1834     "continue the upgrade "
1835     "process?") %(productName,),
1836     type = "yesno")
1837     if rc == 0:
1838     iutil.resetRpmDb(anaconda.rootPath)
1839     sys.exit(0)
1840    
1841     def _checkUpgradeArch(self, anaconda):
1842     def compareArch(a, b):
1843     if re.match("i.86", a) and re.match("i.86", b):
1844     return True
1845     else:
1846     return a == b
1847    
1848     # get the arch of the initscripts package
1849     try:
1850     pkgs = self.ayum.pkgSack.returnNewestByName('initscripts')
1851     except yum.Errors.PackageSackError:
1852     log.info("no packages named initscripts")
1853     return None
1854    
1855     pkgs = self.ayum.bestPackagesFromList(pkgs)
1856     if len(pkgs) == 0:
1857     log.info("no best package")
1858     return
1859     myarch = pkgs[0].arch
1860    
1861     log.info("initscripts is arch: %s" %(myarch,))
1862     for po in self.ayum.rpmdb.getProvides('initscripts'):
1863     log.info("po.arch is arch: %s" %(po.arch,))
1864     if not compareArch(po.arch, myarch):
1865     rc = anaconda.intf.messageWindow(_("Warning"),
1866     _("The arch of the release of %(productName)s you "
1867     "are upgrading to appears to be %(myarch)s which "
1868     "does not match your previously installed arch of "
1869     "%(arch)s. This is likely to not succeed. Are "
1870     "you sure you wish to continue the upgrade "
1871     "process?")
1872     % {'productName': productName,
1873     'myarch': myarch,
1874     'arch': po.arch},
1875     type="yesno")
1876     if rc == 0:
1877     iutil.resetRpmDb(anaconda.rootPath)
1878     sys.exit(0)
1879     else:
1880     log.warning("upgrade between possibly incompatible "
1881     "arches %s -> %s" %(po.arch, myarch))
1882     break
1883    
1884     def doInstall(self, anaconda):
1885     log.info("Preparing to install packages")
1886    
1887     if not anaconda.id.upgrade:
1888     rpm.addMacro("__dbi_htconfig",
1889     "hash nofsync %{__dbi_other} %{__dbi_perms}")
1890    
1891     if anaconda.isKickstart and anaconda.id.ksdata.packages.excludeDocs:
1892     rpm.addMacro("_excludedocs", "1")
1893    
1894     cb = AnacondaCallback(self.ayum, anaconda,
1895     self.instLog, self.modeText)
1896     cb.setSizes(len(self.dlpkgs), self.totalSize, self.totalFiles)
1897    
1898     rc = self.ayum.run(self.instLog, cb, anaconda.intf, anaconda.id)
1899    
1900     if cb.initWindow is not None:
1901     cb.initWindow.pop()
1902    
1903     self.instLog.write("*** FINISHED INSTALLING PACKAGES ***")
1904     self.instLog.close ()
1905    
1906     anaconda.id.instProgress = None
1907    
1908     if rc == DISPATCH_BACK:
1909     return DISPATCH_BACK
1910    
1911     def doPostInstall(self, anaconda):
1912     if anaconda.id.getUpgrade():
1913     w = anaconda.intf.waitWindow(_("Post Upgrade"),
1914     _("Performing post-upgrade configuration"))
1915     else:
1916     w = anaconda.intf.waitWindow(_("Post Installation"),
1917     _("Performing post-installation configuration"))
1918    
1919     packages.rpmSetupGraphicalSystem(anaconda)
1920    
1921     for repo in self.ayum.repos.listEnabled():
1922     repo.dirCleanup()
1923    
1924     # expire yum caches on upgrade
1925     if (flags.cmdline.has_key("preupgrade") or anaconda.id.getUpgrade()) and os.path.exists("%s/var/cache/yum" %(anaconda.rootPath,)):
1926     log.info("Expiring yum caches")
1927     try:
1928     iutil.execWithRedirect("yum", ["clean", "all"],
1929     stdout="/dev/tty5", stderr="/dev/tty5",
1930     root = anaconda.rootPath)
1931     except:
1932     pass
1933    
1934     # nuke preupgrade
1935     if flags.cmdline.has_key("preupgrade") and os.path.exists("%s/var/cache/yum/anaconda-upgrade" %(anaconda.rootPath,)):
1936     try:
1937     shutil.rmtree("%s/var/cache/yum/anaconda-upgrade" %(anaconda.rootPath,))
1938     except:
1939     pass
1940    
1941     # XXX: write proper lvm config
1942    
1943     AnacondaBackend.doPostInstall(self, anaconda)
1944     w.pop()
1945    
1946     def kernelVersionList(self, rootPath="/"):
1947     # FIXME: using rpm here is a little lame, but otherwise, we'd
1948     # be pulling in filelists
1949     return packages.rpmKernelVersionList(rootPath)
1950    
1951     def __getGroupId(self, group):
1952     """Get the groupid for the given name (english or translated)."""
1953     for g in self.ayum.comps.groups:
1954     if group == g.name:
1955     return g.groupid
1956     for trans in g.translated_name.values():
1957     if group == trans:
1958     return g.groupid
1959    
1960     def isGroupSelected(self, group):
1961     try:
1962     grp = self.ayum.comps.return_group(group)
1963     if grp.selected: return True
1964     except yum.Errors.GroupsError, e:
1965     pass
1966     return False
1967    
1968     def selectGroup(self, group, *args):
1969     if not self.ayum.comps.has_group(group):
1970     log.debug("no such group %s" % group)
1971     raise NoSuchGroup, group
1972    
1973     types = ["mandatory"]
1974    
1975     if args:
1976     if args[0][0]:
1977     types.append("default")
1978     if args[0][1]:
1979     types.append("optional")
1980     else:
1981     types.append("default")
1982    
1983     try:
1984     mbrs = self.ayum.selectGroup(group, group_package_types=types)
1985     if len(mbrs) == 0 and self.isGroupSelected(group):
1986     return
1987     except yum.Errors.GroupsError, e:
1988     # try to find out if it's the name or translated name
1989     gid = self.__getGroupId(group)
1990     if gid is not None:
1991     mbrs = self.ayum.selectGroup(gid, group_package_types=types)
1992     if len(mbrs) == 0 and self.isGroupSelected(gid):
1993     return
1994     else:
1995     log.debug("no such group %s" %(group,))
1996     raise NoSuchGroup, group
1997    
1998     def deselectGroup(self, group, *args):
1999     try:
2000     self.ayum.deselectGroup(group, force=True)
2001     except yum.Errors.GroupsError, e:
2002     # try to find out if it's the name or translated name
2003     gid = self.__getGroupId(group)
2004     if gid is not None:
2005     self.ayum.deselectGroup(gid, force=True)
2006     else:
2007     log.debug("no such group %s" %(group,))
2008    
2009     def selectPackage(self, pkg, *args):
2010     try:
2011     mbrs = self.ayum.install(pattern=pkg)
2012     return len(mbrs)
2013     except yum.Errors.InstallError:
2014     log.debug("no package matching %s" %(pkg,))
2015     return 0
2016    
2017     def deselectPackage(self, pkg, *args):
2018     sp = pkg.rsplit(".", 2)
2019     txmbrs = []
2020     if len(sp) == 2:
2021     txmbrs = self.ayum.tsInfo.matchNaevr(name=sp[0], arch=sp[1])
2022    
2023     if len(txmbrs) == 0:
2024     exact, match, unmatch = yum.packages.parsePackages(self.ayum.pkgSack.returnPackages(), [pkg], casematch=1)
2025     for p in exact + match:
2026     txmbrs.append(p)
2027    
2028     if len(txmbrs) > 0:
2029     for x in txmbrs:
2030     self.ayum.tsInfo.remove(x.pkgtup)
2031     # we also need to remove from the conditionals
2032     # dict so that things don't get pulled back in as a result
2033     # of them. yes, this is ugly. conditionals should die.
2034     for req, pkgs in self.ayum.tsInfo.conditionals.iteritems():
2035     if x in pkgs:
2036     pkgs.remove(x)
2037     self.ayum.tsInfo.conditionals[req] = pkgs
2038     return len(txmbrs)
2039     else:
2040     log.debug("no such package %s to remove" %(pkg,))
2041     return 0
2042    
2043     def groupListExists(self, grps):
2044     """Returns bool of whether all of the given groups exist."""
2045     for gid in grps:
2046     g = self.ayum.comps.return_group(gid)
2047     if not g:
2048     log.debug("no such group %s" % (gid,))
2049     return False
2050     return True
2051    
2052     def groupListDefault(self, grps):
2053     """Returns bool of whether all of the given groups are default"""
2054     rc = False
2055     for gid in grps:
2056     g = self.ayum.comps.return_group(gid)
2057     if g and not g.default:
2058     return False
2059     elif g:
2060     rc = True
2061     return rc
2062    
2063     def writeKS(self, f):
2064     for repo in self.ayum.repos.listEnabled():
2065     if repo.name == "Installation Repo":
2066     continue
2067     if repo.name == "Red Hat Enterprise Linux":
2068     continue
2069     # ignore addon repos from media
2070     if repo.anacondaBaseURLs[0].startswith("file://"):
2071     continue
2072    
2073     line = "repo --name=\"%s\" " % (repo.name or repo.repoid)
2074    
2075     if repo.baseurl:
2076     line += " --baseurl=%s" % repo.anacondaBaseURLs[0]
2077     else:
2078     line += " --mirrorlist=%s" % repo.mirrorlist
2079    
2080     if repo.proxy:
2081     line += " --proxy=\"%s\"" % repo.proxy_dict['http']
2082    
2083     if repo.cost:
2084     line += " --cost=%s" % repo.cost
2085    
2086     if repo.includepkgs:
2087     line += " --includepkgs=\"%s\"" % ",".join(repo.includepkgs)
2088    
2089     if repo.exclude:
2090     line += " --excludepkgs=\"%s\"" % ",".join(repo.exclude)
2091    
2092     if not repo.sslverify:
2093     line += " --noverifyssl"
2094    
2095     line += "\n"
2096    
2097     f.write(line)
2098    
2099     def writePackagesKS(self, f, anaconda):
2100     if anaconda.isKickstart:
2101     f.write(anaconda.id.ksdata.packages.__str__())
2102     return
2103    
2104     groups = []
2105     installed = []
2106     removed = []
2107    
2108     # Faster to grab all the package names up front rather than call
2109     # searchNevra in the loop below.
2110     allPkgNames = map(lambda pkg: pkg.name, self.ayum.pkgSack.returnPackages())
2111     allPkgNames.sort()
2112    
2113     # On CD/DVD installs, we have one transaction per CD and will end up
2114     # checking allPkgNames against a very short list of packages. So we
2115     # have to reset to media #0, which is an all packages transaction.
2116     old = self.ayum.tsInfo.curmedia
2117     self.ayum.tsInfo.curmedia = 0
2118    
2119     self.ayum.tsInfo.makelists()
2120     txmbrNames = map (lambda x: x.name, self.ayum.tsInfo.getMembers())
2121    
2122     self.ayum.tsInfo.curmedia = old
2123    
2124     if len(self.ayum.tsInfo.instgroups) == 0 and len(txmbrNames) == 0:
2125     return
2126    
2127     for grp in filter(lambda x: x.selected, self.ayum.comps.groups):
2128     groups.append(grp.groupid)
2129    
2130     defaults = grp.default_packages.keys() + grp.mandatory_packages.keys()
2131     optionals = grp.optional_packages.keys()
2132    
2133     for pkg in filter(lambda x: x in defaults and (not x in txmbrNames and x in allPkgNames), grp.packages):
2134     removed.append(pkg)
2135    
2136     for pkg in filter(lambda x: x in txmbrNames, optionals):
2137     installed.append(pkg)
2138    
2139     if len(groups) == 1 and groups[0].lower() == "core":
2140     f.write("\n%packages --nobase\n")
2141     else:
2142     f.write("\n%packages\n")
2143    
2144     for grp in groups:
2145     f.write("@%s\n" % grp)
2146    
2147     for pkg in installed:
2148     f.write("%s\n" % pkg)
2149    
2150     for pkg in removed:
2151     f.write("-%s\n" % pkg)
2152    
2153     f.write("%end")
2154    
2155     def writeConfiguration(self):
2156     return
2157    
2158     def getRequiredMedia(self):
2159     return self.ayum.tsInfo.reqmedia.keys()
2160    
2161     class DownloadHeaderProgress:
2162     def __init__(self, intf, ayum=None):
2163     window = intf.progressWindow(_("Installation Starting"),
2164     _("Starting installation process"),
2165     1.0, 0.01)
2166     self.window = window
2167     self.ayum = ayum
2168     self.current = self.loopstart = 0
2169     self.incr = 1
2170    
2171     if self.ayum is not None and self.ayum.tsInfo is not None:
2172     self.numpkgs = len(self.ayum.tsInfo.getMembers())
2173     if self.numpkgs != 0:
2174     self.incr = (1.0 / self.numpkgs) * (1.0 - self.loopstart)
2175     else:
2176     self.numpkgs = 0
2177    
2178     self.refresh()
2179    
2180     self.restartLoop = self.downloadHeader = self.transactionPopulation = self.refresh
2181     self.procReq = self.procConflict = self.unresolved = self.noop
2182    
2183     def noop(self, *args, **kwargs):
2184     pass
2185    
2186     def pkgAdded(self, *args):
2187     if self.numpkgs:
2188     self.set(self.current + self.incr)
2189    
2190     def pop(self):
2191     self.window.pop()
2192    
2193     def refresh(self, *args):
2194     self.window.refresh()
2195    
2196     def set(self, value):
2197     self.current = value
2198     self.window.set(self.current)
2199    
2200     class YumDepSolveProgress:
2201     def __init__(self, intf, ayum = None):
2202     window = intf.progressWindow(_("Dependency Check"),
2203     _("Checking dependencies in packages selected for installation"),
2204     1.0, 0.01)
2205     self.window = window
2206    
2207     self.numpkgs = None
2208     self.loopstart = None
2209     self.incr = None
2210     self.ayum = ayum
2211     self.current = 0
2212    
2213     self.restartLoop = self.downloadHeader = self.transactionPopulation = self.refresh
2214     self.procReq = self.procConflict = self.unresolved = self.noop
2215    
2216     def tscheck(self, num = None):
2217     self.refresh()
2218     if num is None and self.ayum is not None and self.ayum.tsInfo is not None:
2219     num = len(self.ayum.tsInfo.getMembers())
2220    
2221     if num:
2222     self.numpkgs = num
2223     self.loopstart = self.current
2224     self.incr = (1.0 / num) * ((1.0 - self.loopstart) / 2)
2225    
2226     def pkgAdded(self, *args):
2227     if self.numpkgs:
2228     self.set(self.current + self.incr)
2229    
2230     def noop(self, *args, **kwargs):
2231     pass
2232    
2233     def refresh(self, *args):
2234     self.window.refresh()
2235    
2236     def set(self, value):
2237     self.current = value
2238     self.window.set(self.current)
2239    
2240     def start(self):
2241     self.set(0.0)
2242     self.refresh()
2243    
2244     def end(self):
2245     self.window.set(1.0)
2246     self.window.refresh()
2247    
2248     def pop(self):
2249     self.window.pop()
2250    
2251     # We don't have reasonable hook for sackSetup, and it
2252     # is fairly fast, so we use just waitWindow here
2253     class SackSetupProgress:
2254     def __init__(self, intf):
2255     self.intf = intf
2256    
2257     def connect(self, repo):
2258     if repo.name is None:
2259     txt = _("Retrieving installation information.")
2260     else:
2261     txt = _("Retrieving installation information for %s.")%(repo.name)
2262     self.window = self.intf.waitWindow(_("Installation Progress"), txt)
2263    
2264     def disconnect(self):
2265     self.window.pop()
2266    
2267     class RepoSetupPulseProgress:
2268     def __init__(self, intf):
2269     self.intf = intf
2270     self.repo = None
2271    
2272     def connect(self, repo):
2273     self.repo = repo
2274     if repo.name is None:
2275     txt = _("Retrieving installation information.")
2276     else:
2277     txt = _("Retrieving installation information for %s.")%(repo.name)
2278     self.window = self.intf.progressWindow(_("Installation Progress"),
2279     txt,
2280     1.0, pulse=True)
2281     repo.setCallback(self)
2282    
2283     def disconnect(self):
2284     self.window.pop()
2285     self.repo.setCallback(None)
2286    
2287     def refresh(self, *args):
2288     self.window.refresh()
2289    
2290     def set(self):
2291     self.window.pulse()
2292    
2293     def start(self, filename, url, basename, size, text):
2294     log.debug("Grabbing %s" % url)
2295     self.set()
2296     self.refresh()
2297    
2298     def update(self, read):
2299     self.set()
2300     self.refresh()
2301    
2302     def end(self, read):
2303     self.set()
2304     self.window.refresh()

admin@koozali.org
ViewVC Help
Powered by ViewVC 1.2.1 RSS 2.0 feed