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']
81 set # introduced in 2.4
86 # This is Debian-specific at present
87 def check_modules_installed():
88 # Find which LSB modules are installed on this system
89 output = commands.getoutput("dpkg-query -f '${Version} ${Provides}\n' -W %s 2>/dev/null" % PACKAGES)
94 for line in output.split(os.linesep):
95 version, provides = line.split(' ', 1)
96 version = version.split('-', 1)[0]
97 for pkg in provides.split(','):
98 mob = modnamere.search(pkg)
102 mgroups = mob.groupdict()
103 # If no versioned provides...
104 if mgroups.get('version'):
105 module = '%(module)s-%(version)s-%(arch)s' % mgroups
108 module = mgroups['module']
109 for v in valid_lsb_versions(version, module):
110 mgroups['version'] = v
111 module = '%(module)s-%(version)s-%(arch)s' % mgroups
114 modules = list(modules)
118 longnames = {'v' : 'version', 'o': 'origin', 'a': 'suite',
119 'c' : 'component', 'l': 'label'}
121 def parse_policy_line(data):
123 bits = data.split(',')
125 kv = bit.split('=', 1)
129 retval[longnames[k]] = v
132 def parse_apt_policy():
135 policy = commands.getoutput('LANG=C apt-cache policy 2>/dev/null')
136 for line in policy.split('\n'):
138 m = re.match(r'(\d+)', line)
140 priority = int(m.group(1))
141 if line.startswith('release'):
142 bits = line.split(' ', 1)
144 data.append( (priority, parse_policy_line(bits[1])) )
148 def guess_release_from_apt(origin='Debian', component='main',
149 ignoresuites=('experimental'),
151 releases = parse_apt_policy()
156 # We only care about the specified origin, component, and label
157 releases = [x for x in releases if (
158 x[1].get('origin', '') == origin and
159 x[1].get('component', '') == component and
160 x[1].get('label', '') == label)]
162 # Check again to make sure we didn't wipe out all of the releases
169 # We've sorted the list by descending priority, so the first entry should
170 # be the "main" release in use on the system
172 return releases[0][1]
174 def guess_debian_release():
175 distinfo = {'ID' : 'Debian'}
178 if kern in ('Linux', 'Hurd', 'NetBSD'):
179 distinfo['OS'] = 'GNU/'+kern
180 elif kern == 'FreeBSD':
181 distinfo['OS'] = 'GNU/k'+kern
183 distinfo['OS'] = 'GNU'
185 distinfo['DESCRIPTION'] = '%(ID)s %(OS)s' % distinfo
187 if os.path.exists('/etc/debian_version'):
189 release = open('/etc/debian_version').read().strip()
191 print >> sys.stderr, 'Unable to open /etc/debian_version:', str(msg)
194 if not release[0:1].isalpha():
195 # /etc/debian_version should be numeric
196 codename = lookup_codename(release, 'n/a')
197 distinfo.update({ 'RELEASE' : release, 'CODENAME' : codename })
198 elif release.endswith('/sid'):
199 if release.rstrip('/sid').lower().isalpha() != 'testing':
200 global TESTING_CODENAME
201 TESTING_CODENAME = release.rstrip('/sid')
202 distinfo['RELEASE'] = 'testing/unstable'
204 distinfo['RELEASE'] = release
206 # Only use apt information if we did not get the proper information
207 # from /etc/debian_version or if we don't have a codename
208 # (which will happen if /etc/debian_version does not contain a
209 # number but some text like 'testing/unstable' or 'lenny/sid')
211 # This is slightly faster and less error prone in case the user
212 # has an entry in his /etc/apt/sources.list but has not actually
213 # upgraded the system.
214 rinfo = guess_release_from_apt()
215 if rinfo and not distinfo.get('CODENAME'):
216 release = rinfo.get('version')
218 codename = lookup_codename(release, 'n/a')
220 release = rinfo.get('suite', 'unstable')
221 if release == 'testing':
222 # Would be nice if I didn't have to hardcode this.
223 codename = TESTING_CODENAME
226 distinfo.update({ 'RELEASE' : release, 'CODENAME' : codename })
228 if distinfo.get('RELEASE'):
229 distinfo['DESCRIPTION'] += ' %(RELEASE)s' % distinfo
230 if distinfo.get('CODENAME'):
231 distinfo['DESCRIPTION'] += ' (%(CODENAME)s)' % distinfo
235 # Whatever is guessed above can be overridden in /etc/lsb-release
236 def get_lsb_information():
238 if os.path.exists('/etc/lsb-release'):
240 for line in open('/etc/lsb-release'):
247 var, arg = line.split('=', 1)
248 if var.startswith('DISTRIB_'):
250 if arg.startswith('"') and arg.endswith('"'):
252 if arg: # Ignore empty arguments
255 print >> sys.stderr, 'Unable to open /etc/lsb-release:', str(msg)
259 def get_distro_information():
260 distinfo = guess_debian_release()
261 distinfo.update(get_lsb_information())
265 print get_distro_information()
266 print check_modules_installed()
268 if __name__ == '__main__':