blob: 6c92d5aa3a91f034c0f3b939d4373f631a4f75c1 [file] [log] [blame]
Chris Craik93216d02015-03-05 13:58:42 -08001# Copyright (c) 2015 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4import os
5import re
6import subprocess
7import sys
8
9from trace_viewer import trace_viewer_project
10
11class AffectedFile(object):
12 def __init__(self, input_api, filename):
13 self._filename = filename
14 self._input_api = input_api
15 self._cached_contents = None
16 self._cached_changed_contents = None
17 self._cached_new_contents = None
18
19 def __repr__(self):
20 return self._filename
21
22 @property
23 def filename(self):
24 return self._filename
25
26 @property
27 def contents(self):
28 if self._cached_contents is None:
29 self._cached_contents = self._input_api._git(
30 ['show', ':%s' % self._filename])
31 return self._cached_contents
32
33 @property
34 def is_added(self):
35 return self.fileame in self._input_api.added_files
36
37 @property
38 def contents_as_lines(self):
39 """Returns an iterator over the lines in the new version of file.
40
41 The new version is the file in the user's workspace, i.e. the "right hand
42 side".
43
44 Contents will be empty if the file is a directory or does not exist.
45 Note: The carriage returns (LF or CR) are stripped off.
46 """
47 if self._cached_new_contents is None:
48 self._cached_new_contents = self.contents.splitlines()
49 return self._cached_new_contents[:]
50
51 @property
52 def changed_lines(self):
53 """Returns a list of tuples (line number, line text) of all new lines.
54
55 This relies on the scm diff output describing each changed code section
56 with a line of the form
57
58 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
59 """
60 if self._cached_changed_contents is not None:
61 return self._cached_changed_contents[:]
62 self._cached_changed_contents = []
63 line_num = 0
64
65 for line in self.GenerateDiff().splitlines():
66 m = re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
67 if m:
68 line_num = int(m.groups(1)[0])
69 continue
70 if line.startswith('+') and not line.startswith('++'):
71 self._cached_changed_contents.append((line_num, line[1:]))
72 if not line.startswith('-'):
73 line_num += 1
74 return self._cached_changed_contents[:]
75
76 def GenerateDiff(self):
Chris Craik44c28202015-05-12 17:25:16 -070077 return self._input_api._git([
78 'diff', self._input_api.diff_base, '--cached', self.filename])
Chris Craik93216d02015-03-05 13:58:42 -080079
80
81class InputAPI(object):
Chris Craik44c28202015-05-12 17:25:16 -070082 def __init__(self, tvp, diff_base):
Chris Craik93216d02015-03-05 13:58:42 -080083 self.DEFAULT_BLACK_LIST = []
84 self._tvp = tvp
85 self._filename_statuses = None
86 self._added_files = None
Chris Craik44c28202015-05-12 17:25:16 -070087 self.diff_base = diff_base
Chris Craik93216d02015-03-05 13:58:42 -080088
89 def _git(self, args):
90 assert isinstance(args, list)
91 args = ['git'] + args
92 p = subprocess.Popen(
93 args,
94 stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
95 cwd=self.repository_root)
96 res = p.communicate()
97 if p.wait() != 0:
98 raise Exception(res[1])
99 return res[0]
100
101 @property
102 def repository_root(self):
103 return self._tvp.trace_viewer_path
104
105 @property
106 def added_files(self):
107 if not self._added_files:
108 self._added_files = set()
109 for filename, status_char in filename_statuses:
110 if status_char == 'A':
111 self._added_files.Add(filename)
112 return self._added_files
113
114 @property
115 def affected_files(self):
116 return self.AffectedFiles(include_deletes=True)
117
118 def AffectedFiles(self,
119 include_deletes=False,
120 file_filter=lambda t: True):
121 filename_statuses = self._GetFilenameStatuses()
122 for filename, status_char in filename_statuses:
123 if status_char == 'D':
124 if include_deletes:
125 if file_filter(filename):
126 yield AffectedFile(self, filename)
127 else:
128 if file_filter(filename):
129 yield AffectedFile(self, filename)
130
131 def _GetFilenameStatuses(self):
132 if self._filename_statuses != None:
133 return self._filename_statuses
134
135 self._filename_statuses = []
Chris Craik44c28202015-05-12 17:25:16 -0700136 stdout = self._git([
137 'diff', self.diff_base, '--cached', '--name-status'])
Chris Craik93216d02015-03-05 13:58:42 -0800138 for line in stdout.split('\n'):
139 line = line.strip()
140 if len(line) == 0:
141 continue
142 m = re.match('([ACDMRTUXB])\s+(.+)', line)
143 if not m:
144 import pdb; pdb.set_trace()
145 assert m
146
147 status_char = m.group(1)
148 filename = m.group(2)
149 self._filename_statuses.append((filename, status_char))
150 return self._filename_statuses
151
Chris Craik44c28202015-05-12 17:25:16 -0700152 def IsTestDataFile(self, affected_file):
153 full_path = os.path.join(self.repository_root, affected_file.filename)
154 return full_path.startswith(self._tvp.test_data_path)
155
Chris Craik93216d02015-03-05 13:58:42 -0800156
157def RunChecks(input_api):
158 results = []
159
160 from hooks import pre_commit_checks
161 results += pre_commit_checks.RunChecks(input_api)
162
163 from trace_viewer.build import check_gyp
164 err = check_gyp.GypCheck()
165 if err:
166 results += [err]
167
168 from trace_viewer.build import check_gn
169 err = check_gn.GnCheck()
170 if err:
171 results += [err]
172
173 from trace_viewer.build import check_modules
174 err = check_modules.CheckModules()
175 if err:
176 results += [err]
177
178 from hooks import js_checks
179 results += js_checks.RunChecks(input_api)
180
181 return results
182
183
Chris Craik44c28202015-05-12 17:25:16 -0700184def GetResults(diff_base):
Chris Craik93216d02015-03-05 13:58:42 -0800185 tvp = trace_viewer_project.TraceViewerProject()
Chris Craik44c28202015-05-12 17:25:16 -0700186 input_api = InputAPI(tvp, diff_base)
187 return RunChecks(input_api)
188
189
190def Main(args):
191 results = GetResults('HEAD')
Chris Craik93216d02015-03-05 13:58:42 -0800192 print '\n\n'.join(results)
193
194 if len(results):
195 return 255
196 return 0