| 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 |