~ubuntu-branches/ubuntu/quantal/lsb/quantal-proposed

« back to all changes in this revision

Viewing changes to lsb_release.py

  • Committer: Bazaar Package Importer
  • Author(s): Steve Langasek, Jeff Licquia
  • Date: 2009-06-02 20:20:07 UTC
  • mfrom: (1.1.3 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090602202007-yrfljcu970v0kcqd
Tags: 4.0-0ubuntu1
* Merge from Debian unstable, remaining changes:
  - lsb-base-logging-ubuntu.sh: change log_{success,warning,failure}_msg()
    to use usplash_write "TEXT" instead of "STATUS" to avoid unreadable
    line-wrapping when using usplash in verbose mode.
  - Don't conflict with python (>= 2.6).
  - Depend on postfix rather than exim4 as preferred mail-transport-agent
    alternative.
  - Depend on libgl1-mesa-glx rather than libgl1-mesa as preferred libgl1
    alternative.
  - Since /etc/lsb-release overrides detected information, there's no
    need to try and detect that information if lsb-release contains
    everything we need.  This saves us calling the hugely expensive
    apt-cache.
  - Add Ubuntu logging functions.

[ Jeff Licquia ]
* Upgrade to support LSB 4.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python
 
2
 
 
3
# LSB release detection module for Debian
 
4
# (C) 2005-09 Chris Lawrence <lawrencc@debian.org>
 
5
 
 
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.
 
9
 
 
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.
 
14
 
 
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
 
18
#    02111-1307, USA.
 
19
 
 
20
import sys
 
21
import commands
 
22
import os
 
23
import re
 
24
 
 
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 = {
 
29
    '1.1' : 'buzz',
 
30
    '1.2' : 'rex',
 
31
    '1.3' : 'bo',
 
32
    '2.0' : 'hamm',
 
33
    '2.1' : 'slink',
 
34
    '2.2' : 'potato',
 
35
    '3.0' : 'woody',
 
36
    '3.1' : 'sarge',
 
37
    '4.0' : 'etch',
 
38
    '5.0' : 'lenny',
 
39
    }
 
40
 
 
41
TESTING_CODENAME = 'unknown.new.testing'
 
42
 
 
43
def lookup_codename(release, unknown=None):
 
44
    m = re.match(r'(\d+)\.(\d+)(r(\d+))?', release)
 
45
    if not m:
 
46
        return unknown
 
47
 
 
48
    shortrelease = '%s.%s' % m.group(1,2)
 
49
    return RELEASE_CODENAME_LOOKUP.get(shortrelease, unknown)
 
50
 
 
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'
 
53
 
 
54
modnamere = re.compile(r'lsb-(?P<module>[a-z0-9]+)-(?P<arch>[^ ]+)(?: \(= (?P<version>[0-9.]+)\))?')
 
55
 
 
56
def valid_lsb_versions(version, module):
 
57
    # If a module is ever released that only appears in >= version, deal
 
58
    # with that here
 
59
    if version == '3.0':
 
60
        return ['2.0', '3.0']
 
61
    elif version == '3.1':
 
62
        if module in ('desktop', 'qt4'):
 
63
            return ['3.1']
 
64
        else:
 
65
            return ['2.0', '3.0', '3.1']
 
66
    elif version == '3.2':
 
67
        if module == 'desktop':
 
68
            return ['3.1', '3.2']
 
69
        elif module == 'qt4':
 
70
            return ['3.1']
 
71
        elif module in ('printing', 'languages', 'multimedia'):
 
72
            return ['3.2']
 
73
        elif module == 'cxx':
 
74
            return ['3.0', '3.1', '3.2']
 
75
        else:
 
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']
 
80
        elif module == 'qt4':
 
81
            return ['3.1']
 
82
        elif module in ('printing', 'languages', 'multimedia'):
 
83
            return ['3.2', '4.0']
 
84
        elif module == 'security':
 
85
            return ['4.0']
 
86
        elif module == 'cxx':
 
87
            return ['3.0', '3.1', '3.2', '4.0']
 
88
        else:
 
89
            return ['2.0', '3.0', '3.1', '3.2', '4.0']
 
90
 
 
91
    return [version]
 
92
 
 
93
try:
 
94
    set # introduced in 2.4
 
95
except NameError:
 
96
    import sets
 
97
    set = sets.Set
 
98
 
 
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)
 
103
    if not output:
 
104
        return []
 
105
 
 
106
    modules = set()
 
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)
 
112
            if not mob:
 
113
                continue
 
114
 
 
115
            mgroups = mob.groupdict()
 
116
            # If no versioned provides...
 
