OLD | NEW |
1 # Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 # Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
2 # for details. All rights reserved. Use of this source code is governed by a | 2 # for details. All rights reserved. Use of this source code is governed by a |
3 # BSD-style license that can be found in the LICENSE file. | 3 # BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import os | 5 import os |
6 import cpplint | 6 import cpplint |
7 import re | 7 import re |
8 | 8 |
9 | 9 |
10 class PathHackException(Exception): | 10 class PathHackException(Exception): |
11 def __init__(self, error_msg): | 11 def __init__(self, error_msg): |
12 self.error_msg = error_msg | 12 self.error_msg = error_msg |
13 | 13 |
14 def __str__(self): | 14 def __str__(self): |
15 return repr(self.error_msg) | 15 return repr(self.error_msg) |
16 | 16 |
| 17 def AddSvnPathIfNeeded(runtime_path): |
| 18 # Add the .svn into the runtime directory if needed for git or svn 1.7. |
| 19 fake_svn_path = os.path.join(runtime_path, '.svn') |
| 20 if os.path.exists(fake_svn_path): |
| 21 return None |
| 22 open(fake_svn_path, 'w').close() |
| 23 return lambda: os.remove(fake_svn_path) |
| 24 |
17 | 25 |
18 def TrySvnPathHack(parent_path): | 26 def TrySvnPathHack(parent_path): |
19 orig_path = os.path.join(parent_path, '.svn') | 27 orig_path = os.path.join(parent_path, '.svn') |
20 renamed_path = os.path.join(parent_path, '.svn_orig') | 28 renamed_path = os.path.join(parent_path, '.svn_orig') |
21 if os.path.exists(renamed_path): | 29 if os.path.exists(renamed_path): |
22 error_msg = '".svn_orig" exists in presubmit parent directory(' | 30 error_msg = '".svn_orig" exists in presubmit parent directory(' |
23 error_msg += parent_path | 31 error_msg += parent_path |
24 error_msg += '). Consider renaming it manually to ".svn".' | 32 error_msg += '). Consider renaming it manually to ".svn".' |
25 raise PathHackException(error_msg) | 33 raise PathHackException(error_msg) |
26 if os.path.exists(orig_path): | 34 if os.path.exists(orig_path): |
27 # Make the parent SVN directory non-discoverable by cpplint to get | 35 # Make the parent SVN directory non-discoverable by cpplint to get |
28 # the correct header guard checks. This is needed if using all Dart | 36 # the correct header guard checks. This is needed if using all Dart |
29 # checkout. | 37 # checkout. |
30 os.rename(orig_path, renamed_path) | 38 os.rename(orig_path, renamed_path) |
31 return lambda: os.rename(renamed_path, orig_path) | 39 return lambda: os.rename(renamed_path, orig_path) |
32 | 40 |
33 | 41 |
34 def TryGitPathHack(filename, parent_path): | |
35 def CommonSubdirectory(parent, child): | |
36 while len(child) > len(parent): | |
37 child, tail = os.path.split(child) | |
38 if child == parent: | |
39 return os.path.join(parent, tail) | |
40 if os.path.exists(os.path.join(parent_path, '.git')): | |
41 runtime_path = CommonSubdirectory(parent_path, filename) | |
42 if runtime_path is not None: | |
43 fake_svn_path = os.path.join(runtime_path, '.svn') | |
44 if os.path.exists(fake_svn_path): | |
45 error_msg = '".svn" exists in presubmit parent subdirectory(' | |
46 error_msg += fake_svn_path | |
47 error_msg += '). Consider removing it manually.' | |
48 raise PathHackException(error_msg) | |
49 # Deposit a file named ".svn" in the runtime directory to fool | |
50 # cpplint into thinking it is the source root. | |
51 open(fake_svn_path, 'w').close() | |
52 return lambda: os.remove(fake_svn_path) | |
53 | |
54 | |
55 def RunLint(input_api, output_api): | 42 def RunLint(input_api, output_api): |
56 result = [] | 43 result = [] |
57 cpplint._cpplint_state.ResetErrorCounts() | 44 cpplint._cpplint_state.ResetErrorCounts() |
58 memcpy_match_count = 0 | 45 memcpy_match_count = 0 |
59 # Find all .cc and .h files in the change list. | 46 # Find all .cc and .h files in the change list. |
60 for svn_file in input_api.AffectedTextFiles(): | 47 for svn_file in input_api.AffectedTextFiles(): |
61 filename = svn_file.AbsoluteLocalPath() | 48 filename = svn_file.AbsoluteLocalPath() |
62 if filename.endswith('.cc') or filename.endswith('.h'): | 49 if filename.endswith('.cc') or filename.endswith('.h'): |
63 cleanup = None | 50 cleanup_parent = None |
64 parent_path = os.path.dirname(input_api.PresubmitLocalPath()) | 51 cleanup_runtime = None |
65 try: | 52 try: |
| 53 runtime_path = input_api.PresubmitLocalPath() |
| 54 parent_path = os.path.dirname(runtime_path) |
66 if filename.endswith('.h'): | 55 if filename.endswith('.h'): |
67 cleanup = TrySvnPathHack(parent_path) | 56 cleanup_runtime = AddSvnPathIfNeeded(runtime_path) |
68 if cleanup is None: | 57 cleanup_parent = TrySvnPathHack(parent_path) |
69 cleanup = TryGitPathHack(filename, parent_path) | |
70 except PathHackException, exception: | 58 except PathHackException, exception: |
71 return [output_api.PresubmitError(str(exception))] | 59 return [output_api.PresubmitError(str(exception))] |
72 # Run cpplint on the file. | 60 # Run cpplint on the file. |
73 cpplint.ProcessFile(filename, 1) | 61 cpplint.ProcessFile(filename, 1) |
74 if cleanup is not None: | 62 if cleanup_parent is not None: |
75 cleanup() | 63 cleanup_parent() |
| 64 if cleanup_runtime is not None: |
| 65 cleanup_runtime() |
76 # memcpy does not handle overlapping memory regions. Even though this | 66 # memcpy does not handle overlapping memory regions. Even though this |
77 # is well documented it seems to be used in error quite often. To avoid | 67 # is well documented it seems to be used in error quite often. To avoid |
78 # problems we disallow the direct use of memcpy. The exceptions are in | 68 # problems we disallow the direct use of memcpy. The exceptions are in |
79 # third-party code and in platform/globals.h which uses it to implement | 69 # third-party code and in platform/globals.h which uses it to implement |
80 # bit_cast and bit_copy. | 70 # bit_cast and bit_copy. |
81 if not filename.endswith(os.path.join('platform', 'globals.h')) and \ | 71 if not filename.endswith(os.path.join('platform', 'globals.h')) and \ |
82 filename.find('third_party') == -1: | 72 filename.find('third_party') == -1: |
83 fh = open(filename, 'r') | 73 fh = open(filename, 'r') |
84 content = fh.read() | 74 content = fh.read() |
85 match = re.search('\\bmemcpy\\b', content) | 75 match = re.search('\\bmemcpy\\b', content) |
86 if match: | 76 if match: |
87 line_number = content[0:match.start()].count('\n') + 1 | 77 line_number = content[0:match.start()].count('\n') + 1 |
88 print "%s:%d: use of memcpy is forbidden" % (filename, line_number) | 78 print "%s:%d: use of memcpy is forbidden" % (filename, line_number) |
89 memcpy_match_count += 1 | 79 memcpy_match_count += 1 |
90 | 80 |
91 # Report a presubmit error if any of the files had an error. | 81 # Report a presubmit error if any of the files had an error. |
92 if cpplint._cpplint_state.error_count > 0 or memcpy_match_count > 0: | 82 if cpplint._cpplint_state.error_count > 0 or memcpy_match_count > 0: |
93 result = [output_api.PresubmitError('Failed cpplint check.')] | 83 result = [output_api.PresubmitError('Failed cpplint check.')] |
94 return result | 84 return result |
95 | 85 |
96 | 86 |
97 def CheckChangeOnUpload(input_api, output_api): | 87 def CheckChangeOnUpload(input_api, output_api): |
98 return RunLint(input_api, output_api) | 88 return RunLint(input_api, output_api) |
99 | 89 |
100 | 90 |
101 def CheckChangeOnCommit(input_api, output_api): | 91 def CheckChangeOnCommit(input_api, output_api): |
102 return RunLint(input_api, output_api) | 92 return RunLint(input_api, output_api) |
OLD | NEW |