upload tizen1.0 source
[kernel/linux-2.6.36.git] / debian / bin / buildcheck.py
1 #!/usr/bin/python
2
3 import sys
4 sys.path.append('debian/lib/python')
5
6 import fnmatch
7 import stat
8
9 from debian_linux.abi import Symbols
10 from debian_linux.config import ConfigCoreDump
11 from debian_linux.debian import *
12
13
14 class CheckAbi(object):
15     class SymbolInfo(object):
16         def __init__(self, symbol, symbol_ref=None):
17             self.symbol = symbol
18             self.symbol_ref = symbol_ref or symbol
19
20         @property
21         def module(self):
22             return self.symbol.module
23
24         @property
25         def name(self):
26             return self.symbol.name
27
28         def write(self, out, ignored):
29             info = []
30             if ignored:
31                 info.append("ignored")
32             for name in ('module', 'version', 'export'):
33                 data = getattr(self.symbol, name)
34                 data_ref = getattr(self.symbol_ref, name)
35                 if data != data_ref:
36                     info.append("%s: %s -> %s" % (name, data_ref, data))
37                 else:
38                     info.append("%s: %s" % (name, data))
39             out.write("%-48s %s\n" % (self.symbol.name, ", ".join(info)))
40
41     def __init__(self, config, dir, arch, featureset, flavour):
42         self.config = config
43         self.arch, self.featureset, self.flavour = arch, featureset, flavour
44
45         self.filename_new = "%s/Module.symvers" % dir
46
47         changelog = Changelog(version=VersionLinux)[0]
48         version = changelog.version.linux_version
49         abiname = self.config['abi',]['abiname']
50         self.filename_ref = "debian/abi/%s-%s/%s_%s_%s" % (version, abiname, arch, featureset, flavour)
51
52     def __call__(self, out):
53         ret = 0
54
55         new = Symbols(open(self.filename_new))
56         try:
57             ref = Symbols(open(self.filename_ref))
58         except IOError:
59             out.write("Can't read ABI reference.  ABI not checked!  Continuing.\n")
60             return 0
61
62         symbols, add, change, remove = self._cmp(ref, new)
63
64         ignore = self._ignore(symbols)
65
66         add_effective = add - ignore
67         change_effective = change - ignore
68         remove_effective = remove - ignore
69
70         if change_effective or remove_effective:
71             out.write("ABI has changed!  Refusing to continue.\n")
72             ret = 1
73         elif change or remove:
74             out.write("ABI has changed but all changes have been ignored.  Continuing.\n")
75         elif add_effective:
76             out.write("New symbols have been added.  Continuing.\n")
77         elif add:
78             out.write("New symbols have been added but have been ignored.  Continuing.\n")
79         else:
80             out.write("No ABI changes.\n")
81
82         if add:
83             out.write("\nAdded symbols:\n")
84             for name in sorted(add):
85                 symbols[name].write(out, name in ignore)
86
87         if change:
88             out.write("\nChanged symbols:\n")
89             for name in sorted(change):
90                 symbols[name].write(out, name in ignore)
91
92         if remove:
93             out.write("\nRemoved symbols:\n")
94             for name in sorted(remove):
95                 symbols[name].write(out, name in ignore)
96
97         return ret
98
99     def _cmp(self, ref, new):
100         ref_names = set(ref.keys())
101         new_names = set(new.keys())
102
103         add = set()
104         change = set()
105         remove = set()
106
107         symbols = {}
108
109         for name in new_names - ref_names:
110             add.add(name)
111             symbols[name] = self.SymbolInfo(new[name])
112
113         for name in ref_names.intersection(new_names):
114             s_ref = ref[name]
115             s_new = new[name]
116
117             if s_ref != s_new:
118                 change.add(name)
119                 symbols[name] = self.SymbolInfo(s_new, s_ref)
120
121         for name in ref_names - new_names:
122             remove.add(name)
123             symbols[name] = self.SymbolInfo(ref[name])
124
125         return symbols, add, change, remove
126
127     def _ignore_pattern(self, pattern):
128         ret = []
129         for i in re.split(r'(\*\*?)', pattern):
130             if i == '*':
131                 ret.append(r'[^!]+')
132             elif i == '**':
133                 ret.append(r'.+')
134             elif i:
135                 ret.append(re.escape(i))
136         return re.compile('^' + ''.join(ret) + '$')
137
138     def _ignore(self, symbols):
139         # TODO: let config merge this lists
140         configs = []
141         configs.append(self.config.get(('abi', self.arch, self.featureset, self.flavour), {}))
142         configs.append(self.config.get(('abi', self.arch, None, self.flavour), {}))
143         configs.append(self.config.get(('abi', self.arch, self.featureset), {}))
144         configs.append(self.config.get(('abi', self.arch), {}))
145         configs.append(self.config.get(('abi', None, self.featureset), {}))
146         configs.append(self.config.get(('abi',), {}))
147
148         ignores = set()
149         for config in configs:
150             ignores.update(config.get('ignore-changes', []))
151
152         filtered = set()
153         for ignore in ignores:
154             type = 'name'
155             if ':' in ignore:
156                 type, ignore = ignore.split(':')
157             if type in ('name', 'module'):
158                 p = self._ignore_pattern(ignore)
159                 for symbol in symbols.itervalues():
160                     if p.match(getattr(symbol, type)):
161                         filtered.add(symbol.name)
162             else:
163                 raise NotImplementedError
164
165         return filtered
166  
167
168 class CheckImage(object):
169     def __init__(self, config, dir, arch, featureset, flavour):
170         self.dir = dir
171         self.arch, self.featureset, self.flavour = arch, featureset, flavour
172
173         self.config_entry_build = config.merge('build', arch, featureset, flavour)
174         self.config_entry_image = config.merge('image', arch, featureset, flavour)
175
176     def __call__(self, out):
177         image = self.config_entry_build.get('image-file')
178
179         if not image:
180             # TODO: Bail out
181             return 0
182
183         image = os.path.join(self.dir, image)
184
185         fail = 0
186
187         fail |= self.check_size(out, image)
188
189         return fail
190
191     def check_size(self, out, image):
192         value = self.config_entry_image.get('check-size')
193
194         if not value:
195             return 0
196
197         value = int(value)
198
199         size = os.stat(image)[stat.ST_SIZE]
200
201         if size > value:
202             out.write('Image too large (%d > %d)!  Refusing to continue.\n' % (size, value))
203             return 1
204
205         out.write('Image fits (%d <= %d).  Continuing.\n' % (size, value))
206         return 0
207
208
209 class Main(object):
210     def __init__(self, dir, arch, featureset, flavour):
211         self.args = dir, arch, featureset, flavour
212
213         self.config = ConfigCoreDump(fp=file("debian/config.defines.dump"))
214
215     def __call__(self):
216         fail = 0
217
218         for c in CheckAbi, CheckImage:
219             fail |= c(self.config, *self.args)(sys.stdout)
220
221         return fail
222
223
224 if __name__ == '__main__':
225     sys.exit(Main(*sys.argv[1:])())