~ubuntu-langpack/langpack-o-matic/main

« back to all changes in this revision

Viewing changes to lib/macros.py

  • Committer: Sebastien Bacher
  • Date: 2021-11-22 16:04:05 UTC
  • mfrom: (594.2.1 langpack-o-matic)
  • Revision ID: seb128@ubuntu.com-20211122160405-17hx41i98tvg459q
The repository has been moved to git

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
'''macros.py: Generate macro values from configuration values and provide
2
 
substitution functions.
3
 
 
4
 
The following macros are available:
5
 
 
6
 
  LCODE CCODE PCCODE PKGNAME PKGCODE LANG COUNTRY PCOUNTRY DISTRO RELEASE UPLOADER
7
 
  DATE TIMESTAMP CLASS CLASSNAME CLASSNAMESPACE CLASSDEPENDS
8
 
  BASERECOMMENDS
9
 
'''
10
 
 
11
 
import time
12
 
import re
13
 
import os
14
 
from decimal import Decimal
15
 
 
16
 
 
17
 
def _file_map(file, key, sep=None):
18
 
    '''Look up key in given file ("key value" lines).
19
 
 
20
 
    Throw KeyError if key was not found.
21
 
    '''
22
 
    val = None
23
 
    with open(file) as f:
24
 
        for l in f:
25
 
            try:
26
 
                (k, v) = l.split(sep, 1)
27
 
            except ValueError:
28
 
                continue
29
 
            # sort out comments
30
 
            if k.find('#') >= 0 or v.find('#') >= 0:
31
 
                continue
32
 
            if k == key:
33
 
                val = v.strip()
34
 
    if val is None:
35
 
        raise KeyError('Key %s not found in %s' % (key, file))
36
 
    return val
37
 
 
38
 
 
39
 
class LangpackMacros:
40
 
    def __init__(self, distro, locale, cls, release, version):
41
 
        '''Initialize values of macros.
42
 
 
43
 
        This uses information from maps/, config/, some hardcoded aggregate
44
 
        strings (such as package names), and some external input:
45
 
 
46
 
        - locale: Standard locale representation (e. g. pt_BR.UTF-8)
47
 
        - cls: empty, or valid name in maps/classnames
48
 
        - release: distrorelease name (in maps/releaseversions-$distro)
49
 
        - version: export date of language pack tarball, will be used in
50
 
          version numbers
51
 
        '''
52
 
        self.macros = {}
53
 
        # chop .* and @* suffixes to get encoding-agnostic locale
54
 
        try:
55
 
            self['LOCALE'] = (locale.split('.')[0]).split('@')[0]
56
 
        except KeyError:
57
 
            self['LOCALE'] = locale
58
 
 
59
 
        # class
60
 
        self['CLASS'] = cls
61
 
        if cls:
62
 
            self['CLASSNAME'] = _file_map('maps/classnames', cls)
63
 
            self['CLASSNAMESPACE'] = self['CLASSNAME'] + ' '
64
 
 
65
 
        # language and country
66
 
        try:
67
 
            (self['LCODE'], self['CCODE']) = self['LOCALE'].split('_')
68
 
            self['PCCODE'] = '(%s)' % self['CCODE']
69
 
            try:
70
 
                self['COUNTRY'] = _file_map('maps/countries', self['CCODE'], ':')
71
 
                self['PCOUNTRY'] = '(%s)' % self['COUNTRY']
72
 
            except KeyError:
73
 
                self['COUNTRY'] = ''
74
 
                self['PCOUNTRY'] = ''
75
 
        except ValueError:
76
 
            self['LCODE'] = self['LOCALE']
77
 
 
78
 
        if not self['LCODE']:
79
 
            raise Exception('Internal error: LCODE is empty')
80
 
 
81
 
        # other variables
82
 
        self['DATE'] = time.strftime('%a, %d %b %Y %H:%M:%S +0000')
83
 
        self['DISTRO'] = distro
84
 
        self['RELEASE'] = release
85
 
        self['RELEASEVERSION'] = _file_map('maps/releaseversions-' + distro, release.split('-')[0])
86
 
        self['TIMESTAMP'] = version
87
 
 
88
 
        # package name
89
 
        if Decimal(self['RELEASEVERSION']) >= Decimal('9.10'):
90
 
            try:
91
 
                self['PKGCODE'] = _file_map('maps/locale2pkgname', '%s-%s' % (self['LCODE'], self['CCODE'].lower()), ':')
92
 
                self['LANG'] = _file_map('maps/variants', '%s' % self['PKGCODE'], ':')
93
 
                if self['CLASS']:
94
 
                    self['PKGNAME'] = '%s-%s' % (self['CLASS'], self['PKGCODE'])
95
 
                else:
96
 
                    self['PKGNAME'] = self['PKGCODE']
97
 
            except KeyError:
98
 
                self['PKGCODE'] = self['LCODE']
99
 
                try:
100
 
                    self['LANG'] = _file_map('maps/variants', '%s' % self['PKGCODE'], ':')
101
 
                except KeyError:
102
 
                    self['LANG'] = _file_map('maps/languages', self['LCODE'], ':')
