| #!/usr/bin/env python | 
 | # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
 | # Use of this source code is governed by a BSD-style license that can be | 
 | # found in the LICENSE file. | 
 |  | 
 | """ | 
 | This script runs every build as the first hook (See DEPS). If it detects that | 
 | the build should be clobbered, it will delete the contents of the build | 
 | directory. | 
 |  | 
 | A landmine is tripped when a builder checks out a different revision, and the | 
 | diff between the new landmines and the old ones is non-null. At this point, the | 
 | build is clobbered. | 
 | """ | 
 |  | 
 | import difflib | 
 | import errno | 
 | import gyp_environment | 
 | import logging | 
 | import optparse | 
 | import os | 
 | import sys | 
 | import subprocess | 
 | import time | 
 |  | 
 | import clobber | 
 | import landmine_utils | 
 |  | 
 |  | 
 | def get_build_dir(src_dir): | 
 |   """ | 
 |   Returns output directory absolute path dependent on build and targets. | 
 |   Examples: | 
 |     r'c:\b\build\slave\win\build\src\out' | 
 |     '/mnt/data/b/build/slave/linux/build/src/out' | 
 |     '/b/build/slave/ios_rel_device/build/src/out' | 
 |  | 
 |   Keep this function in sync with tools/build/scripts/slave/compile.py | 
 |   """ | 
 |   if 'CHROMIUM_OUT_DIR' in os.environ: | 
 |     output_dir = os.environ.get('CHROMIUM_OUT_DIR').strip() | 
 |     if not output_dir: | 
 |       raise Error('CHROMIUM_OUT_DIR environment variable is set but blank!') | 
 |   else: | 
 |     output_dir = landmine_utils.gyp_generator_flags().get('output_dir', 'out') | 
 |   return os.path.abspath(os.path.join(src_dir, output_dir)) | 
 |  | 
 |  | 
 | def clobber_if_necessary(new_landmines, src_dir): | 
 |   """Does the work of setting, planting, and triggering landmines.""" | 
 |   out_dir = get_build_dir(src_dir) | 
 |   landmines_path = os.path.normpath(os.path.join(src_dir, '.landmines')) | 
 |   try: | 
 |     os.makedirs(out_dir) | 
 |   except OSError as e: | 
 |     if e.errno == errno.EEXIST: | 
 |       pass | 
 |  | 
 |   if os.path.exists(landmines_path): | 
 |     with open(landmines_path, 'r') as f: | 
 |       old_landmines = f.readlines() | 
 |     if old_landmines != new_landmines: | 
 |       old_date = time.ctime(os.stat(landmines_path).st_ctime) | 
 |       diff = difflib.unified_diff(old_landmines, new_landmines, | 
 |           fromfile='old_landmines', tofile='new_landmines', | 
 |           fromfiledate=old_date, tofiledate=time.ctime(), n=0) | 
 |       sys.stdout.write('Clobbering due to:\n') | 
 |       sys.stdout.writelines(diff) | 
 |       sys.stdout.flush() | 
 |  | 
 |       clobber.clobber(out_dir) | 
 |  | 
 |   # Save current set of landmines for next time. | 
 |   with open(landmines_path, 'w') as f: | 
 |     f.writelines(new_landmines) | 
 |  | 
 |  | 
 | def process_options(): | 
 |   """Returns an options object containing the configuration for this script.""" | 
 |   parser = optparse.OptionParser() | 
 |   parser.add_option( | 
 |       '-s', '--landmine-scripts', action='append', | 
 |       help='Path to the script which emits landmines to stdout. The target ' | 
 |            'is passed to this script via option -t. Note that an extra ' | 
 |            'script can be specified via an env var EXTRA_LANDMINES_SCRIPT.') | 
 |   parser.add_option('-d', '--src-dir', | 
 |       help='Path of the source root dir. Overrides the default location of the ' | 
 |            'source root dir when calculating the build directory.') | 
 |   parser.add_option('-v', '--verbose', action='store_true', | 
 |       default=('LANDMINES_VERBOSE' in os.environ), | 
 |       help=('Emit some extra debugging information (default off). This option ' | 
 |           'is also enabled by the presence of a LANDMINES_VERBOSE environment ' | 
 |           'variable.')) | 
 |  | 
 |   options, args = parser.parse_args() | 
 |  | 
 |   if args: | 
 |     parser.error('Unknown arguments %s' % args) | 
 |  | 
 |   logging.basicConfig( | 
 |       level=logging.DEBUG if options.verbose else logging.ERROR) | 
 |  | 
 |   if options.src_dir: | 
 |     if not os.path.isdir(options.src_dir): | 
 |       parser.error('Cannot find source root dir at %s' % options.src_dir) | 
 |     logging.debug('Overriding source root dir. Using: %s', options.src_dir) | 
 |   else: | 
 |     options.src_dir = \ | 
 |         os.path.dirname(os.path.dirname(os.path.realpath(__file__))) | 
 |  | 
 |   if not options.landmine_scripts: | 
 |     options.landmine_scripts = [os.path.join(options.src_dir, 'build', | 
 |                                              'get_landmines.py')] | 
 |  | 
 |   extra_script = os.environ.get('EXTRA_LANDMINES_SCRIPT') | 
 |   if extra_script: | 
 |     options.landmine_scripts += [extra_script] | 
 |  | 
 |   return options | 
 |  | 
 |  | 
 | def main(): | 
 |   options = process_options() | 
 |  | 
 |   gyp_environment.SetEnvironment() | 
 |  | 
 |   landmines = [] | 
 |   for s in options.landmine_scripts: | 
 |     proc = subprocess.Popen([sys.executable, s], stdout=subprocess.PIPE) | 
 |     output, _ = proc.communicate() | 
 |     landmines.extend([('%s\n' % l.strip()) for l in output.splitlines()]) | 
 |   clobber_if_necessary(landmines, options.src_dir) | 
 |  | 
 |   return 0 | 
 |  | 
 |  | 
 | if __name__ == '__main__': | 
 |   sys.exit(main()) |