3
# LSB release detection module for Debian
4
# (C) 2005-09 Chris Lawrence <lawrencc@debian.org>
6
# This package 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 dated June, 1991.
10
# This package 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 General Public License for more details.
15
# You should have received a copy of the GNU General Public License
16
# along with this package; if not, write to the Free Software
17
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
25
# XXX: Update as needed
26
# This should really be included in apt-cache policy output... it is already
27
# in the Release file...
28
RELEASE_CODENAME_LOOKUP = {
41
TESTING_CODENAME = 'unknown.new.testing'
43
def lookup_codename(release, unknown=None):
44
m = re.match(r'(\d+)\.(\d+)(r(\d+))?', release)
48
shortrelease = '%s.%s' % m.group(1,2)
49
return RELEASE_CODENAME_LOOKUP.get(shortrelease, unknown)
51
# LSB compliance packages... may grow eventually
52
PACKAGES = 'lsb-core lsb-cxx lsb-graphics lsb-desktop lsb-qt4 lsb-languages lsb-multimedia lsb-printing'
54
modnamere = re.compile(r'lsb-(?P<module>[a-z0-9]+)-(?P<arch>[^ ]+)(?: \(= (?P<version>[0-9.]+)\))?')
56
def valid_lsb_versions(version, module):
57
# If a module is ever released that only appears in >= version, deal
61
elif version == '3.1':
62
if module in ('desktop', 'qt4'):
65
return ['2.0', '3.0', '3.1']
66
elif version == '3.2':
67
if module == 'desktop':
71
elif module in ('printing', 'languages', 'multimedia'):
74
return ['3.0', '3.1', '3.2']
76
return ['2.0', '3.0', '3.1', '3.2']
77
elif version == '4.0':
78
if module == 'desktop':
79
return ['3.1', '3.2', '4.0']
82
elif module in ('printing', 'languages', 'multimedia'):
84
elif module == 'security':
87
return ['3.0', '3.1', '3.2', '4.0']
89
return ['2.0', '3.0', '3.1', '3.2', '4.0']
94
set # introduced in 2.4
99
# This is Debian-specific at present
100
def check_modules_installed():
101
# Find which LSB modules are installed on this system
102
output = commands.getoutput("dpkg-query -f '${Version} ${Provides}\n' -W %s 2>/dev/null" % PACKAGES)
107
for line in output.split(os.linesep):
108
version, provides = line.split(' ', 1)
109
version = version.split('-', 1)[0]
110
for pkg in provides.split(','):
111
mob = modnamere.search(pkg)
115
mgroups = mob.groupdict()
116
# If no versioned provides...
117
if mgroups.get('version'):
118
module = '%(module)s-%(version)s-%(arch)s' % mgroups
121
module = mgroups['module']
122
for v in valid_lsb_versions(version, module):
123
mgroups['version'] = v
124
module = '%(module)s-%(version)s-%(arch)s' % mgroups
127
modules = list(modules)
131
longnames = {'v' : 'version', 'o': 'origin', 'a': 'suite',
132
'c' : 'component', 'l': 'label'}
134
def parse_policy_line(data):
136
bits = data.split(',')
138
kv = bit.split('=', 1)
142
retval[longnames[k]] = v
145
def parse_apt_policy():
148
policy = commands.getoutput('apt-cache policy 2>/dev/null')
149
for line in policy.split('\n'):
151
m = re.match(r'(\d+)', line)
153
priority = int(m.group(1))
154
if line.startswith('release'):
155
bits = line.split(' ', 1)
157
data.append( (priority, parse_policy_line(bits[1])) )
161
def guess_release_from_apt(origin='Debian', component='main',
162
ignoresuites=('experimental'),
164
releases = parse_apt_policy()
169
# We only care about the specified origin, component, and label
170
releases = [x for x in releases if (
171
x[1].get('origin', '') == origin and
172
x[1].get('component', '') == component and
173
x[1].get('label', '') == label)]
175
# Check again to make sure we didn't wipe out all of the releases
182
# We've sorted the list by descending priority, so the first entry should
183
# be the "main" release in use on the system
185
return releases[0][1]
187
def guess_debian_release():
188
distinfo = {'ID' : 'Debian'}
191
if kern in ('Linux', 'Hurd', 'NetBSD'):
192
distinfo['OS'] = 'GNU/'+kern
193
elif kern == 'FreeBSD':
194
distinfo['OS'] = 'GNU/k'+kern
196
distinfo['OS'] = 'GNU'
198
distinfo['DESCRIPTION'] = '%(ID)s %(OS)s' % distinfo
200
if os.path.exists('/etc/debian_version'):
201
release = open('/etc/debian_version').read().strip()
202
if not release[0:1].isalpha():
203
# /etc/debian_version should be numeric
204
codename = lookup_codename(release, 'n/a')
205
distinfo.update({ 'RELEASE' : release, 'CODENAME' : codename })
206
elif release.endswith('/sid'):
207
if release.rstrip('/sid').lower().isalpha() != 'testing':
208
global TESTING_CODENAME
209
TESTING_CODENAME = release.rstrip('/sid')
210
distinfo['RELEASE'] = 'testing/unstable'
212
distinfo['RELEASE'] = release
214
# Only use apt information if we did not get the proper information
215
# from /etc/debian_version or if we don't have a codename
216
# (which will happen if /etc/debian_version does not contain a
217
# number but some text like 'testing/unstable' or 'lenny/sid')
219
# This is slightly faster and less error prone in case the user
220
# has an entry in his /etc/apt/sources.list but has not actually
221
# upgraded the system.
222
rinfo = guess_release_from_apt()
223
if rinfo and not distinfo.get('CODENAME'):
224
release = rinfo.get('version')
226
codename = lookup_codename(release, 'n/a')
228
release = rinfo.get('suite', 'unstable')
229
if release == 'testing':
230
# Would be nice if I didn't have to hardcode this.
231
codename = TESTING_CODENAME
234
distinfo.update({ 'RELEASE' : release, 'CODENAME' : codename })
236
if distinfo.get('RELEASE'):
237
distinfo['DESCRIPTION'] += ' %(RELEASE)s' % distinfo
238
if distinfo.get('CODENAME'):
239
distinfo['DESCRIPTION'] += ' (%(CODENAME)s)' % distinfo
243
# Whatever is guessed above can be overridden in /etc/lsb-release
244
def get_lsb_information():
246
if os.path.exists('/etc/lsb-release'):
247
for line in open('/etc/lsb-release'):
254
var, arg = line.split('=', 1)
255
if var.startswith('DISTRIB_'):
257
if arg.startswith('"') and arg.endswith('"'):
262
def get_distro_information():
263
lsbinfo = get_lsb_information()
264
# OS is only used inside guess_debian_release anyway
265
for key in ('ID', 'RELEASE', 'CODENAME', 'DESCRIPTION',):
266
if key not in lsbinfo:
267
distinfo = guess_debian_release()
268
distinfo.update(lsbinfo)
274
print get_distro_information()
275
print check_modules_installed()
277
if __name__ == '__main__':