forked from MRPT/mrpt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfind_replace_nested_namespaces.py
executable file
·97 lines (80 loc) · 3.47 KB
/
find_replace_nested_namespaces.py
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#!/usr/bin/env python3
"""
Current script replaces instances of multiple namespaces with the modern
C++17-equivalent nested namespaces
.. seealso::
* `<https://github.com/MRPT/mrpt/issues/752>_`
* `<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4230.html>_`
"""
import click
import sh
import re
from typing import List
@click.command()
@click.option('-r', '--root-dir', help='Top-level directory to operate in',
required=True, type=click.Path(exists=True))
@click.option('-e', '--extensions', help='Extensions which are to be considered', multiple=True)
def main(root_dir: str, extensions: List[str]):
# list of files to operate in
fpaths = [] # type: List[str]
# files that need to be checked manually
files_manual_check = [] # type: List[str]
num_files_modified = 0 # type: int
# find all the files we're interested in
for e in extensions:
fpaths.extend([i.rstrip() for i in sh.find(root_dir, "-iname",
"*.{}".format(e))])
expr_text = "namespace (\w*)[\s]{"
expr = re.compile(expr_text)
# we now have a list of files
for fpath in fpaths:
with open(fpath, 'rU') as f:
old_conts = f.read()
# do we have more than a single match
ns_expr_results = expr.findall(old_conts)
times_found = len(ns_expr_results)
if times_found > 1:
start_str = "\s*".join([expr_text] * times_found)
# match whitespace characters or comments after '}'
ending_str_after = "(\s*)(//.*)?(\s*)"
end_str = ending_str_after.join(['}'] * times_found)
end_str += ending_str_after
valid_start_results = re.search(start_str, old_conts)
valid_end_results = re.search(end_str, old_conts)
if not valid_start_results or not valid_end_results:
files_manual_check.append(fpath)
continue
# compose new contents
new_conts = old_conts
# convert the start
# grab the namespace names
ns_names = [g for g in valid_start_results.groups()]
# compose the new start
new_start = " ".join(["namespace", "::".join(ns_names), ])
new_start = "\n".join([new_start, "{"])
new_conts = "".join([new_conts[:valid_start_results.start()],
new_start,
new_conts[valid_start_results.end():],
"\n"])
# need to update the end characters position
valid_end_results = list(re.finditer(end_str, new_conts))[-1]
# convert the end
# convert only the count of instances that you are
# interested in, starting from the bottom
new_end = "}"
new_conts = "".join([new_conts[:valid_end_results.start()],
new_end,
"\n",
new_conts[valid_end_results.end():],
"\n"])
# flush the new contents
with open(fpath, 'w') as f:
num_files_modified += 1
f.write(new_conts)
print("{} files modified".format(num_files_modified))
print("{} files to check manually:\n{}".format(
len(files_manual_check),
'\n'.join(["\t{}".format(i) for i in
files_manual_check])))
if __name__ == "__main__":
main()