Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(307)

Side by Side Diff: scripts/slave/recipe_modules/filter/api.py

Issue 485873004: Adds ability for builders to only compile targets affected by change (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/build.git@master
Patch Set: merge 2 trunk Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | scripts/slave/recipe_modules/filter/example.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2014 The Chromium Authors. All rights reserved. 1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import re 5 import re
6 6
7 from slave import recipe_api 7 from slave import recipe_api
8 8
9 class FilterApi(recipe_api.RecipeApi): 9 class FilterApi(recipe_api.RecipeApi):
10 def __init__(self, **kwargs): 10 def __init__(self, **kwargs):
11 super(FilterApi, self).__init__(**kwargs) 11 super(FilterApi, self).__init__(**kwargs)
12 self._result = False 12 self._result = False
13 self._matching_exes = [] 13 self._matching_exes = []
14 self._compile_targets = []
14 15
15 def __is_path_in_exclusion_list(self, path, exclusions): 16 def __is_path_in_exclusion_list(self, path, exclusions):
16 """Returns true if |path| matches any of the regular expressions in 17 """Returns true if |path| matches any of the regular expressions in
17 |exclusions|.""" 18 |exclusions|."""
18 for regex in exclusions: 19 for regex in exclusions:
19 match = regex.match(path) 20 match = regex.match(path)
20 if match and match.end() == len(path): 21 if match and match.end() == len(path):
21 return regex.pattern 22 return regex.pattern
22 return False 23 return False
23 24
24 @property 25 @property
25 def result(self): 26 def result(self):
26 """Returns the result from most recent call to 27 """Returns the result from most recent call to
27 does_patch_require_compile.""" 28 does_patch_require_compile."""
28 return self._result 29 return self._result
29 30
30 @property 31 @property
31 def matching_exes(self): 32 def matching_exes(self):
32 """Returns the set of exes passed to does_patch_require_compile() that 33 """Returns the set of exes passed to does_patch_require_compile() that
33 are effected by the set of files that have changed.""" 34 are effected by the set of files that have changed."""
34 return self._matching_exes 35 return self._matching_exes
35 36
36 def does_patch_require_compile(self, exclusions=None, exes=None, **kwargs): 37 @property
38 def compile_targets(self):
39 """Returns the set of targets that need to be compiled based on the set of
40 files that have changed."""
41 return self._compile_targets
42
43 def does_patch_require_compile(self, exclusions=None, exes=None,
44 compile_targets=None, **kwargs):
37 """Return true if the current patch requires a build (and exes to run). 45 """Return true if the current patch requires a build (and exes to run).
38 Return value can be accessed by call to result(). 46 Return value can be accessed by call to result().
39 47
40 Args: 48 Args:
41 exclusions: list of python regular expressions (as strings). If any of 49 exclusions: list of python regular expressions (as strings). If any of
42 the files in the current patch match one of the values in |exclusions| 50 the files in the current patch match one of the values in |exclusions|
43 True is returned (by way of result()). 51 True is returned (by way of result()).
44 exes: the possible set of executables that are desired to run. When done 52 exes: the possible set of executables that are desired to run. When done
45 matching_exes() returns the set of exes that are effected by the files 53 matching_exes() returns the set of exes that are effected by the files
46 that have changed.""" 54 that have changed.
55 compile_targets: proposed set of targets to compile."""
47 56
48 exclusions = exclusions or self.m.properties.get('filter_exclusions', []) 57 exclusions = exclusions or self.m.properties.get('filter_exclusions', [])
49 self._matching_exes = exes or self.m.properties.get('matching_exes', []) 58 self._matching_exes = exes or self.m.properties.get('matching_exes', [])
59 self._compile_targets = compile_targets or \
60 self.m.properties.get('compile_targets', [])
50 61
51 # Get the set of files in the current patch. 62 # Get the set of files in the current patch.
52 step_result = self.m.git('diff', '--cached', '--name-only', 63 step_result = self.m.git('diff', '--cached', '--name-only',
53 name='git diff to analyze patch', 64 name='git diff to analyze patch',
54 stdout=self.m.raw_io.output(), 65 stdout=self.m.raw_io.output(),
55 step_test_data=lambda: 66 step_test_data=lambda:
56 self.m.raw_io.test_api.stream_output('foo.cc')) 67 self.m.raw_io.test_api.stream_output('foo.cc'))
57 68
58 # Check the path of each file against the exclusion list. If found, no need 69 # Check the path of each file against the exclusion list. If found, no need
59 # to check dependencies. 70 # to check dependencies.
60 exclusion_regexs = [re.compile(exclusion) for exclusion in exclusions] 71 exclusion_regexs = [re.compile(exclusion) for exclusion in exclusions]
61 paths = [] 72 paths = []
62 for path in step_result.stdout.split(): 73 for path in step_result.stdout.split():
63 paths.append(path) 74 paths.append(path)
64 first_match = self.__is_path_in_exclusion_list(path, exclusion_regexs) 75 first_match = self.__is_path_in_exclusion_list(path, exclusion_regexs)
65 if first_match: 76 if first_match:
66 step_result.presentation.logs.setdefault('excluded_files', []).append( 77 step_result.presentation.logs.setdefault('excluded_files', []).append(
67 '%s (regex = \'%s\')' % (path, first_match)) 78 '%s (regex = \'%s\')' % (path, first_match))
68 self._result = 1 79 self._result = True
69 return 80 return
70 81
71 analyze_input = {'files': paths, 'targets': self._matching_exes} 82 analyze_input = {'files': paths, 'targets': self._matching_exes}
72 83
73 test_output = {'status': 'No dependency', 'targets': []} 84 test_output = {'status': 'No dependency',
85 'targets': [],
86 'build_targets': []}
74 87
75 kwargs.setdefault('env', {}) 88 kwargs.setdefault('env', {})
76 kwargs['env'].update(self.m.chromium.c.gyp_env.as_jsonish()) 89 kwargs['env'].update(self.m.chromium.c.gyp_env.as_jsonish())
77 90
78 try: 91 try:
79 step_result = self.m.python('analyze', 92 step_result = self.m.python('analyze',
80 self.m.path['checkout'].join('build', 'gyp_chromium'), 93 self.m.path['checkout'].join('build', 'gyp_chromium'),
81 args=['--analyzer', 94 args=['--analyzer',
82 self.m.json.input(analyze_input), 95 self.m.json.input(analyze_input),
83 self.m.json.output()], 96 self.m.json.output()],
84 step_test_data=lambda: self.m.json.test_api.output( 97 step_test_data=lambda: self.m.json.test_api.output(
85 test_output), 98 test_output),
86 **kwargs) 99 **kwargs)
87 except self.m.step.StepFailure as f: 100 except self.m.step.StepFailure as f:
88 # Continue on if there is an error executing python. Most likely runhooks 101 # Continue on if there is an error executing python. Most likely runhooks
89 # will fail too, but errors there are more well understood than here. 102 # will fail too, but errors there are more well understood than here.
90 self._result = True 103 self._result = True
91 step_result = f.result 104 step_result = f.result
92 step_result.presentation.status = 'WARNING' 105 step_result.presentation.status = 'WARNING'
93 return 106 return
94 107
95 if 'error' in step_result.json.output: 108 if 'error' in step_result.json.output:
96 self._result = True 109 self._result = True
97 step_result.presentation.step_text = 'Error: ' + \ 110 step_result.presentation.step_text = 'Error: ' + \
98 step_result.json.output['error'] 111 step_result.json.output['error']
99 elif step_result.json.output['status'] == 'Found dependency' or \ 112 elif step_result.json.output['status'] == 'Found dependency':
100 step_result.json.output['status'] == 'Found dependency (all)': 113 self._result = True
101 self._matching_exes = step_result.json.output['targets'] 114 self._matching_exes = step_result.json.output['targets']
115 self._compile_targets = step_result.json.output['build_targets']
116 elif step_result.json.output['status'] == 'Found dependency (all)':
102 self._result = True 117 self._result = True
103 else: 118 else:
104 step_result.presentation.step_text = 'No compile necessary' 119 step_result.presentation.step_text = 'No compile necessary'
OLDNEW
« no previous file with comments | « no previous file | scripts/slave/recipe_modules/filter/example.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698