File: find_replace_nested_namespaces.py

package info (click to toggle)
mrpt 1%3A2.15.10%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 92,552 kB
  • sloc: cpp: 558,205; ansic: 36,841; xml: 3,872; python: 2,195; sh: 524; makefile: 232
file content (97 lines) | stat: -rwxr-xr-x 3,555 bytes parent folder | download | duplicates (4)
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()