liveimage-mount: add missing import
[livecd.git] / imgcreate / yuminst.py
blobea4473739be7fc2053d5f672f2856165bcc0af5b
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=None, url=None, *args, **kwargs):
40 text = kwargs.get("text", "")
41 self.emit(logging.INFO, "Retrieving %s " % (url or text))
42 self.url = url
43 def update(self, *args):
44 pass
45 def end(self, *args):
46 self.emit(logging.INFO, "...OK\n")
48 class LiveCDYum(yum.YumBase):
49 def __init__(self, releasever=None, useplugins=False):
50 """
51 releasever = optional value to use in replacing $releasever in repos
52 """
53 yum.YumBase.__init__(self)
54 self.releasever = releasever
55 self.useplugins = useplugins
57 def doFileLogSetup(self, uid, logfile):
58 # don't do the file log for the livecd as it can lead to open fds
59 # being left and an inability to clean up after ourself
60 pass
62 def close(self):
63 try:
64 os.unlink(self.conf.installroot + "/yum.conf")
65 except:
66 pass
67 yum.YumBase.close(self)
69 def __del__(self):
70 pass
72 def _writeConf(self, confpath, installroot):
73 conf = "[main]\n"
74 conf += "installroot=%s\n" % installroot
75 conf += "cachedir=/var/cache/yum\n"
76 if self.useplugins:
77 conf += "plugins=1\n"
78 else:
79 conf += "plugins=0\n"
80 conf += "reposdir=\n"
81 conf += "failovermethod=priority\n"
82 conf += "keepcache=1\n"
83 conf += "tsflags=nocontexts\n"
85 f = file(confpath, "w+")
86 f.write(conf)
87 f.close()
89 os.chmod(confpath, 0644)
91 def _cleanupRpmdbLocks(self, installroot):
92 # cleans up temporary files left by bdb so that differing
93 # versions of rpm don't cause problems
94 for f in glob.glob(installroot + "/var/lib/rpm/__db*"):
95 os.unlink(f)
97 def setup(self, confpath, installroot, cacheonly=False):
98 self._writeConf(confpath, installroot)
99 self._cleanupRpmdbLocks(installroot)
100 self.doConfigSetup(fn = confpath, root = installroot)
101 if cacheonly:
102 self.conf.cache = 1
103 else:
104 self.conf.cache = 0
105 self.doTsSetup()
106 self.doRpmDBSetup()
107 self.doRepoSetup()
108 self.doSackSetup()
110 def selectPackage(self, pkg):
111 """Select a given package. Can be specified with name.arch or name*"""
112 return self.install(pattern = pkg)
114 def deselectPackage(self, pkg):
115 """Deselect package. Can be specified as name.arch or name*"""
116 sp = pkg.rsplit(".", 2)
117 txmbrs = []
118 if len(sp) == 2:
119 txmbrs = self.tsInfo.matchNaevr(name=sp[0], arch=sp[1])
121 if len(txmbrs) == 0:
122 exact, match, unmatch = yum.packages.parsePackages(self.pkgSack.returnPackages(), [pkg], casematch=1)
123 for p in exact + match:
124 txmbrs.append(p)
126 if len(txmbrs) > 0:
127 for x in txmbrs:
128 self.tsInfo.remove(x.pkgtup)
129 # we also need to remove from the conditionals
130 # dict so that things don't get pulled back in as a result
131 # of them. yes, this is ugly. conditionals should die.
132 for req, pkgs in self.tsInfo.conditionals.iteritems():
133 if x in pkgs:
134 pkgs.remove(x)
135 self.tsInfo.conditionals[req] = pkgs
136 else:
137 logging.warn("No such package %s to remove" %(pkg,))
139 def selectGroup(self, grp, include = pykickstart.parser.GROUP_DEFAULT):
140 # default to getting mandatory and default packages from a group
141 # unless we have specific options from kickstart
142 package_types = ['mandatory', 'default']
143 if include == pykickstart.parser.GROUP_REQUIRED:
144 package_types.remove('default')
145 elif include == pykickstart.parser.GROUP_ALL:
146 package_types.append('optional')
147 yum.YumBase.selectGroup(self, grp, group_package_types=package_types)
149 def addRepository(self, name, url = None, mirrorlist = None):
150 def _varSubstitute(option):
151 # takes a variable and substitutes like yum configs do
152 option = option.replace("$basearch", rpmUtils.arch.getBaseArch())
153 option = option.replace("$arch", rpmUtils.arch.getCanonArch())
154 # If the url includes $releasever substitute user's value or
155 # current system's version.
156 if option.find("$releasever") > -1:
157 if self.releasever:
158 option = option.replace("$releasever", self.releasever)
159 else:
160 try:
161 option = option.replace("$releasever", yum.config._getsysver("/", "redhat-release"))
162 except yum.Errors.YumBaseError:
163 raise CreatorError("$releasever in repo url, but no releasever set")
164 return option
166 repo = yum.yumRepo.YumRepository(name)
167 if url:
168 repo.baseurl.append(_varSubstitute(url))
169 if mirrorlist:
170 repo.mirrorlist = _varSubstitute(mirrorlist)
171 conf = yum.config.RepoConf()
172 for k, v in conf.iteritems():
173 if v or not hasattr(repo, k):
174 repo.setAttribute(k, v)
175 repo.basecachedir = self.conf.cachedir
176 repo.base_persistdir = self.conf.cachedir
177 repo.failovermethod = "priority"
178 repo.metadata_expire = 0
179 repo.mirrorlist_expire = 0
180 repo.timestamp_check = 0
181 # disable gpg check???
182 repo.gpgcheck = 0
183 repo.enable()
184 repo.setup(self.conf.cache)
185 repo.setCallback(TextProgress())
186 self.repos.add(repo)
187 return repo
189 def installHasFile(self, file):
190 provides_pkg = self.whatProvides(file, None, None)
191 dlpkgs = map(lambda x: x.po, filter(lambda txmbr: txmbr.ts_state in ("i", "u"), self.tsInfo.getMembers()))
192 for p in dlpkgs:
193 for q in provides_pkg:
194 if (p == q):
195 return True
196 return False
199 def runInstall(self):
200 os.environ["HOME"] = "/"
201 try:
202 (res, resmsg) = self.buildTransaction()
203 except yum.Errors.RepoError, e:
204 raise CreatorError("Unable to download from repo : %s" %(e,))
205 # Empty transactions are generally fine, we might be rebuilding an
206 # existing image with no packages added
207 if resmsg and resmsg[0].endswith(" - empty transaction"):
208 return res
209 if res != 2:
210 raise CreatorError("Failed to build transaction : %s" % str.join("\n", resmsg))
212 dlpkgs = map(lambda x: x.po, filter(lambda txmbr: txmbr.ts_state in ("i", "u"), self.tsInfo.getMembers()))
213 self.downloadPkgs(dlpkgs)
214 # FIXME: sigcheck?
216 self.initActionTs()
217 self.populateTs(keepold=0)
218 deps = self.ts.check()
219 if len(deps) != 0:
220 raise CreatorError("Dependency check failed : %s" % "\n".join([str(d) for d in deps]))
221 rc = self.ts.order()
222 if rc != 0:
223 raise CreatorError("ordering packages for installation failedr. rc = %s" % rc)
225 # FIXME: callback should be refactored a little in yum
226 sys.path.append('/usr/share/yum-cli')
227 import yum.misc
228 yum.misc.setup_locale()
229 import callback
230 cb = callback.RPMInstallCallback()
231 cb.tsInfo = self.tsInfo
232 cb.filelog = False
233 ret = self.runTransaction(cb)
234 print ""
235 self._cleanupRpmdbLocks(self.conf.installroot)
236 return ret