Output details of dep check failure
[livecd.git] / imgcreate / yuminst.py
blob6b1698f3868163c1eea87572c57e8e9b3aa1034a
2 # yum.py : yum utilities
4 # Copyright 2007, Red Hat Inc.
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; version 2 of the License.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Library General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 import glob
20 import os
21 import sys
22 import logging
24 import yum
25 import rpmUtils
26 import pykickstart.parser
28 from imgcreate.errors import *
30 class TextProgress(object):
31 logger = logging.getLogger()
32 def emit(self, lvl, msg):
33 '''play nice with the logging module'''
34 for hdlr in self.logger.handlers:
35 if lvl >= self.logger.level:
36 hdlr.stream.write(msg)
37 hdlr.stream.flush()
39 def start(self, filename, url, *args, **kwargs):
40 self.emit(logging.INFO, "Retrieving %s " % (url,))
41 self.url = url
42 def update(self, *args):
43 pass
44 def end(self, *args):
45 self.emit(logging.INFO, "...OK\n")
47 class LiveCDYum(yum.YumBase):
48 def __init__(self, releasever=None, useplugins=False):
49 """
50 releasever = optional value to use in replacing $releasever in repos
51 """
52 yum.YumBase.__init__(self)
53 self.releasever = releasever
54 self.useplugins = useplugins
56 def doFileLogSetup(self, uid, logfile):
57 # don't do the file log for the livecd as it can lead to open fds
58 # being left and an inability to clean up after ourself
59 pass
61 def close(self):
62 try:
63 os.unlink(self.conf.installroot + "/yum.conf")
64 except:
65 pass
66 yum.YumBase.close(self)
68 def __del__(self):
69 pass
71 def _writeConf(self, confpath, installroot):
72 conf = "[main]\n"
73 conf += "installroot=%s\n" % installroot
74 conf += "cachedir=/var/cache/yum\n"
75 if self.useplugins:
76 conf += "plugins=1\n"
77 else:
78 conf += "plugins=0\n"
79 conf += "reposdir=\n"
80 conf += "failovermethod=priority\n"
81 conf += "keepcache=1\n"
82 conf += "tsflags=nocontexts\n"
84 f = file(confpath, "w+")
85 f.write(conf)
86 f.close()
88 os.chmod(confpath, 0644)
90 def _cleanupRpmdbLocks(self, installroot):
91 # cleans up temporary files left by bdb so that differing
92 # versions of rpm don't cause problems
93 for f in glob.glob(installroot + "/var/lib/rpm/__db*"):
94 os.unlink(f)
96 def setup(self, confpath, installroot, cacheonly=False):
97 self._writeConf(confpath, installroot)
98 self._cleanupRpmdbLocks(installroot)
99 self.doConfigSetup(fn = confpath, root = installroot)
100 if cacheonly:
101 self.conf.cache = 1
102 else:
103 self.conf.cache = 0
104 self.doTsSetup()
105 self.doRpmDBSetup()
106 self.doRepoSetup()
107 self.doSackSetup()
109 def selectPackage(self, pkg):
110 """Select a given package. Can be specified with name.arch or name*"""
111 return self.install(pattern = pkg)
113 def deselectPackage(self, pkg):
114 """Deselect package. Can be specified as name.arch or name*"""
115 sp = pkg.rsplit(".", 2)
116 txmbrs = []
117 if len(sp) == 2:
118 txmbrs = self.tsInfo.matchNaevr(name=sp[0], arch=sp[1])
120 if len(txmbrs) == 0:
121 exact, match, unmatch = yum.packages.parsePackages(self.pkgSack.returnPackages(), [pkg], casematch=1)
122 for p in exact + match:
123 txmbrs.append(p)
125 if len(txmbrs) > 0:
126 for x in txmbrs:
127 self.tsInfo.remove(x.pkgtup)
128 # we also need to remove from the conditionals
129 # dict so that things don't get pulled back in as a result
130 # of them. yes, this is ugly. conditionals should die.
131 for req, pkgs in self.tsInfo.conditionals.iteritems():
132 if x in pkgs:
133 pkgs.remove(x)
134 self.tsInfo.conditionals[req] = pkgs
135 else:
136 logging.warn("No such package %s to remove" %(pkg,))
138 def selectGroup(self, grp, include = pykickstart.parser.GROUP_DEFAULT):
139 # default to getting mandatory and default packages from a group
140 # unless we have specific options from kickstart
141 package_types = ['mandatory', 'default']
142 if include == pykickstart.parser.GROUP_REQUIRED:
143 package_types.remove('default')
144 elif include == pykickstart.parser.GROUP_ALL:
145 package_types.append('optional')
146 yum.YumBase.selectGroup(self, grp, group_package_types=package_types)
148 def addRepository(self, name, url = None, mirrorlist = None):
149 def _varSubstitute(option):
150 # takes a variable and substitutes like yum configs do
151 option = option.replace("$basearch", rpmUtils.arch.getBaseArch())
152 option = option.replace("$arch", rpmUtils.arch.getCanonArch())
153 # If the url includes $releasever substitute user's value or
154 # current system's version.
155 if option.find("$releasever") > -1:
156 if self.releasever:
157 option = option.replace("$releasever", self.releasever)
158 else:
159 try:
160 option = option.replace("$releasever", yum.config._getsysver("/", "redhat-release"))
161 except yum.Errors.YumBaseError:
162 raise CreatorError("$releasever in repo url, but no releasever set")
163 return option
165 repo = yum.yumRepo.YumRepository(name)
166 if url:
167 repo.baseurl.append(_varSubstitute(url))
168 if mirrorlist:
169 repo.mirrorlist = _varSubstitute(mirrorlist)
170 conf = yum.config.RepoConf()
171 for k, v in conf.iteritems():
172 if v or not hasattr(repo, k):
173 repo.setAttribute(k, v)
174 repo.basecachedir = self.conf.cachedir
175 repo.base_persistdir = self.conf.cachedir
176 repo.failovermethod = "priority"
177 repo.metadata_expire = 0
178 repo.mirrorlist_expire = 0
179 repo.timestamp_check = 0
180 # disable gpg check???
181 repo.gpgcheck = 0
182 repo.enable()
183 repo.setup(self.conf.cache)
184 repo.setCallback(TextProgress())
185 self.repos.add(repo)
186 return repo
188 def installHasFile(self, file):
189 provides_pkg = self.whatProvides(file, None, None)
190 dlpkgs = map(lambda x: x.po, filter(lambda txmbr: txmbr.ts_state in ("i", "u"), self.tsInfo.getMembers()))
191 for p in dlpkgs:
192 for q in provides_pkg:
193 if (p == q):
194 return True
195 return False
198 def runInstall(self):
199 os.environ["HOME"] = "/"
200 try:
201 (res, resmsg) = self.buildTransaction()
202 except yum.Errors.RepoError, e:
203 raise CreatorError("Unable to download from repo : %s" %(e,))
204 # Empty transactions are generally fine, we might be rebuilding an
205 # existing image with no packages added
206 if resmsg and resmsg[0].endswith(" - empty transaction"):
207 return res
208 if res != 2:
209 raise CreatorError("Failed to build transaction : %s" % str.join("\n", resmsg))
211 dlpkgs = map(lambda x: x.po, filter(lambda txmbr: txmbr.ts_state in ("i", "u"), self.tsInfo.getMembers()))
212 self.downloadPkgs(dlpkgs)
213 # FIXME: sigcheck?
215 self.initActionTs()
216 self.populateTs(keepold=0)
217 deps = self.ts.check()
218 if len(deps) != 0:
219 raise CreatorError("Dependency check failed : %s" % "\n".join(deps))
220 rc = self.ts.order()
221 if rc != 0:
222 raise CreatorError("ordering packages for installation failedr. rc = %s" % rc)
224 # FIXME: callback should be refactored a little in yum
225 sys.path.append('/usr/share/yum-cli')
226 import yum.misc
227 yum.misc.setup_locale()
228 import callback
229 cb = callback.RPMInstallCallback()
230 cb.tsInfo = self.tsInfo
231 cb.filelog = False
232 ret = self.runTransaction(cb)
233 print ""
234 self._cleanupRpmdbLocks(self.conf.installroot)
235 return ret