diff options
Diffstat (limited to 'meta/lib/oe/buildhistory_analysis.py')
| -rw-r--r-- | meta/lib/oe/buildhistory_analysis.py | 65 |
1 files changed, 62 insertions, 3 deletions
diff --git a/meta/lib/oe/buildhistory_analysis.py b/meta/lib/oe/buildhistory_analysis.py index 5b28774c98..2d6fa1779e 100644 --- a/meta/lib/oe/buildhistory_analysis.py +++ b/meta/lib/oe/buildhistory_analysis.py | |||
| @@ -213,6 +213,7 @@ class FileChange: | |||
| 213 | changetype_perms = 'P' | 213 | changetype_perms = 'P' |
| 214 | changetype_ownergroup = 'O' | 214 | changetype_ownergroup = 'O' |
| 215 | changetype_link = 'L' | 215 | changetype_link = 'L' |
| 216 | changetype_move = 'M' | ||
| 216 | 217 | ||
| 217 | def __init__(self, path, changetype, oldvalue = None, newvalue = None): | 218 | def __init__(self, path, changetype, oldvalue = None, newvalue = None): |
| 218 | self.path = path | 219 | self.path = path |
| @@ -251,10 +252,11 @@ class FileChange: | |||
| 251 | return '%s changed owner/group from %s to %s' % (self.path, self.oldvalue, self.newvalue) | 252 | return '%s changed owner/group from %s to %s' % (self.path, self.oldvalue, self.newvalue) |
| 252 | elif self.changetype == self.changetype_link: | 253 | elif self.changetype == self.changetype_link: |
| 253 | return '%s changed symlink target from %s to %s' % (self.path, self.oldvalue, self.newvalue) | 254 | return '%s changed symlink target from %s to %s' % (self.path, self.oldvalue, self.newvalue) |
| 255 | elif self.changetype == self.changetype_move: | ||
| 256 | return '%s moved to %s' % (self.path, self.oldvalue) | ||
| 254 | else: | 257 | else: |
| 255 | return '%s changed (unknown)' % self.path | 258 | return '%s changed (unknown)' % self.path |
| 256 | 259 | ||
| 257 | |||
| 258 | def blob_to_dict(blob): | 260 | def blob_to_dict(blob): |
| 259 | alines = [line for line in blob.data_stream.read().decode('utf-8').splitlines()] | 261 | alines = [line for line in blob.data_stream.read().decode('utf-8').splitlines()] |
| 260 | adict = {} | 262 | adict = {} |
| @@ -281,11 +283,14 @@ def file_list_to_dict(lines): | |||
| 281 | adict[path] = splitv[0:3] | 283 | adict[path] = splitv[0:3] |
| 282 | return adict | 284 | return adict |
| 283 | 285 | ||
| 286 | numeric_removal = str.maketrans('0123456789', 'XXXXXXXXXX') | ||
| 284 | 287 | ||
| 285 | def compare_file_lists(alines, blines, compare_ownership=True): | 288 | def compare_file_lists(alines, blines, compare_ownership=True): |
| 286 | adict = file_list_to_dict(alines) | 289 | adict = file_list_to_dict(alines) |
| 287 | bdict = file_list_to_dict(blines) | 290 | bdict = file_list_to_dict(blines) |
| 288 | filechanges = [] | 291 | filechanges = [] |
| 292 | additions = [] | ||
| 293 | removals = [] | ||
| 289 | for path, splitv in adict.items(): | 294 | for path, splitv in adict.items(): |
| 290 | newsplitv = bdict.pop(path, None) | 295 | newsplitv = bdict.pop(path, None) |
| 291 | if newsplitv: | 296 | if newsplitv: |
| @@ -318,11 +323,65 @@ def compare_file_lists(alines, blines, compare_ownership=True): | |||
| 318 | if oldvalue != newvalue: | 323 | if oldvalue != newvalue: |
| 319 | filechanges.append(FileChange(path, FileChange.changetype_link, oldvalue, newvalue)) | 324 | filechanges.append(FileChange(path, FileChange.changetype_link, oldvalue, newvalue)) |
| 320 | else: | 325 | else: |
| 321 | filechanges.append(FileChange(path, FileChange.changetype_remove)) | 326 | removals.append(path) |
| 322 | 327 | ||
| 323 | # Whatever is left over has been added | 328 | # Whatever is left over has been added |
| 324 | for path in bdict: | 329 | for path in bdict: |
| 325 | filechanges.append(FileChange(path, FileChange.changetype_add)) | 330 | additions.append(path) |
| 331 | |||
| 332 | # Rather than print additions and removals, its nicer to print file 'moves' | ||
| 333 | # where names or paths are similar. | ||
| 334 | revmap_remove = {} | ||
| 335 | for removal in removals: | ||
| 336 | translated = removal.translate(numeric_removal) | ||
| 337 | if translated not in revmap_remove: | ||
| 338 | revmap_remove[translated] = [] | ||
| 339 | revmap_remove[translated].append(removal) | ||
| 340 | |||
| 341 | # | ||
| 342 | # We want to detect renames of large trees of files like | ||
| 343 | # /lib/modules/5.4.40-yocto-standard to /lib/modules/5.4.43-yocto-standard | ||
| 344 | # | ||
| 345 | renames = {} | ||
| 346 | for addition in additions.copy(): | ||
| 347 | if addition not in additions: | ||
| 348 | continue | ||
| 349 | translated = addition.translate(numeric_removal) | ||
| 350 | if translated in revmap_remove: | ||
| 351 | if len(revmap_remove[translated]) != 1: | ||
| 352 | continue | ||
| 353 | removal = revmap_remove[translated][0] | ||
| 354 | commondir = addition.split("/") | ||
| 355 | commondir2 = removal.split("/") | ||
| 356 | idx = None | ||
| 357 | for i in range(len(commondir)): | ||
| 358 | if commondir[i] != commondir2[i]: | ||
| 359 | idx = i | ||
| 360 | break | ||
| 361 | commondir = "/".join(commondir[:i+1]) | ||
| 362 | commondir2 = "/".join(commondir2[:i+1]) | ||
| 363 | # If the common parent is in one dict and not the other its likely a rename | ||
| 364 | # so iterate through those files and process as such | ||
| 365 | if commondir2 not in bdict and commondir not in adict: | ||
| 366 | if commondir not in renames: | ||
| 367 | renames[commondir] = commondir2 | ||
| 368 | for addition2 in additions.copy(): | ||
| 369 | if addition2.startswith(commondir): | ||
| 370 | removal2 = addition2.replace(commondir, commondir2) | ||
| 371 | if removal2 in removals: | ||
| 372 | additions.remove(addition2) | ||
| 373 | removals.remove(removal2) | ||
| 374 | continue | ||
| 375 | filechanges.append(FileChange(removal, FileChange.changetype_move, addition)) | ||
| 376 | additions.remove(addition) | ||
| 377 | removals.remove(removal) | ||
| 378 | for rename in renames: | ||
| 379 | filechanges.append(FileChange(renames[rename], FileChange.changetype_move, rename)) | ||
| 380 | |||
| 381 | for addition in additions: | ||
| 382 | filechanges.append(FileChange(addition, FileChange.changetype_add)) | ||
| 383 | for removal in removals: | ||
| 384 | filechanges.append(FileChange(removal, FileChange.changetype_remove)) | ||
| 326 | 385 | ||
| 327 | return filechanges | 386 | return filechanges |
| 328 | 387 | ||
