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.
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
)
39 def start(self
, filename
, url
, *args
, **kwargs
):
40 self
.emit(logging
.INFO
, "Retrieving %s " % (url
,))
42 def update(self
, *args
):
45 self
.emit(logging
.INFO
, "...OK\n")
47 class LiveCDYum(yum
.YumBase
):
48 def __init__(self
, releasever
=None, useplugins
=False):
50 releasever = optional value to use in replacing $releasever in repos
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
63 os
.unlink(self
.conf
.installroot
+ "/yum.conf")
66 yum
.YumBase
.close(self
)
71 def _writeConf(self
, confpath
, installroot
):
73 conf
+= "installroot=%s\n" % installroot
74 conf
+= "cachedir=/var/cache/yum\n"
80 conf
+= "failovermethod=priority\n"
81 conf
+= "keepcache=1\n"
82 conf
+= "tsflags=nocontexts\n"
84 f
= file(confpath
, "w+")
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*"):
96 def setup(self
, confpath
, installroot
, cacheonly
=False):
97 self
._writeConf
(confpath
, installroot
)
98 self
._cleanupRpmdbLocks
(installroot
)
99 self
.doConfigSetup(fn
= confpath
, root
= installroot
)
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)
118 txmbrs
= self
.tsInfo
.matchNaevr(name
=sp
[0], arch
=sp
[1])
121 exact
, match
, unmatch
= yum
.packages
.parsePackages(self
.pkgSack
.returnPackages(), [pkg
], casematch
=1)
122 for p
in exact
+ match
:
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():
134 self
.tsInfo
.conditionals
[req
] = pkgs
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:
157 option
= option
.replace("$releasever", self
.releasever
)
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")
165 repo
= yum
.yumRepo
.YumRepository(name
)
167 repo
.baseurl
.append(_varSubstitute(url
))
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???
183 repo
.setup(self
.conf
.cache
)
184 repo
.setCallback(TextProgress())
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()))
192 for q
in provides_pkg
:
198 def runInstall(self
):
199 os
.environ
["HOME"] = "/"
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"):
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
)
216 self
.populateTs(keepold
=0)
217 deps
= self
.ts
.check()
219 raise CreatorError("Dependency check failed!")
222 raise CreatorError("ordering packages for installation failed!")
224 # FIXME: callback should be refactored a little in yum
225 sys
.path
.append('/usr/share/yum-cli')
227 yum
.misc
.setup_locale()
229 cb
= callback
.RPMInstallCallback()
230 cb
.tsInfo
= self
.tsInfo
232 ret
= self
.runTransaction(cb
)
234 self
._cleanupRpmdbLocks
(self
.conf
.installroot
)