| #!/usr/bin/env python |
| # Copyright 2018 the V8 project authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| # for py2/py3 compatibility |
| from __future__ import print_function |
| |
| import argparse |
| from datetime import datetime |
| import re |
| import subprocess |
| import sys |
| |
| RE_GITHASH = re.compile(r"^[0-9a-f]{40}") |
| RE_AUTHOR_TIME = re.compile(r"^author-time (\d+)$") |
| RE_FILENAME = re.compile(r"^filename (.+)$") |
| |
| def GetBlame(file_path): |
| result = subprocess.check_output( |
| ['git', 'blame', '-t', '--line-porcelain', file_path]) |
| line_iter = iter(result.splitlines()) |
| blame_list = list() |
| current_blame = None |
| while True: |
| line = next(line_iter, None) |
| if line is None: |
| break |
| if RE_GITHASH.match(line): |
| if current_blame is not None: |
| blame_list.append(current_blame) |
| current_blame = {'time': 0, 'filename': None, 'content': None} |
| continue |
| match = RE_AUTHOR_TIME.match(line) |
| if match: |
| current_blame['time'] = datetime.fromtimestamp(int(match.groups()[0])) |
| continue |
| match = RE_FILENAME.match(line) |
| if match: |
| current_blame['filename'] = match.groups()[0] |
| current_blame['content'] = next(line_iter).strip() |
| continue |
| blame_list.append(current_blame) |
| return blame_list |
| |
| RE_MACRO_END = re.compile(r"\);"); |
| RE_DEPRECATE_MACRO = re.compile(r"\(.*?,(.*)\);", re.MULTILINE) |
| |
| def FilterAndPrint(blame_list, macro, before): |
| index = 0 |
| re_macro = re.compile(macro) |
| deprecated = list() |
| while index < len(blame_list): |
| blame = blame_list[index] |
| match = re_macro.search(blame['content']) |
| if match and blame['time'] < before: |
| line = blame['content'] |
| time = blame['time'] |
| pos = match.end() |
| start = -1 |
| parens = 0 |
| quotes = 0 |
| while True: |
| if pos >= len(line): |
| # extend to next line |
| index = index + 1 |
| blame = blame_list[index] |
| if line.endswith(','): |
| # add whitespace when breaking line due to comma |
| line = line + ' ' |
| line = line + blame['content'] |
| if line[pos] == '(': |
| parens = parens + 1 |
| elif line[pos] == ')': |
| parens = parens - 1 |
| if parens == 0: |
| break |
| elif line[pos] == '"': |
| quotes = quotes + 1 |
| elif line[pos] == ',' and quotes % 2 == 0 and start == -1: |
| start = pos + 1 |
| pos = pos + 1 |
| deprecated.append([index + 1, time, line[start:pos].strip()]) |
| index = index + 1 |
| print("Marked as " + macro + ": " + str(len(deprecated))) |
| for linenumber, time, content in deprecated: |
| print(str(linenumber).rjust(8) + " : " + str(time) + " : " + content) |
| return len(deprecated) |
| |
| def ParseOptions(args): |
| parser = argparse.ArgumentParser(description="Collect deprecation statistics") |
| parser.add_argument("file_path", help="Path to v8.h") |
| parser.add_argument("--before", help="Filter by date") |
| options = parser.parse_args(args) |
| if options.before: |
| options.before = datetime.strptime(options.before, '%Y-%m-%d') |
| else: |
| options.before = datetime.now() |
| return options |
| |
| def Main(args): |
| options = ParseOptions(args) |
| blame_list = GetBlame(options.file_path) |
| FilterAndPrint(blame_list, "V8_DEPRECATE_SOON", options.before) |
| FilterAndPrint(blame_list, "V8_DEPRECATED", options.before) |
| |
| if __name__ == "__main__": |
| Main(sys.argv[1:]) |