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

Side by Side Diff: build/landmines.py

Issue 22935010: Refactor landmines.py so that it can be used downstream. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Use sys.executable to invoke the landmines scripts. Created 7 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 | Annotate | Revision Log
« no previous file with comments | « build/landmine_utils.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """ 6 """
7 This file holds a list of reasons why a particular build needs to be clobbered
8 (or a list of 'landmines').
9
10 This script runs every build as a hook. If it detects that the build should 7 This script runs every build as a hook. If it detects that the build should
11 be clobbered, it will touch the file <build_dir>/.landmine_triggered. The 8 be clobbered, it will touch the file <build_dir>/.landmine_triggered. The
12 various build scripts will then check for the presence of this file and clobber 9 various build scripts will then check for the presence of this file and clobber
13 accordingly. The script will also emit the reasons for the clobber to stdout. 10 accordingly. The script will also emit the reasons for the clobber to stdout.
14 11
15 A landmine is tripped when a builder checks out a different revision, and the 12 A landmine is tripped when a builder checks out a different revision, and the
16 diff between the new landmines and the old ones is non-null. At this point, the 13 diff between the new landmines and the old ones is non-null. At this point, the
17 build is clobbered. 14 build is clobbered.
18 """ 15 """
19 16
20 import difflib 17 import difflib
21 import functools
22 import gyp_helper 18 import gyp_helper
23 import logging 19 import logging
24 import optparse 20 import optparse
25 import os 21 import os
26 import shlex
27 import sys 22 import sys
23 import subprocess
28 import time 24 import time
29 25
26 import landmine_utils
27
28
30 SRC_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) 29 SRC_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
31 30
32 def memoize(default=None):
33 """This decorator caches the return value of a parameterless pure function"""
34 def memoizer(func):
35 val = []
36 @functools.wraps(func)
37 def inner():
38 if not val:
39 ret = func()
40 val.append(ret if ret is not None else default)
41 if logging.getLogger().isEnabledFor(logging.INFO):
42 print '%s -> %r' % (func.__name__, val[0])
43 return val[0]
44 return inner
45 return memoizer
46
47
48 @memoize()
49 def IsWindows():
50 return sys.platform in ['win32', 'cygwin']
51
52
53 @memoize()
54 def IsLinux():
55 return sys.platform.startswith('linux')
56
57
58 @memoize()
59 def IsMac():
60 return sys.platform == 'darwin'
61
62
63 @memoize()
64 def gyp_defines():
65 """Parses and returns GYP_DEFINES env var as a dictionary."""
66 return dict(arg.split('=', 1)
67 for arg in shlex.split(os.environ.get('GYP_DEFINES', '')))
68
69 @memoize()
70 def gyp_msvs_version():
71 return os.environ.get('GYP_MSVS_VERSION', '')
72
73 @memoize()
74 def distributor():
75 """
76 Returns a string which is the distributed build engine in use (if any).
77 Possible values: 'goma', 'ib', ''
78 """
79 if 'goma' in gyp_defines():
80 return 'goma'
81 elif IsWindows():
82 if 'CHROME_HEADLESS' in os.environ:
83 return 'ib' # use (win and !goma and headless) as approximation of ib
84
85
86 @memoize()
87 def platform():
88 """
89 Returns a string representing the platform this build is targetted for.
90 Possible values: 'win', 'mac', 'linux', 'ios', 'android'
91 """
92 if 'OS' in gyp_defines():
93 if 'android' in gyp_defines()['OS']:
94 return 'android'
95 else:
96 return gyp_defines()['OS']
97 elif IsWindows():
98 return 'win'
99 elif IsLinux():
100 return 'linux'
101 else:
102 return 'mac'
103
104
105 @memoize()
106 def builder():
107 """
108 Returns a string representing the build engine (not compiler) to use.
109 Possible values: 'make', 'ninja', 'xcode', 'msvs', 'scons'
110 """
111 if 'GYP_GENERATORS' in os.environ:
112 # for simplicity, only support the first explicit generator
113 generator = os.environ['GYP_GENERATORS'].split(',')[0]
114 if generator.endswith('-android'):
115 return generator.split('-')[0]
116 elif generator.endswith('-ninja'):
117 return 'ninja'
118 else:
119 return generator
120 else:
121 if platform() == 'android':
122 # Good enough for now? Do any android bots use make?
123 return 'ninja'
124 elif platform() == 'ios':
125 return 'xcode'
126 elif IsWindows():
127 return 'msvs'
128 elif IsLinux():
129 return 'ninja'
130 elif IsMac():
131 return 'xcode'
132 else:
133 assert False, 'Don\'t know what builder we\'re using!'
134
135
136 def get_landmines(target):
137 """
138 ALL LANDMINES ARE DEFINED HERE.
139 target is 'Release' or 'Debug'
140 """
141 landmines = []
142 add = lambda item: landmines.append(item + '\n')
143
144 if (distributor() == 'goma' and platform() == 'win32' and
145 builder() == 'ninja'):
146 add('Need to clobber winja goma due to backend cwd cache fix.')
147 if platform() == 'android':
148 add('Clobber: Resources removed in r195014 require clobber.')
149 if platform() == 'win' and builder() == 'ninja':
150 add('Compile on cc_unittests fails due to symbols removed in r185063.')
151 if platform() == 'linux' and builder() == 'ninja':
152 add('Builders switching from make to ninja will clobber on this.')
153 if platform() == 'mac':
154 add('Switching from bundle to unbundled dylib (issue 14743002).')
155 if (platform() == 'win' and builder() == 'ninja' and
156 gyp_msvs_version() == '2012' and
157 gyp_defines().get('target_arch') == 'x64' and
158 gyp_defines().get('dcheck_always_on') == '1'):
159 add("Switched win x64 trybots from VS2010 to VS2012.")
160 add('Need to clobber everything due to an IDL change in r154579 (blink)')
161
162 return landmines
163
164 31
165 def get_target_build_dir(build_tool, target, is_iphone=False): 32 def get_target_build_dir(build_tool, target, is_iphone=False):
166 """ 33 """
167 Returns output directory absolute path dependent on build and targets. 34 Returns output directory absolute path dependent on build and targets.
168 Examples: 35 Examples:
169 r'c:\b\build\slave\win\build\src\out\Release' 36 r'c:\b\build\slave\win\build\src\out\Release'
170 '/mnt/data/b/build/slave/linux/build/src/out/Debug' 37 '/mnt/data/b/build/slave/linux/build/src/out/Debug'
171 '/b/build/slave/ios_rel_device/build/src/xcodebuild/Release-iphoneos' 38 '/b/build/slave/ios_rel_device/build/src/xcodebuild/Release-iphoneos'
172 39
173 Keep this function in sync with tools/build/scripts/slave/compile.py 40 Keep this function in sync with tools/build/scripts/slave/compile.py
174 """ 41 """
175 ret = None 42 ret = None
176 if build_tool == 'xcode': 43 if build_tool == 'xcode':
177 ret = os.path.join(SRC_DIR, 'xcodebuild', 44 ret = os.path.join(SRC_DIR, 'xcodebuild',
178 target + ('-iphoneos' if is_iphone else '')) 45 target + ('-iphoneos' if is_iphone else ''))
179 elif build_tool in ['make', 'ninja', 'ninja-ios']: # TODO: Remove ninja-ios. 46 elif build_tool in ['make', 'ninja', 'ninja-ios']: # TODO: Remove ninja-ios.
180 ret = os.path.join(SRC_DIR, 'out', target) 47 ret = os.path.join(SRC_DIR, 'out', target)
181 elif build_tool in ['msvs', 'vs', 'ib']: 48 elif build_tool in ['msvs', 'vs', 'ib']:
182 ret = os.path.join(SRC_DIR, 'build', target) 49 ret = os.path.join(SRC_DIR, 'build', target)
183 elif build_tool == 'scons': 50 elif build_tool == 'scons':
184 ret = os.path.join(SRC_DIR, 'sconsbuild', target) 51 ret = os.path.join(SRC_DIR, 'sconsbuild', target)
185 else: 52 else:
186 raise NotImplementedError('Unexpected GYP_GENERATORS (%s)' % build_tool) 53 raise NotImplementedError('Unexpected GYP_GENERATORS (%s)' % build_tool)
187 return os.path.abspath(ret) 54 return os.path.abspath(ret)
188 55
189 56
190 def set_up_landmines(target): 57 def set_up_landmines(target, new_landmines):
191 """Does the work of setting, planting, and triggering landmines.""" 58 """Does the work of setting, planting, and triggering landmines."""
192 out_dir = get_target_build_dir(builder(), target, platform() == 'ios') 59 out_dir = get_target_build_dir(landmine_utils.builder(), target,
60 landmine_utils.platform() == 'ios')
193 61
194 landmines_path = os.path.join(out_dir, '.landmines') 62 landmines_path = os.path.join(out_dir, '.landmines')
195 if not os.path.exists(out_dir): 63 if not os.path.exists(out_dir):
196 os.makedirs(out_dir) 64 os.makedirs(out_dir)
197 65
198 new_landmines = get_landmines(target)
199
200 if not os.path.exists(landmines_path): 66 if not os.path.exists(landmines_path):
201 with open(landmines_path, 'w') as f: 67 with open(landmines_path, 'w') as f:
202 f.writelines(new_landmines) 68 f.writelines(new_landmines)
203 else: 69 else:
204 triggered = os.path.join(out_dir, '.landmines_triggered') 70 triggered = os.path.join(out_dir, '.landmines_triggered')
205 with open(landmines_path, 'r') as f: 71 with open(landmines_path, 'r') as f:
206 old_landmines = f.readlines() 72 old_landmines = f.readlines()
207 if old_landmines != new_landmines: 73 if old_landmines != new_landmines:
208 old_date = time.ctime(os.stat(landmines_path).st_ctime) 74 old_date = time.ctime(os.stat(landmines_path).st_ctime)
209 diff = difflib.unified_diff(old_landmines, new_landmines, 75 diff = difflib.unified_diff(old_landmines, new_landmines,
210 fromfile='old_landmines', tofile='new_landmines', 76 fromfile='old_landmines', tofile='new_landmines',
211 fromfiledate=old_date, tofiledate=time.ctime(), n=0) 77 fromfiledate=old_date, tofiledate=time.ctime(), n=0)
212 78
213 with open(triggered, 'w') as f: 79 with open(triggered, 'w') as f:
214 f.writelines(diff) 80 f.writelines(diff)
215 elif os.path.exists(triggered): 81 elif os.path.exists(triggered):
216 # Remove false triggered landmines. 82 # Remove false triggered landmines.
217 os.remove(triggered) 83 os.remove(triggered)
218 84
219 85
220 def main(): 86 def main():
221 parser = optparse.OptionParser() 87 parser = optparse.OptionParser()
88 parser.add_option(
89 '-s', '--landmine-scripts', action='append',
90 default=[os.path.join(SRC_DIR, 'build', 'get_landmines.py')],
91 help='Path to the script which emits landmines to stdout. The target '
92 'is passed to this script via option -t.')
222 parser.add_option('-v', '--verbose', action='store_true', 93 parser.add_option('-v', '--verbose', action='store_true',
223 default=('LANDMINES_VERBOSE' in os.environ), 94 default=('LANDMINES_VERBOSE' in os.environ),
224 help=('Emit some extra debugging information (default off). This option ' 95 help=('Emit some extra debugging information (default off). This option '
225 'is also enabled by the presence of a LANDMINES_VERBOSE environment ' 96 'is also enabled by the presence of a LANDMINES_VERBOSE environment '
226 'variable.')) 97 'variable.'))
98
227 options, args = parser.parse_args() 99 options, args = parser.parse_args()
228 100
229 if args: 101 if args:
230 parser.error('Unknown arguments %s' % args) 102 parser.error('Unknown arguments %s' % args)
231 103
232 logging.basicConfig( 104 logging.basicConfig(
233 level=logging.DEBUG if options.verbose else logging.ERROR) 105 level=logging.DEBUG if options.verbose else logging.ERROR)
234 106
235 gyp_helper.apply_chromium_gyp_env() 107 gyp_helper.apply_chromium_gyp_env()
236 108
237 for target in ('Debug', 'Release', 'Debug_x64', 'Release_x64'): 109 for target in ('Debug', 'Release', 'Debug_x64', 'Release_x64'):
238 set_up_landmines(target) 110 landmines = []
111 for s in options.landmine_scripts:
112 print 'Getting landmines from `%s -t %s`' % (s, target)
jamesr 2013/08/22 20:37:32 Please revert this change. It's spewing useless c
113 proc = subprocess.Popen([sys.executable, s, '-t', target],
114 stdout=subprocess.PIPE)
115 output, _ = proc.communicate()
116 landmines.extend([('%s\n' % l.strip()) for l in output.splitlines()])
117 set_up_landmines(target, landmines)
239 118
240 return 0 119 return 0
241 120
242 121
243 if __name__ == '__main__': 122 if __name__ == '__main__':
244 sys.exit(main()) 123 sys.exit(main())
OLDNEW
« no previous file with comments | « build/landmine_utils.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698