103
 
                if self['CLASS']:
104
 
                    self['PKGNAME'] = '%s-%s' % (self['CLASS'], self['LCODE'])
105
 
                else:
106
 
                    self['PKGNAME'] = self['LCODE']
107
 
        else:
108
 
            self['PKGCODE'] = self['LCODE']
109
 
            self['LANG'] = _file_map('maps/languages', self['LCODE'], ':')
110
 
            if self['CLASS']:
111
 
                self['PKGNAME'] = '%s-%s' % (self['CLASS'], self['LCODE'])
112
 
            else:
113
 
                self['PKGNAME'] = self['LCODE']
114
 
 
115
 
        # %CLASS% packages should depend on corresponding generic one
116
 
        if cls != '':
117
 
            self['CLASSDEPENDS'] = ', language-pack-%s' % self['PKGCODE']
118
 
        else:
119
 
            self['CLASSDEPENDS'] = ''
120
 
 
121
 
        # configuration files
122
 
        f = open('config/UPLOADER')
123
 
        self['UPLOADER'] = f.read().strip()
124
 
        f.close()
125
 
 
126
 
        # conflicts / replaces for zh langpack-split
127
 
        if self['PKGCODE'] == 'zh-hans' or self['PKGCODE'] == 'zh-hant':
128
 
            if cls != '':
129
 
                self['OBSOLETESZHBASE'] = ', language-pack-%s-zh-base (<< 1:9.10)' % self['CLASS']
130
 
                self['OBSOLETESZH'] = ', language-pack-%s-zh (<< 1:9.10)' % self['CLASS']
131
 
                self['CONFLICTSZH'] = '\nConflicts: language-pack-%s-zh (<< 1:9.10)' % self['CLASS']
132
 
            else:
133
 
                self['OBSOLETESZHBASE'] = ', language-pack-zh-base (<< 1:9.10)'
134
 
                self['OBSOLETESZH'] = ', language-pack-zh (<< 1:9.10)'
135
 
                self['CONFLICTSZH'] = '\nConflicts: language-pack-zh (<< 1:9.10)'
136
 
        else:
137
 
            self['OBSOLETESZHBASE'] = ''
138
 
            self['OBSOLETESZH'] = ''
139
 
            self['CONFLICTSZH'] = ''
140
 
 
141
 
    def __getitem__(self, item):
142
 
        # return empty string as default
143
 
        return self.macros.get(item, '')
144
 
 
145
 
    def __setitem__(self, item, value):
146
 
        self.macros[item] = value
147
 
 
148
 
    def __contains__(self, item):
149
 
        return self.macros.__contains__(item)
150
 
 
151
 
    def subst_string(self, s):
152
 
        '''Substitute all macros in given string.'''
153
 
 
154
 
        re_macro = re.compile('%([A-Z]+)%')
155
 
        while 1:
156
 
            m = re_macro.search(s)
157
 
            if m:
158
 
                s = s[:m.start(1) - 1] + self[m.group(1)] + s[m.end(1) + 1:]
159
 
            else:
160
 
                break
161
 
 
162
 
        return s
163
 
 
164
 
    def subst_file(self, file):
165
 
        '''Substitute all macros in given file.'''
166
 
 
167
 
        f = open(file)
168
 
        s = f.read()
169
 
        f.close()
170
 
        f = open(file, 'w')
171
 
        f.write(self.subst_string(s))
172
 
        f.close()
173
 
 
174
 
    def subst_tree(self, root):
175
 
        '''Substitute all macros in given directory tree.'''
176
 
 
177
 
        for path, dirs, files in os.walk(root):
178
 
            for f in files:
179
 
                self.subst_file(os.path.join(root, path, f))
180
 
 
181
 
 
182
 
if __name__ == '__main__':
183
 
    import tempfile
184
 
    import unittest
185
 
 
186
 
    class _T(unittest.TestCase):
187
 
        def test_lang(self):
188
 
            '''language, no country, no class'''
189
 
 
190
 
            l = LangpackMacros('ubuntu', 'de', '', 'precise', '3.14')
191
 
            self.assertEqual(l.subst_string('%LCODE% "%CCODE%" language-pack-%PKGNAME%'),
192
 
                             'de "" language-pack-de')
193
 
            self.assertEqual(l.subst_string('-%PCCODE%-%PKGCODE%-%LANG%-%RELEASE%'),
194
 
                             '--de-German-precise')
195
 
            self.assertEqual(l.subst_string('-%COUNTRY%-%PCOUNTRY%-'), '---')
196
 
            self.assertNotEqual(l.subst_string('%UPLOADER%'), '')
197
 
            self.assertTrue(len(l.subst_string('%DATE%')) > 10)
198
 
            self.assertEqual(l.subst_string('-%CLASS%-%CLASSNAME%-%CLASSNAMESPACE%-'), '----')
199
 
            self.assertEqual(l.subst_string('%CLASSDEPENDS%'), '')
200
 
            self.assertEqual(l.subst_string('%DISTRO%'), 'ubuntu')
201
 
 
202
 
        def test_lang_country(self):
203
 
            '''language, country, no class'''
