OLD | NEW |
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 | 7 This file holds a list of reasons why a particular build needs to be clobbered |
8 (or a list of 'landmines'). | 8 (or a list of 'landmines'). |
9 | 9 |
10 This script runs every build as a hook. If it detects that the build should | 10 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 | 11 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 | 12 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. | 13 accordingly. The script will also emit the reasons for the clobber to stdout. |
14 | 14 |
15 A landmine is tripped when a builder checks out a different revision, and the | 15 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 | 16 diff between the new landmines and the old ones is non-null. At this point, the |
17 build is clobbered. | 17 build is clobbered. |
18 """ | 18 """ |
19 | 19 |
20 import difflib | 20 import difflib |
21 import functools | 21 import functools |
22 import gyp_helper | 22 import gyp_helper |
| 23 import logging |
| 24 import optparse |
23 import os | 25 import os |
24 import shlex | 26 import shlex |
25 import sys | 27 import sys |
26 import time | 28 import time |
27 | 29 |
28 SRC_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) | 30 SRC_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) |
29 | 31 |
30 def memoize(default=None): | 32 def memoize(default=None): |
31 """This decorator caches the return value of a parameterless pure function""" | 33 """This decorator caches the return value of a parameterless pure function""" |
32 def memoizer(func): | 34 def memoizer(func): |
33 val = [] | 35 val = [] |
34 @functools.wraps(func) | 36 @functools.wraps(func) |
35 def inner(): | 37 def inner(): |
36 if not val: | 38 if not val: |
37 ret = func() | 39 ret = func() |
38 val.append(ret if ret is not None else default) | 40 val.append(ret if ret is not None else default) |
39 print '%s -> %r' % (func.__name__, val[0]) | 41 if logging.getLogger().isEnabledFor(logging.INFO): |
| 42 print '%s -> %r' % (func.__name__, val[0]) |
40 return val[0] | 43 return val[0] |
41 return inner | 44 return inner |
42 return memoizer | 45 return memoizer |
43 | 46 |
44 | 47 |
45 @memoize() | 48 @memoize() |
46 def IsWindows(): | 49 def IsWindows(): |
47 return sys.platform.startswith('win') or sys.platform == 'cygwin' | 50 return sys.platform.startswith('win') or sys.platform == 'cygwin' |
48 | 51 |
49 | 52 |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
160 ret = os.path.join(SRC_DIR, 'out', target) | 163 ret = os.path.join(SRC_DIR, 'out', target) |
161 elif build_tool == 'msvs': | 164 elif build_tool == 'msvs': |
162 ret = os.path.join(SRC_DIR, 'build', target) | 165 ret = os.path.join(SRC_DIR, 'build', target) |
163 elif build_tool == 'scons': | 166 elif build_tool == 'scons': |
164 ret = os.path.join(SRC_DIR, 'sconsbuild', target) | 167 ret = os.path.join(SRC_DIR, 'sconsbuild', target) |
165 else: | 168 else: |
166 raise NotImplementedError() | 169 raise NotImplementedError() |
167 return os.path.abspath(ret) | 170 return os.path.abspath(ret) |
168 | 171 |
169 | 172 |
170 def main(argv): | 173 def set_up_landmines(target): |
171 if len(argv) > 1: | 174 """Does the work of setting, planting, and triggering landmines.""" |
172 print('Unknown arguments %s' % argv[1:]) | 175 out_dir = get_target_build_dir(builder(), target, platform() == 'ios') |
173 return 1 | 176 |
| 177 landmines_path = os.path.join(out_dir, '.landmines') |
| 178 if not os.path.exists(out_dir): |
| 179 os.makedirs(out_dir) |
| 180 |
| 181 new_landmines = get_landmines(target) |
| 182 |
| 183 if not os.path.exists(landmines_path): |
| 184 with open(landmines_path, 'w') as f: |
| 185 f.writelines(new_landmines) |
| 186 else: |
| 187 triggered = os.path.join(out_dir, '.landmines_triggered') |
| 188 with open(landmines_path, 'r') as f: |
| 189 old_landmines = f.readlines() |
| 190 if old_landmines != new_landmines: |
| 191 old_date = time.ctime(os.stat(landmines_path).st_ctime) |
| 192 diff = difflib.unified_diff(old_landmines, new_landmines, |
| 193 fromfile='old_landmines', tofile='new_landmines', |
| 194 fromfiledate=old_date, tofiledate=time.ctime(), n=0) |
| 195 |
| 196 with open(triggered, 'w') as f: |
| 197 f.writelines(diff) |
| 198 elif os.path.exists(triggered): |
| 199 # Remove false triggered landmines. |
| 200 os.remove(triggered) |
| 201 |
| 202 |
| 203 def main(): |
| 204 parser = optparse.OptionParser() |
| 205 parser.add_option('-v', '--verbose', action='store_true', |
| 206 default=('LANDMINES_VERBOSE' in os.environ), |
| 207 help=('Emit some extra debugging information (default off). This option ' |
| 208 'is also enabled by the presence of a LANDMINES_VERBOSE environment ' |
| 209 'variable.')) |
| 210 options, args = parser.parse_args() |
| 211 |
| 212 if args: |
| 213 parser.error('Unknown arguments %s' % args) |
| 214 |
| 215 logging.basicConfig( |
| 216 level=logging.DEBUG if options.verbose else logging.ERROR) |
174 | 217 |
175 gyp_helper.apply_chromium_gyp_env() | 218 gyp_helper.apply_chromium_gyp_env() |
176 | 219 |
177 for target in ('Debug', 'Release'): | 220 for target in ('Debug', 'Release'): |
178 out_dir = get_target_build_dir(builder(), target, | 221 set_up_landmines(target) |
179 platform() == 'ios') | |
180 | |
181 landmines_path = os.path.join(out_dir, '.landmines') | |
182 if not os.path.exists(out_dir): | |
183 os.makedirs(out_dir) | |
184 | |
185 new_landmines = get_landmines(target) | |
186 | |
187 if not os.path.exists(landmines_path): | |
188 with open(landmines_path, 'w') as f: | |
189 f.writelines(new_landmines) | |
190 else: | |
191 triggered = os.path.join(out_dir, '.landmines_triggered') | |
192 with open(landmines_path, 'r') as f: | |
193 old_landmines = f.readlines() | |
194 if old_landmines != new_landmines: | |
195 old_date = time.ctime(os.stat(landmines_path).st_ctime) | |
196 diff = difflib.unified_diff(old_landmines, new_landmines, | |
197 fromfile='old_landmines', tofile='new_landmines', | |
198 fromfiledate=old_date, tofiledate=time.ctime(), n=0) | |
199 | |
200 with open(triggered, 'w') as f: | |
201 f.writelines(diff) | |
202 elif os.path.exists(triggered): | |
203 # Remove false triggered landmines. | |
204 os.remove(triggered) | |
205 | 222 |
206 return 0 | 223 return 0 |
207 | 224 |
208 | 225 |
209 if __name__ == '__main__': | 226 if __name__ == '__main__': |
210 sys.exit(main(sys.argv)) | 227 sys.exit(main()) |
OLD | NEW |