1
"""Handles differences between different distributions
3
Authors: Dave Malcolm <dmalcolm@redhat.com>, Zack Cerza <zcerza@redhat.com>"""
4
__author__ = "Dave Malcolm <dmalcolm@redhat.com>, Zack Cerza <zcerza@redhat.com>"
8
from version import Version
9
from logging import debugLogger as logger
11
class DistributionNotSupportedError(Exception):
13
This distribution is not supported.
15
PATCH_MESSAGE = "Please send patches to dogtail-devel-list@gnome.org"
17
def __init__(self, distro):
21
return self.distro + ". " + DistributionNotSupportedError.PATCH_MESSAGE
23
class PackageNotFoundError(Exception):
25
Error finding the requested package.
34
Class to abstract the details of whatever software package database is in
39
self.localePrefixes = [self.prefix + '/share/locale']
41
def getVersion(self, packageName):
43
Method to get the version of an installed package as a Version
44
instance (or raise an exception if not found)
46
Note: does not know about distributions' internal revision numbers.
48
raise NotImplementedError
50
def getFiles(self, packageName):
52
Method to get a list of filenames owned by the package, or raise an
53
exception if not found.
55
raise NotImplementedError
57
def getMoFiles(self, locale = None):
59
Method to get a list of all .mo files on the system, optionally for a
64
def appendIfMoFile(moFiles, dirName, fNames):
67
if re.match('(.*)\\.mo', fName):
68
moFiles[dirName + '/' + fName] = None
70
for localePrefix in self.localePrefixes:
71
if locale: localePrefix = localePrefix + '/' + locale
72
os.path.walk(localePrefix, appendIfMoFile, moFiles)
76
def getDependencies(self, packageName):
78
Method to get a list of unique package names that this package
79
is dependent on, or raise an exception if the package is not
82
raise NotImplementedError
84
class _RpmPackageDb(PackageDb):
86
PackageDb.__init__(self)
88
def getVersion(self, packageName):
90
ts = rpm.TransactionSet()
91
for header in ts.dbMatch("name", packageName):
92
return Version.fromString(header["version"])
93
raise PackageNotFoundError, packageName
95
def getFiles(self, packageName):
97
ts = rpm.TransactionSet()
98
for header in ts.dbMatch("name", packageName):
99
return header["filenames"]
100
raise PackageNotFoundError, packageName
102
def getDependencies(self, packageName):
104
ts = rpm.TransactionSet()
105
for header in ts.dbMatch("name", packageName):
106
# Simulate a set using a hash (to a dummy value);
107
# sets were only added in Python 2.4
110
# Get the list of requirements; these are
111
# sometimes package names, but can also be
112
# so-names of libraries, and invented virtual
114
for requirement in header[rpm.RPMTAG_REQUIRES]:
115
# Get the name of the package providing
117
for depPackageHeader in ts.dbMatch("provides", requirement):
118
depName = depPackageHeader['name']
119
if depName!=packageName:
120
# Add to the Hash with a dummy value
123
raise PackageNotFoundError, packageName
125
class _AptPackageDb(PackageDb):
127
PackageDb.__init__(self)
130
def getVersion(self, packageName):
134
self.cache = apt_pkg.GetCache()
135
packages = self.cache.Packages
136
for package in packages:
137
if package.Name == packageName:
139
verString = re.match('.*Ver:\'(.*)-.*\' Section:', str(package.CurrentVer)).group(1)
140
return Version.fromString(verString)
141
raise PackageNotFoundError, packageName
143
def getFiles(self, packageName):
145
list = os.popen('dpkg -L %s' % packageName).readlines()
147
raise PackageNotFoundError, packageName
151
if file: files.append(file)
154
def getDependencies(self, packageName):
155
# Simulate a set using a hash (to a dummy value);
156
# sets were only added in Python 2.4
161
self.cache = apt_pkg.GetCache()
162
packages = self.cache.Packages
163
for package in packages:
164
if package.Name == packageName:
165
current = package.CurrentVer
167
raise PackageNotFoundError, packageName
168
depends = current.DependsList
169
list = depends['Depends']
170
for dependency in list:
171
name = dependency[0].TargetPkg.Name
172
# Add to the hash using a dummy value
176
class _UbuntuAptPackageDb(_AptPackageDb):
178
_AptPackageDb.__init__(self)
179
self.localePrefixes.append(self.prefix + '/share/locale-langpack')
181
class _PortagePackageDb(PackageDb):
183
PackageDb.__init__(self)
185
def getVersion(self, packageName):
186
# the portage utilities are almost always going to be in
187
# /usr/lib/portage/pym
189
sys.path.append ('/usr/lib/portage/pym')
191
# FIXME: this takes the first package returned in the list, in the
192
# case that there are slotted packages, and removes the leading
193
# category such as 'sys-apps'
194
gentooPackageName = portage.db["/"]["vartree"].dbapi.match(packageName)[0].split('/')[1];
195
# this removes the distribution specific versioning returning only the
197
upstreamVersion = portage.pkgsplit(gentooPackageName)[1]
198
#print "Version of package is: " + upstreamVersion
199
return Version.fromString(upstreamVersion);
201
class _ConaryPackageDb(PackageDb):
203
PackageDb.__init__(self)
205
def getVersion(self, packageName):
207
from conaryclient import ConaryClient
208
client = ConaryClient()
209
dbVersions = client.db.getTroveVersionList(packageName)
210
if not len(dbVersions):
211
raise PackageNotFoundError, packageName
212
return dbVersions[0].trailingRevision().asString().split("-")[0]
214
# getVersion not implemented because on Solaris multiple modules are installed
215
# in single packages, so it is hard to tell what version number of a specific
217
class _SolarisPackageDb(PackageDb):
219
PackageDb.__init__(self)
221
class JhBuildPackageDb(PackageDb):
223
PackageDb.__init__(self)
225
prefixes.append(os.environ['LD_LIBRARY_PATH'])
226
prefixes.append(os.environ['XDG_CONFIG_DIRS'])
227
prefixes.append(os.environ['PKG_CONFIG_PATH'])
228
self.prefix = os.path.commonprefix(prefixes)
229
self.localePrefixes.append(self.prefix + '/share/locale')
231
def getDependencies(self, packageName):
233
lines = os.popen('jhbuild list ' + packageName).readlines()
236
result[line.strip()] = None
241
Class representing a distribution.
243
Scripts may want to do arbitrary logic based on whichever distro is in use
244
(e.g. handling differences in names of packages, distribution-specific
247
We can either create methods in the Distro class to handle these, or we
248
can use constructs like isinstance(distro, Ubuntu) to handle this. We can
249
even create hierarchies of distro subclasses to handle this kind of thing
250
(could get messy fast though)
253
class Fedora(Distro):
255
self.packageDb = _RpmPackageDb()
260
class Debian(Distro):
262
self.packageDb = _AptPackageDb()
264
class Ubuntu(Debian):
266
self.packageDb = _UbuntuAptPackageDb()
270
self.packageDb = _RpmPackageDb()
272
class Gentoo(Distro):
274
self.packageDb = _PortagePackageDb()
276
class Conary(Distro):
278
self.packageDb = _ConaryPackageDb()
280
class Solaris(Distro):
282
self.packageDb = _SolarisPackageDb()
284
class JHBuild(Distro):
286
self.packageDb = JhBuildPackageDb()
289
logger.log("Detecting distribution:", newline = False)
291
if os.environ.get("CERTIFIED_GNOMIE", "no") == "yes":
293
elif os.path.exists("/etc/SuSE-release"):
295
elif os.path.exists("/etc/fedora-release"):
297
elif os.path.exists("/etc/redhat-release"):
299
elif os.path.exists("/usr/share/doc/ubuntu-minimal"):
301
elif os.path.exists("/etc/debian_version"):
303
elif os.path.exists("/etc/gentoo-release"):
305
elif os.path.exists("/etc/slackware-version"):
306
raise DistributionNotSupportedError("Slackware")
307
elif os.path.exists("/var/lib/conarydb/conarydb"):
309
elif os.path.exists ("/etc/release") and \
310
re.match(".*Solaris", open ("/etc/release").readline()):
313
raise DistributionNotSupportedError("Unknown")
314
logger.log(distro.__class__.__name__)
317
distro = detectDistro()
318
packageDb = distro.packageDb