summaryrefslogtreecommitdiffstats
path: root/meta/lib
diff options
context:
space:
mode:
Diffstat (limited to 'meta/lib')
-rw-r--r--meta/lib/oe/buildhistory_analysis.py89
1 files changed, 64 insertions, 25 deletions
diff --git a/meta/lib/oe/buildhistory_analysis.py b/meta/lib/oe/buildhistory_analysis.py
index 627467c26e..103cfb41b1 100644
--- a/meta/lib/oe/buildhistory_analysis.py
+++ b/meta/lib/oe/buildhistory_analysis.py
@@ -23,22 +23,41 @@ monitor_fields = ['RDEPENDS', 'RRECOMMENDS', 'PACKAGES', 'FILELIST', 'PKGSIZE',
23monitor_numeric_threshold = 20 23monitor_numeric_threshold = 20
24# Image files to monitor (note that image-info.txt is handled separately) 24# Image files to monitor (note that image-info.txt is handled separately)
25img_monitor_files = ['installed-package-names.txt', 'files-in-image.txt'] 25img_monitor_files = ['installed-package-names.txt', 'files-in-image.txt']
26# Related context fields for reporting (note: PE, PV & PR are always reported for monitored package fields)
27related_fields = {}
28related_fields['RDEPENDS'] = ['DEPENDS']
29related_fields['RRECOMMENDS'] = ['DEPENDS']
30related_fields['FILELIST'] = ['FILES']
31related_fields['PKGSIZE'] = ['FILELIST']
32related_fields['files-in-image.txt'] = ['installed-package-names.txt', 'USER_CLASSES', 'IMAGE_CLASSES', 'ROOTFS_POSTPROCESS_COMMAND', 'IMAGE_POSTPROCESS_COMMAND']
33related_fields['installed-package-names.txt'] = ['IMAGE_FEATURES', 'IMAGE_LINGUAS', 'IMAGE_INSTALL', 'BAD_RECOMMENDATIONS']
34
26 35
27class ChangeRecord: 36class ChangeRecord:
28 def __init__(self, path, fieldname, oldvalue, newvalue): 37 def __init__(self, path, fieldname, oldvalue, newvalue, monitored):
29 self.path = path 38 self.path = path
30 self.fieldname = fieldname 39 self.fieldname = fieldname
31 self.oldvalue = oldvalue 40 self.oldvalue = oldvalue
32 self.newvalue = newvalue 41 self.newvalue = newvalue
42 self.monitored = monitored
43 self.related = []
33 self.filechanges = None 44 self.filechanges = None
34 45
35 def __str__(self): 46 def __str__(self):
47 return self._str_internal(True)
48
49 def _str_internal(self, pathprefix):
50 if pathprefix:
51 prefix = '%s: ' % self.path
52 else:
53 prefix = ''
54
36 if self.fieldname in list_fields: 55 if self.fieldname in list_fields:
37 aitems = self.oldvalue.split() 56 aitems = self.oldvalue.split()
38 bitems = self.newvalue.split() 57 bitems = self.newvalue.split()
39 removed = list(set(aitems) - set(bitems)) 58 removed = list(set(aitems) - set(bitems))
40 added = list(set(bitems) - set(aitems)) 59 added = list(set(bitems) - set(aitems))
41 return '%s: %s:%s%s' % (self.path, self.fieldname, ' removed "%s"' % ' '.join(removed) if removed else '', ' added "%s"' % ' '.join(added) if added else '') 60 out = '%s:%s%s' % (self.fieldname, ' removed "%s"' % ' '.join(removed) if removed else '', ' added "%s"' % ' '.join(added) if added else '')
42 elif self.fieldname in numeric_fields: 61 elif self.fieldname in numeric_fields:
43 aval = int(self.oldvalue or 0) 62 aval = int(self.oldvalue or 0)
44 bval = int(self.newvalue or 0) 63 bval = int(self.newvalue or 0)
@@ -46,9 +65,11 @@ class ChangeRecord:
46 percentchg = ((bval - aval) / float(aval)) * 100 65 percentchg = ((bval - aval) / float(aval)) * 100
47 else: 66 else:
48 percentchg = 100 67 percentchg = 100
49 return '%s: %s changed from %s to %s (%s%d%%)' % (self.path, self.fieldname, self.oldvalue or "''", self.newvalue or "''", '+' if percentchg > 0 else '', percentchg) 68 out = '%s changed from %s to %s (%s%d%%)' % (self.fieldname, self.oldvalue or "''", self.newvalue or "''", '+' if percentchg > 0 else '', percentchg)
50 elif self.fieldname in img_monitor_files: 69 elif self.fieldname in img_monitor_files:
51 out = 'Changes to %s (%s):\n ' % (self.path, self.fieldname) 70 if pathprefix:
71 prefix = 'Changes to %s ' % self.path
72 out = '(%s):\n ' % self.fieldname
52 if self.filechanges: 73 if self.filechanges:
53 out += '\n '.join(['%s' % i for i in self.filechanges]) 74 out += '\n '.join(['%s' % i for i in self.filechanges])
54 else: 75 else:
@@ -57,10 +78,15 @@ class ChangeRecord:
57 diff = difflib.unified_diff(alines, blines, self.fieldname, self.fieldname, lineterm='') 78 diff = difflib.unified_diff(alines, blines, self.fieldname, self.fieldname, lineterm='')
58 out += '\n '.join(list(diff)) 79 out += '\n '.join(list(diff))
59 out += '\n --' 80 out += '\n --'
60 return out
61 else: 81 else:
62 return '%s: %s changed from "%s" to "%s"' % (self.path, self.self.fieldname, self.oldvalue, self.newvalue) 82 out = '%s changed from "%s" to "%s"' % (self.fieldname, self.oldvalue, self.newvalue)
63 83
84 if self.related:
85 for chg in self.related:
86 for line in chg._str_internal(False).splitlines():
87 out += '\n * %s' % line
88
89 return '%s%s' % (prefix, out)
64 90
65class FileChange: 91class FileChange:
66 changetype_add = 'A' 92 changetype_add = 'A'
@@ -199,21 +225,20 @@ def compare_dict_blobs(path, ablob, bblob, report_all):
199 changes = [] 225 changes = []
200 keys = list(set(adict.keys()) | set(bdict.keys())) 226 keys = list(set(adict.keys()) | set(bdict.keys()))
201 for key in keys: 227 for key in keys:
202 if report_all or key in monitor_fields: 228 astr = adict.get(key, '')
203 astr = adict.get(key, '') 229 bstr = bdict.get(key, '')
204 bstr = bdict.get(key, '') 230 if astr != bstr:
205 if astr != bstr: 231 if (not report_all) and key in numeric_fields:
206 if (not report_all) and key in numeric_fields: 232 aval = int(astr or 0)
207 aval = int(astr or 0) 233 bval = int(bstr or 0)
208 bval = int(bstr or 0) 234 if aval != 0:
209 if aval != 0: 235 percentchg = ((bval - aval) / float(aval)) * 100
210 percentchg = ((bval - aval) / float(aval)) * 100 236 else:
211 else: 237 percentchg = 100
212 percentchg = 100 238 if percentchg < monitor_numeric_threshold:
213 if percentchg < monitor_numeric_threshold: 239 continue
214 continue 240 chg = ChangeRecord(path, key, astr, bstr, key in monitor_fields)
215 chg = ChangeRecord(path, key, astr, bstr) 241 changes.append(chg)
216 changes.append(chg)
217 return changes 242 return changes
218 243
219 244
@@ -236,7 +261,7 @@ def process_changes(repopath, revision1, revision2 = 'HEAD', report_all = False)
236 blines = d.b_blob.data_stream.read().splitlines() 261 blines = d.b_blob.data_stream.read().splitlines()
237 filechanges = compare_file_lists(alines,blines) 262 filechanges = compare_file_lists(alines,blines)
238 if filechanges: 263 if filechanges:
239 chg = ChangeRecord(path, filename, None, None) 264 chg = ChangeRecord(path, filename, None, None, True)
240 chg.filechanges = filechanges 265 chg.filechanges = filechanges
241 changes.append(chg) 266 changes.append(chg)
242 elif filename == 'installed-package-names.txt': 267 elif filename == 'installed-package-names.txt':
@@ -244,13 +269,27 @@ def process_changes(repopath, revision1, revision2 = 'HEAD', report_all = False)
244 blines = d.b_blob.data_stream.read().splitlines() 269 blines = d.b_blob.data_stream.read().splitlines()
245 filechanges = compare_lists(alines,blines) 270 filechanges = compare_lists(alines,blines)
246 if filechanges: 271 if filechanges:
247 chg = ChangeRecord(path, filename, None, None) 272 chg = ChangeRecord(path, filename, None, None, True)
248 chg.filechanges = filechanges 273 chg.filechanges = filechanges
249 changes.append(chg) 274 changes.append(chg)
250 else: 275 else:
251 chg = ChangeRecord(path, filename, d.a_blob.data_stream.read(), d.b_blob.data_stream.read()) 276 chg = ChangeRecord(path, filename, d.a_blob.data_stream.read(), d.b_blob.data_stream.read(), True)
252 changes.append(chg) 277 changes.append(chg)
253 elif filename == 'image-info.txt': 278 elif filename == 'image-info.txt':
254 changes.extend(compare_dict_blobs(path, d.a_blob, d.b_blob, report_all)) 279 changes.extend(compare_dict_blobs(path, d.a_blob, d.b_blob, report_all))
255 280
256 return changes 281 # Link related changes
282 for chg in changes:
283 if chg.monitored:
284 for chg2 in changes:
285 # (Check dirname in the case of fields from recipe info files)
286 if chg.path == chg2.path or os.path.dirname(chg.path) == chg2.path:
287 if chg2.fieldname in related_fields.get(chg.fieldname, []):
288 chg.related.append(chg2)
289 elif chg.path.startswith('packages/') and chg2.fieldname in ['PE', 'PV', 'PR']:
290 chg.related.append(chg2)
291
292 if report_all:
293 return changes
294 else:
295 return [chg for chg in changes if chg.monitored]