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

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

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


Revision 1.2 - (show annotations) (download) (as text)
Sun Dec 22 04:27:50 2013 UTC (11 years ago) by wellsi
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +0 -0 lines
Content type: text/x-python
FILE REMOVED
anaconda updates now handled via patches

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