117
            if mgroups.get('version'):
 
118
                module = '%(module)s-%(version)s-%(arch)s' % mgroups
 
119
                modules.add(module)
 
120
            else:
 
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
 
125
                    modules.add(module)
 
126
 
 
127
    modules = list(modules)
 
128
    modules.sort()
 
129
    return modules
 
130
 
 
131
longnames = {'v' : 'version', 'o': 'origin', 'a': 'suite',
 
132
             'c' : 'component', 'l': 'label'}
 
133
 
 
134
def parse_policy_line(data):
 
135
    retval = {}
 
136
    bits = data.split(',')
 
137
    for bit in bits:
 
138
        kv = bit.split('=', 1)
 
139
        if len(kv) > 1:
 
140
            k, v = kv[:2]
 
141
            if k in longnames:
 
142
                retval[longnames[k]] = v
 
143
    return retval
 
144
 
 
145
def parse_apt_policy():
 
146
    data = []
 
147
    
 
148
    policy = commands.getoutput('apt-cache policy 2>/dev/null')
 
149
    for line in policy.split('\n'):
 
150
        line = line.strip()
 
151
        m = re.match(r'(\d+)', line)
 
152
        if m:
 
153
            priority = int(m.group(1))
 
154
        if line.startswith('release'):
 
155
            bits = line.split(' ', 1)
 
156
            if len(bits) > 1:
 
157
                data.append( (priority, parse_policy_line(bits[1])) )
 
158
 
 
159
    return data
 
160
 
 
161
def guess_release_from_apt(origin='Debian', component='main',
 
162
                           ignoresuites=('experimental'),
 
163
                           label='Debian'):
 
164
    releases = parse_apt_policy()
 
165
 
 
166
    if not releases:
 
167
        return None
 
168
 
 
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)]
 
174
 
 
175
    # Check again to make sure we didn't wipe out all of the releases
 
176
    if not releases:
 
177
        return None
 
178
    
 
179
    releases.sort()
 
180
    releases.reverse()
 
181
 
 
182
    # We've sorted the list by descending priority, so the first entry should
 
183
    # be the "main" release in use on the system
 
184
 
 
185
    return releases[0][1]
 
186
 
 
187
def guess_debian_release():
 
188
    distinfo = {'ID' : 'Debian'}
 
189
 
 
190
    kern = os.uname()[0]
 
191
    if kern in ('Linux', 'Hurd', 'NetBSD'):
 
192
        distinfo['OS'] = 'GNU/'+kern
 
193
    elif kern == 'FreeBSD':
 
194
        distinfo['OS'] = 'GNU/k'+kern
 
195
    else:
 
196
        distinfo['OS'] = 'GNU'
 
197
 
 
198
    distinfo['DESCRIPTION'] = '%(ID)s %(OS)s' % distinfo
 
199
 
 
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'
 
211
        else:
 
212
            distinfo['RELEASE'] = release
 
213
 
 
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')
 
218
    #
 
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')
 
225
        if release:
 
226
            codename = lookup_codename(release, 'n/a')
 
227
        else:
 
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
 
232
            else:
 
233
                codename = 'sid'
 
234
        distinfo.update({ 'RELEASE' : release, 'CODENAME' : codename })
 
235
 
 
236
    if distinfo.get('RELEASE'):
 
237
        distinfo['DESCRIPTION'] += ' %(RELEASE)s' % distinfo
 
238
    if distinfo.get('CODENAME'):
 
239
        distinfo['DESCRIPTION'] += ' (%(CODENAME)s)' % distinfo
 
240
 
 
241
    return distinfo
 
242
 
 
243
# Whatever is guessed above can be overridden in /etc/lsb-release
 
244
def get_lsb_information():
 
245
    distinfo = {}
 
246
    if os.path.exists('/etc/lsb-release'):
 
247
        for line in open('/etc/lsb-release'):
 
248
            line = line.strip()
 
249
            if not line:
 
250
                continue
 
251
            # Skip invalid lines
 
252
            if not '=' in line:
 
253
                continue
 
254
            var, arg = line.split('=', 1)
 
255
            if var.startswith('DISTRIB_'):
 
256
                var = var[8:]
 
257
                if arg.startswith('"') and arg.endswith('"'):
 
258
                    arg = arg[1:-1]
 
259
                distinfo[var] = arg
 
260
    return distinfo
 
261
 
 
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)
 
269
            return distinfo
 
270
    else:
 
271
        return lsbinfo
 
272
 
 
273
def test():
 
274
    print get_distro_information()
 
275
    print check_modules_installed()
 
276
 
 
277
if __name__ == '__main__':
 
278
    test()