204
 
 
205
 
            for locale in ('de_CH', 'de_CH.utf8'):
206
 
                l = LangpackMacros('ubuntu', locale, '', 'precise', '3.14')
207
 
                self.assertEqual(l.subst_string('%LCODE% "%CCODE%" language-pack-%PKGNAME%'),
208
 
                                 'de "CH" language-pack-de')
209
 
                self.assertEqual(l.subst_string('-%PCCODE%-%PKGCODE%-%LANG%-%RELEASE%'),
210
 
                                 '-(CH)-de-German-precise')
211
 
                self.assertEqual(l.subst_string('-%COUNTRY%-%PCOUNTRY%-'), '-Switzerland-(Switzerland)-')
212
 
                self.assertNotEqual(l.subst_string('%UPLOADER%'), '')
213
 
                self.assertTrue(len(l.subst_string('%DATE%')) > 10)
214
 
                self.assertEqual(l.subst_string('-%CLASS%-%CLASSNAME%-%CLASSNAMESPACE%-'), '----')
215
 
                self.assertEqual(l.subst_string('%CLASSDEPENDS%'), '')
216
 
 
217
 
        def test_lang_country_class(self):
218
 
            '''language, country, class'''
219
 
 
220
 
            for locale in ('de_CH', 'de_CH.utf8'):
221
 
                l = LangpackMacros('ubuntu', locale, 'gnome', 'trusty', '3.14')
222
 
                self.assertEqual(l.subst_string('%LCODE% "%CCODE%" language-pack-%PKGNAME%'),
223
 
                                 'de "CH" language-pack-gnome-de')
224
 
                self.assertEqual(l.subst_string('-%PCCODE%-%PKGCODE%-%LANG%-%RELEASE%'),
225
 
                                 '-(CH)-de-German-trusty')
226
 
                self.assertEqual(l.subst_string('-%COUNTRY%-%PCOUNTRY%-'), '-Switzerland-(Switzerland)-')
227
 
                self.assertNotEqual(l.subst_string('%UPLOADER%'), '')
228
 
                self.assertTrue(len(l.subst_string('%DATE%')) > 10)
229
 
                self.assertEqual(l.subst_string('-%CLASS%-%CLASSNAME%-%CLASSNAMESPACE%-'),
230
 
                                 '-gnome-GNOME-GNOME -')
231
 
                self.assertEqual(l.subst_string('%CLASSDEPENDS%'), ', language-pack-de')
232
 
                self.assertEqual(l.subst_string('%BASERECOMMENDS%'), '')
233
 
 
234
 
        def test_zh_split(self):
235
 
            '''Chinese split (PKGCODE)'''
236
 
 
237
 
            l = LangpackMacros('ubuntu', 'zh_CN', 'kde', 'trusty', '3.14')
238
 
            self.assertEqual(l.subst_string('%LCODE% "%CCODE%" language-pack-%PKGNAME%'),
239
 
                             'zh "CN" language-pack-kde-zh-hans')
240
 
            self.assertEqual(l.subst_string('-%PCCODE%-%PKGCODE%-%LANG%-%RELEASE%'),
241
 
                             '-(CN)-zh-hans-Simplified Chinese-trusty')
242
 
            self.assertEqual(l.subst_string('-%COUNTRY%-%PCOUNTRY%-'), '-China-(China)-')
243
 
            self.assertNotEqual(l.subst_string('%UPLOADER%'), '')
244
 
            self.assertTrue(len(l.subst_string('%DATE%')) > 10)
245
 
            self.assertEqual(l.subst_string('-%CLASS%-%CLASSNAME%-%CLASSNAMESPACE%-'),
246
 
                             '-kde-KDE-KDE -')
247
 
            self.assertEqual(l.subst_string('%CLASSDEPENDS%'), ', language-pack-zh-hans')
248
 
 
249
 
        def test_subst_file(self):
250
 
            '''subst_file()'''
251
 
 
252
 
            l = LangpackMacros('ubuntu', 'de', '', 'precise', '3.14')
253
 
            (fd, fname) = tempfile.mkstemp()
254
 
            try:
255
 
                os.close(fd)
256
 
                f = open(fname, 'w')
257
 
                f.write('%LCODE% "%CCODE%" language-pack-%PKGNAME%')
258
 
                f.close()
259
 
                l.subst_file(fname)
260
 
                with open(fname) as f:
261
 
                    self.assertEqual(f.read(), 'de "" language-pack-de')
262
 
            finally:
263
 
                os.unlink(fname)
264
 
 
265
 
        def test_unknown_broken(self):
266
 
            '''unknown macros and corner cases'''
267
 
 
268
 
            l = LangpackMacros('ubuntu', 'de', '', 'precise', '3.14')
269
 
            self.assertEqual(l.subst_string('%LCODE%% %%LANG% %%LCODE%% %LCODE LCODE%'),
270
 
                             'de% %German %de% %LCODE LCODE%')
271
 
            self.assertEqual(l.subst_string('%LCODE% %MOO% %LCODE%'),
272
 
                             'de  de')
273
 
 
274
 
    unittest.main()