Skip to content
Snippets Groups Projects
check_deprecated.py 4.82 KiB
Newer Older
  • Learn to ignore specific revisions
  • # SPDX-License-Identifier: GPL-2.0-or-later
    
    """
    Utility for reporting deprecated code which should be removed,
    noted by the date which must be included with the *DEPRECATED* comment.
    
    Once this date is past, the code should be removed.
    """
    
    from typing import (
        Callable,
        Generator,
        List,
        Tuple,
        Optional,
    )
    
    
    import os
    import datetime
    from os.path import splitext
    
    SKIP_DIRS = (
        "extern",
    
        # Not this directory.
        "tests",
    
    )
    
    
    class term_colors:
        HEADER = '\033[95m'
        OKBLUE = '\033[94m'
        OKCYAN = '\033[96m'
        OKGREEN = '\033[92m'
        WARNING = '\033[93m'
        FAIL = '\033[91m'
        ENDC = '\033[0m'
        BOLD = '\033[1m'
        UNDERLINE = '\033[4m'
    
    
    def is_c_header(filename: str) -> bool:
        ext = splitext(filename)[1]
        return (ext in {".h", ".hh", ".hpp", ".hxx", ".hh"})
    
    
    def is_c(filename: str) -> bool:
        ext = splitext(filename)[1]
        return (ext in {".c", ".cc", ".cpp", ".cxx", ".m", ".mm", ".rc", ".inl"})
    
    
    def is_c_any(filename: str) -> bool:
        return is_c(filename) or is_c_header(filename)
    
    
    def is_py(filename: str) -> bool:
        ext = splitext(filename)[1]
        return (ext == ".py")
    
    
    def is_source_any(filename: str) -> bool:
        return is_c_any(filename) or is_py(filename)
    
    
    def source_list(path: str, filename_check: Optional[Callable[[str], bool]] = None) -> Generator[str, None, None]:
        for dirpath, dirnames, filenames in os.walk(path):
            # skip '.git'
            dirnames[:] = [d for d in dirnames if not d.startswith(".")]
    
            for filename in filenames:
                if filename_check is None or filename_check(filename):
                    yield os.path.join(dirpath, filename)
    
    
    def deprecations() -> List[Tuple[datetime.datetime, Tuple[str, int], str]]:
        """
        Searches out source code for lines like
    
        /* *DEPRECATED* 2011/7/17 bgl.Buffer.list info text. */
    
        Or...
    
        # *DEPRECATED* 2010/12/22 some.py.func more info.
    
        """
        SOURCE_DIR = os.path.normpath(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..")))
    
        SKIP_DIRS_ABS = [os.path.join(SOURCE_DIR, p) for p in SKIP_DIRS]
    
        DEPRECATED_ID = "*DEPRECATED*"
        depprecation_list = []
    
        scan_count = 0
    
        print("Scanning in %r for '%s YYYY/MM/DD info'" % (SOURCE_DIR, DEPRECATED_ID), end="...")
    
        for fn in source_list(SOURCE_DIR, is_source_any):
            if os.path.samefile(fn, __file__):
                continue
    
            skip = False
            for p in SKIP_DIRS_ABS:
                if fn.startswith(p):
                    skip = True
                    break
            if skip:
                continue
    
            with open(fn, 'r', encoding="utf8") as fh:
                fn = os.path.relpath(fn, SOURCE_DIR)
                buf = fh.read()
                index = 0
                while True:
                    index = buf.find(DEPRECATED_ID, index)
                    if index == -1:
                        break
                    index_end = buf.find("\n", index)
                    if index_end == -1:
                        index_end = len(buf)
                    line_number = buf[:index].count("\n") + 1
                    l = buf[index + len(DEPRECATED_ID): index_end].strip()
                    try:
                        data = [w.strip() for w in l.split('/', 2)]
                        data[-1], info = data[-1].split(' ', 1)
                        info = info.split("*/", 1)[0].strip()
                        if len(data) != 3:
                            print(
                                "    poorly formatting line:\n"
                                "    %r:%d\n"
                                "    %s" %
                                (fn, line_number, data)
                            )
                        else:
                            depprecation_list.append((
                                datetime.datetime(int(data[0]), int(data[1]), int(data[2])),
                                (fn, line_number),
                                info,
                            ))
                    except:
                        print("Error file - %r:%d" % (fn, line_number))
                        import traceback
                        traceback.print_exc()
    
                    index = index_end
    
            scan_count += 1
    
        print(" {:d} files done, found {:d} deprecation(s)!".format(scan_count, len(depprecation_list)))
    
        return depprecation_list
    
    
    def main() -> None:
        import datetime
        now = datetime.datetime.now()
    
        deps = deprecations()
    
        for data, fileinfo, info in deps:
            days_old = (now - data).days
            info = term_colors.BOLD + info + term_colors.ENDC
            if days_old > 0:
                info = "[" + term_colors.FAIL + "REMOVE" + term_colors.ENDC + "] " + info
            else:
                info = "[" + term_colors.OKBLUE + "OK" + term_colors.ENDC + "] " + info
    
            print("{:s}: days-old({:d}), {:s}:{:d} {:s}".format(
                data.strftime("%Y/%m/%d"),
                days_old,
                fileinfo[0],
                fileinfo[1],
                info,
            ))
    
    
    if __name__ == '__main__':
        main()