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