file_cmds-321.40.3.tar.gz
[apple/file_cmds.git] / mtree / fix_failure_locations.py
1 #!/usr/bin/python
2
3 #
4 # This script is used to automatically fix up the location numbers in
5 # calls to RECORD_FAILURE(). When adding a new call to RECORD_FAILURE,
6 # write it like:
7 # RECORD_FAILURE(0, ...);
8 # Don't put any white space between the open parenthesis, zero and comma.
9 # Once you have added the new calls to RECORD_FAILURE, then run this script,
10 # passing it the path to the directory, like this:
11 # python3 mtree/fix_failure_locations.py mtree/
12 #
13 # This script will edit the files, changing the "0" to the next available
14 # location number. It will also detect and complain if you have duplicate
15 # location numbers.
16 #
17 # DO NOT reuse location numbers! It is best if locations are consistent across
18 # all versions that have that RECORD_FAILURE call.
19 #
20
21 import sys
22 import os
23 import re
24 from collections import defaultdict
25 from datetime import datetime,timezone
26
27 class LocationUpdater(object):
28 epoch = datetime(2020, 6, 17, 23, 22, 46, 562458, tzinfo=timezone.utc)
29 location_base = int((datetime.now(timezone.utc) - epoch).total_seconds() / 60)
30 # Match the number in "RECORD_FAILURE(<number>,"
31 fail_re = (re.compile('(?<=\\bRECORD_FAILURE\\()\\d+(?=,)'),re.compile('(?<=\\bRECORD_FAILURE_MSG\\()\\d+(?=,)'))
32
33 def __init__(self, path):
34 self.location = self.location_base
35 self.path = path
36 # Counters for how often each location number was found
37 self.counts = defaultdict(int)
38 self.locations_changed = 0
39
40 # Replace the "0" in "RECORD_FAILURE(0," with next location number, in *.c
41 def fixLocations(self):
42 def replace_loc(match):
43 location = int(match.group(0))
44 if location == 0:
45 # Replace location 0 with the next available location
46 self.location += 1
47 self.locations_changed += 1
48 location = self.location
49 # Count the number of times this location number was used
50 self.counts[location] += 1
51 # Return the (possibly updated) location number
52 return str(location)
53 rootpath = self.path
54 for dirpath, dirnames, filenames in os.walk(rootpath):
55 for filename in filenames:
56 if filename.endswith(".c") or filename.endswith(".cpp"):
57 path = os.path.join(dirpath, filename)
58 content = open(path, "r").read()
59 for fail_re in self.fail_re:
60 if fail_re.search(content):
61 locations_changed_before = self.locations_changed
62 content = fail_re.sub(replace_loc, content)
63 if self.locations_changed != locations_changed_before:
64 # We updated a location number, so write the changed file
65 print("Updating file {}".format(path))
66 open(path,"w").write(content)
67
68 def duplicates(self):
69 # Return the list of keys whose count is greater than 1
70 return [k for (k,v) in iter(self.counts.items()) if v > 1]
71
72 updater = LocationUpdater(sys.argv[1])
73 updater.fixLocations()
74 dups = updater.duplicates()
75 if len(dups):
76 print("WARNING! Duplicate location numbers: {}".format(dups))
77 sys.exit(1)