tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

landmines.py (5155B)


      1 #!/usr/bin/env python3
      2 # Copyright 2012 The Chromium Authors
      3 # Use of this source code is governed by a BSD-style license that can be
      4 # found in the LICENSE file.
      5 
      6 """
      7 This script runs every gclient runhooks as the first hook (See DEPS). If it
      8 detects that the build should be clobbered, it will delete the contents of the
      9 build directory.
     10 
     11 A landmine is tripped when a builder checks out a different revision, and the
     12 diff between the new landmines and the old ones is non-null. At this point, the
     13 build is clobbered.
     14 
     15 Before adding or changing a landmine consider the consequences of doing so.
     16 Doing so will wipe out every output directory on every Chrome developer's
     17 machine. This can be particularly problematic on Windows where the directory
     18 deletion may well fail (locked files, command prompt in the directory, etc.),
     19 and generated .sln and .vcxproj files will be deleted.
     20 
     21 This output directory deletion will be repeated when going back and forth across
     22 the change that added the landmine, adding to the cost. There are usually less
     23 troublesome alternatives.
     24 """
     25 
     26 import difflib
     27 import errno
     28 import logging
     29 import optparse
     30 import os
     31 import sys
     32 import subprocess
     33 import time
     34 
     35 import clobber
     36 import landmine_utils
     37 
     38 
     39 def get_build_dir(src_dir):
     40  r"""
     41  Returns the absolute path to the directory containing the build directories.
     42  Examples:
     43    'C:\src\out'
     44    '/b/s/w/ir/cache/builder/src/out'
     45  """
     46  if 'CHROMIUM_OUT_DIR' in os.environ:
     47    output_dir = os.environ.get('CHROMIUM_OUT_DIR').strip()
     48    if not output_dir:
     49      raise Error('CHROMIUM_OUT_DIR environment variable is set but blank!')
     50  else:
     51    output_dir = 'out'
     52  return os.path.abspath(os.path.join(src_dir, output_dir))
     53 
     54 
     55 def clobber_if_necessary(new_landmines, src_dir, landmines_path):
     56  """Does the work of setting, planting, and triggering landmines."""
     57  out_dir = get_build_dir(src_dir)
     58  try:
     59    os.makedirs(out_dir)
     60  except OSError as e:
     61    if e.errno == errno.EEXIST:
     62      pass
     63 
     64  if os.path.exists(landmines_path):
     65    with open(landmines_path, 'r') as f:
     66      old_landmines = f.readlines()
     67    if old_landmines != new_landmines:
     68      old_date = time.ctime(os.stat(landmines_path).st_ctime)
     69      diff = difflib.unified_diff(old_landmines, new_landmines,
     70          fromfile='old_landmines', tofile='new_landmines',
     71          fromfiledate=old_date, tofiledate=time.ctime(), n=0)
     72      sys.stdout.write('Clobbering due to:\n')
     73      sys.stdout.writelines(diff)
     74      sys.stdout.flush()
     75 
     76      clobber.clobber(out_dir)
     77 
     78  # Save current set of landmines for next time.
     79  with open(landmines_path, 'w') as f:
     80    f.writelines(new_landmines)
     81 
     82 
     83 def process_options():
     84  """Returns an options object containing the configuration for this script."""
     85  parser = optparse.OptionParser()
     86  parser.add_option(
     87      '-s', '--landmine-scripts', action='append',
     88      help='Path to the script which emits landmines to stdout. The target '
     89           'is passed to this script via option -t. Note that an extra '
     90           'script can be specified via an env var EXTRA_LANDMINES_SCRIPT.')
     91  parser.add_option('-d', '--src-dir',
     92      help='Path of the source root dir. Overrides the default location of the '
     93           'source root dir when calculating the build directory.')
     94  parser.add_option(
     95      '-l',
     96      '--landmines-path',
     97      help='Path to the landmines file to use (defaults to .landmines)')
     98  parser.add_option('-v', '--verbose', action='store_true',
     99      default=('LANDMINES_VERBOSE' in os.environ),
    100      help=('Emit some extra debugging information (default off). This option '
    101          'is also enabled by the presence of a LANDMINES_VERBOSE environment '
    102          'variable.'))
    103 
    104  options, args = parser.parse_args()
    105 
    106  if args:
    107    parser.error('Unknown arguments %s' % args)
    108 
    109  logging.basicConfig(
    110      level=logging.DEBUG if options.verbose else logging.ERROR)
    111 
    112  if options.src_dir:
    113    if not os.path.isdir(options.src_dir):
    114      parser.error('Cannot find source root dir at %s' % options.src_dir)
    115    logging.debug('Overriding source root dir. Using: %s', options.src_dir)
    116  else:
    117    options.src_dir = \
    118        os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
    119 
    120  if not options.landmine_scripts:
    121    options.landmine_scripts = [os.path.join(options.src_dir, 'build',
    122                                             'get_landmines.py')]
    123 
    124  extra_script = os.environ.get('EXTRA_LANDMINES_SCRIPT')
    125  if extra_script:
    126    options.landmine_scripts += [extra_script]
    127 
    128  return options
    129 
    130 
    131 def main():
    132  options = process_options()
    133 
    134  landmines = []
    135  for s in options.landmine_scripts:
    136    proc = subprocess.Popen([sys.executable, s], stdout=subprocess.PIPE,
    137                            universal_newlines=True)
    138    output, _ = proc.communicate()
    139    landmines.extend([('%s\n' % l.strip()) for l in output.splitlines()])
    140  if options.landmines_path:
    141    landmines_path = options.landmines_path
    142  else:
    143    landmines_path = os.path.join(options.src_dir, '.landmines')
    144  clobber_if_necessary(landmines, options.src_dir,
    145                       os.path.normpath(landmines_path))
    146 
    147  return 0
    148 
    149 
    150 if __name__ == '__main__':
    151  sys.exit(main())