1- #!/usr/bin/env python
1+ #!/usr/bin/env python3
22# Copyright 2018 the V8 project authors. All rights reserved.
33# Use of this source code is governed by a BSD-style license that can be
44# found in the LICENSE file.
55
6- # for py2/py3 compatibility
7- from __future__ import print_function
8-
96import argparse
107from datetime import datetime
118import re
129import subprocess
1310import sys
14- from os import path
11+ from pathlib import Path
1512
1613RE_GITHASH = re .compile (r"^[0-9a-f]{40}" )
1714RE_AUTHOR_TIME = re .compile (r"^author-time (\d+)$" )
1815RE_FILENAME = re .compile (r"^filename (.+)$" )
1916
17+ VERSION_CACHE = dict ()
18+ RE_VERSION_MAJOR = re .compile (r".*V8_MAJOR_VERSION ([0-9]+)" )
19+ RE_VERSION_MINOR = re .compile (r".*V8_MINOR_VERSION ([0-9]+)" )
20+
21+
22+ def extract_version (hash ):
23+ if hash in VERSION_CACHE :
24+ return VERSION_CACHE [hash ]
25+ result = subprocess .check_output (
26+ ['git' , 'show' , f"{ hash } :include/v8-version.h" ], encoding = 'UTF-8' )
27+ major = RE_VERSION_MAJOR .search (result ).group (1 )
28+ minor = RE_VERSION_MINOR .search (result ).group (1 )
29+ version = f"{ major } .{ minor } "
30+ VERSION_CACHE [hash ] = version
31+ return version
32+
2033
21- def GetBlame (file_path ):
34+ def get_blame (file_path ):
2235 result = subprocess .check_output (
23- ['git' , 'blame' , '-t' , '--line-porcelain' , file_path ])
36+ ['git' , 'blame' , '-t' , '--line-porcelain' , file_path ], encoding = 'UTF-8' )
2437 line_iter = iter (result .splitlines ())
2538 blame_list = list ()
2639 current_blame = None
@@ -31,11 +44,18 @@ def GetBlame(file_path):
3144 if RE_GITHASH .match (line ):
3245 if current_blame is not None :
3346 blame_list .append (current_blame )
34- current_blame = {'time' : 0 , 'filename' : None , 'content' : None }
47+ hash = line .split (" " )[0 ]
48+ current_blame = {
49+ 'datetime' : 0 ,
50+ 'filename' : None ,
51+ 'content' : None ,
52+ 'hash' : hash
53+ }
3554 continue
3655 match = RE_AUTHOR_TIME .match (line )
3756 if match :
38- current_blame ['time' ] = datetime .fromtimestamp (int (match .groups ()[0 ]))
57+ current_blame ['datetime' ] = datetime .fromtimestamp (int (
58+ match .groups ()[0 ]))
3959 continue
4060 match = RE_FILENAME .match (line )
4161 if match :
@@ -50,26 +70,27 @@ def GetBlame(file_path):
5070RE_DEPRECATE_MACRO = re .compile (r"\(.*?,(.*)\);" , re .MULTILINE )
5171
5272
53- def FilterAndPrint (blame_list , macro , options ):
73+ def filter_and_print (blame_list , macro , options ):
5474 before = options .before
5575 index = 0
5676 re_macro = re .compile (macro )
5777 deprecated = list ()
5878 while index < len (blame_list ):
5979 blame = blame_list [index ]
60- time = blame ['time ' ]
61- if time >= before :
80+ commit_datetime = blame ['datetime ' ]
81+ if commit_datetime >= before :
6282 index += 1
6383 continue
6484 line = blame ['content' ]
85+ commit_hash = blame ['hash' ]
6586 match = re_macro .search (line )
6687 if match :
6788 pos = match .end ()
6889 start = - 1
6990 parens = 0
7091 while True :
7192 if pos >= len (line ):
72- # extend to next line
93+ # Extend to next line
7394 index = index + 1
7495 blame = blame_list [index ]
7596 line = line + blame ['content' ]
@@ -78,25 +99,27 @@ def FilterAndPrint(blame_list, macro, options):
7899 elif line [pos ] == ')' :
79100 parens = parens - 1
80101 if parens == 0 :
81- # Exclud closing ")
102+ # Exclude closing ")
82103 pos = pos - 2
83104 break
84105 elif line [pos ] == '"' and start == - 1 :
85106 start = pos + 1
86107 pos = pos + 1
87108 # Extract content and replace double quotes from merged lines
88109 content = line [start :pos ].strip ().replace ('""' , '' )
89- deprecated .append ([ index + 1 , time , content ] )
110+ deprecated .append (( index + 1 , commit_datetime , commit_hash , content ) )
90111 index = index + 1
91- print ("Marked as " + macro + ": " + str (len (deprecated )))
92- for linenumber , time , content in deprecated :
93- print (" " + (options .v8_header + ":" +
94- str (linenumber )).rjust (len (options .v8_header ) + 5 ) + "\t " +
95- str (time ) + "\t " + content )
112+ print (f"# Marked as { macro } : { len (deprecated )} " )
113+ for linenumber , commit_datetime , commit_hash , content in deprecated :
114+ commit_date = commit_datetime .date ()
115+ file_position = (
116+ f"{ options .v8_header } :{ linenumber } " ).rjust (len (options .v8_header ) + 5 )
117+ print (f" { file_position } \t { commit_date } \t { commit_hash [:8 ]} "
118+ f"\t { extract_version (commit_hash )} \t { content } " )
96119 return len (deprecated )
97120
98121
99- def ParseOptions (args ):
122+ def parse_options (args ):
100123 parser = argparse .ArgumentParser (
101124 description = "Collect deprecation statistics" )
102125 parser .add_argument ("v8_header" , nargs = '?' , help = "Path to v8.h" )
@@ -107,16 +130,19 @@ def ParseOptions(args):
107130 else :
108131 options .before = datetime .now ()
109132 if options .v8_header is None :
110- options .v8_header = path .join (path .dirname (__file__ ), '..' , 'include' , 'v8.h' )
133+ base_path = Path (__file__ ).parent .parent
134+ options .v8_header = str (
135+ (base_path / 'include' / 'v8.h' ).relative_to (base_path ))
111136 return options
112137
113138
114- def Main (args ):
115- options = ParseOptions (args )
116- blame_list = GetBlame (options .v8_header )
117- FilterAndPrint (blame_list , "V8_DEPRECATE_SOON" , options )
118- FilterAndPrint (blame_list , "V8_DEPRECATED" , options )
139+ def main (args ):
140+ options = parse_options (args )
141+ blame_list = get_blame (options .v8_header )
142+ filter_and_print (blame_list , "V8_DEPRECATE_SOON" , options )
143+ print ("\n " )
144+ filter_and_print (blame_list , "V8_DEPRECATED" , options )
119145
120146
121147if __name__ == "__main__" :
122- Main (sys .argv [1 :])
148+ main (sys .argv [1 :])
0 commit comments