Home | History | Annotate | Download | only in buildbot
      1 #!/usr/bin/env python
      2 # Copyright (c) 2013 The Chromium Authors. All rights reserved.
      3 # Use of this source code is governed by a BSD-style license that can be
      4 # found in the LICENSE file.
      5 #
      6 """Logic to generate lists of DEPS used by various parts of
      7 the android_webview continuous integration (buildbot) infrastructure.
      8 
      9 Note: The root Chromium project (which is not explicitly listed here)
     10 has a couple of third_party libraries checked in directly into it. This means
     11 that the list of third parties present in this file is not a comprehensive
     12 list of third party android_webview dependencies.
     13 """
     14 
     15 import argparse
     16 import json
     17 import logging
     18 import os
     19 import sys
     20 
     21 
     22 class DepsWhitelist(object):
     23   def __init__(self):
     24     # If a new DEPS entry is needed for the AOSP bot to compile please add it
     25     # here first.
     26     # This is a staging area for deps that are accepted by the android_webview
     27     # team and are in the process of having the required branches being created
     28     # in the Android tree.
     29     self._compile_but_not_snapshot_dependencies = [
     30       'third_party/mesa/src',
     31     ]
     32 
     33     # Dependencies that need to be merged into the Android tree.
     34     self._snapshot_into_android_dependencies = [
     35       'sdch/open-vcdiff',
     36       'testing/gtest',
     37       'third_party/WebKit',
     38       'third_party/angle_dx11',
     39       ('third_party/eyesfree/src/android/java/src/com/googlecode/eyesfree/'
     40        'braille'),
     41       'third_party/freetype',
     42       'third_party/icu',
     43       'third_party/leveldatabase/src',
     44       'third_party/libjingle/source/talk',
     45       'third_party/libphonenumber/src/phonenumbers',
     46       'third_party/libphonenumber/src/resources',
     47       'third_party/openssl',
     48       'third_party/opus/src',
     49       'third_party/ots',
     50       'third_party/skia/gyp',
     51       'third_party/skia/include',
     52       'third_party/skia/src',
     53       'third_party/smhasher/src',
     54       'third_party/v8-i18n',
     55       'third_party/yasm/source/patched-yasm',
     56       'tools/grit',
     57       'tools/gyp',
     58       'v8',
     59     ]
     60 
     61     # Dependencies required to build android_webview.
     62     self._compile_dependencies = (self._snapshot_into_android_dependencies +
     63                                   self._compile_but_not_snapshot_dependencies)
     64 
     65     # Dependencies required to run android_webview tests but not required to
     66     # compile.
     67     self._test_data_dependencies = [
     68       'chrome/test/data/perf/third_party/octane',
     69     ]
     70 
     71   @staticmethod
     72   def _read_deps_file(deps_file_path):
     73     class FileImplStub(object):
     74       """Stub for the File syntax."""
     75       def __init__(self, file_location):
     76         pass
     77 
     78       @staticmethod
     79       def GetPath():
     80         return ''
     81 
     82       @staticmethod
     83       def GetFilename():
     84         return ''
     85 
     86       @staticmethod
     87       def GetRevision():
     88         return None
     89 
     90     def from_stub(__, _=None):
     91       """Stub for the From syntax."""
     92       return ''
     93 
     94     class VarImpl(object):
     95       def __init__(self, custom_vars, local_scope):
     96         self._custom_vars = custom_vars
     97         self._local_scope = local_scope
     98 
     99       def Lookup(self, var_name):
    100         """Implements the Var syntax."""
    101         if var_name in self._custom_vars:
    102           return self._custom_vars[var_name]
    103         elif var_name in self._local_scope.get("vars", {}):
    104           return self._local_scope["vars"][var_name]
    105         raise Exception("Var is not defined: %s" % var_name)
    106 
    107     local_scope = {}
    108     var = VarImpl({}, local_scope)
    109     global_scope = {
    110         'File': FileImplStub,
    111         'From': from_stub,
    112         'Var': var.Lookup,
    113         'deps_os': {},
    114     }
    115     execfile(deps_file_path, global_scope, local_scope)
    116     deps = local_scope.get('deps', {})
    117     deps_os = local_scope.get('deps_os', {})
    118     for os_specific_deps in deps_os.itervalues():
    119       deps.update(os_specific_deps)
    120     return deps.keys()
    121 
    122   def _make_gclient_blacklist(self, deps_file_path, whitelisted_deps):
    123     """Calculates the list of deps that need to be excluded from the deps_file
    124     so that the only deps left are the one in the whitelist."""
    125     all_deps = self._read_deps_file(deps_file_path)
    126     # The list of deps read from the DEPS file are prefixed with the source
    127     # tree root, which is 'src' for Chromium.
    128     def prepend_root(path):
    129       return os.path.join('src', path)
    130     whitelisted_deps = map(prepend_root, whitelisted_deps)
    131     deps_blacklist = set(all_deps).difference(set(whitelisted_deps))
    132     return dict(map(lambda(x): (x, None), deps_blacklist))
    133 
    134   def get_deps_for_android_build(self, deps_file_path):
    135     """This is used to calculate the custom_deps list for the Android bot.
    136     """
    137     if not deps_file_path:
    138       raise Exception('You need to specify a DEPS file path.')
    139     return self._make_gclient_blacklist(deps_file_path,
    140                                         self._compile_dependencies)
    141 
    142   def get_deps_for_android_build_and_test(self, deps_file_path):
    143     """This is used to calculate the custom_deps list for the Android perf bot.
    144     """
    145     if not deps_file_path:
    146       raise Exception('You need to specify a DEPS file path.')
    147     return self._make_gclient_blacklist(deps_file_path,
    148                                         self._compile_dependencies +
    149                                         self._test_data_dependencies)
    150 
    151   def get_deps_for_android_merge(self, _):
    152     """Calculates the list of deps that need to be merged into the Android tree
    153     in order to build the C++ and Java android_webview code."""
    154     return self._snapshot_into_android_dependencies
    155 
    156   def get_deps_for_license_check(self, _):
    157     """Calculates the list of deps that need to be checked for Android license
    158     compatibility"""
    159     return self._compile_dependencies
    160 
    161   def execute_method(self, method_name, deps_file_path):
    162     methods = {
    163       'android_build': self.get_deps_for_android_build,
    164       'android_build_and_test':
    165         self.get_deps_for_android_build_and_test,
    166       'android_merge': self.get_deps_for_android_merge,
    167       'license_check': self.get_deps_for_license_check
    168     }
    169     if not method_name in methods:
    170       raise Exception('Method name %s is not valid. Valid choices are %s' %
    171                       (method_name, methods.keys()))
    172     return methods[method_name](deps_file_path)
    173 
    174 def main():
    175   parser = argparse.ArgumentParser()
    176   parser.add_argument('--method', help='Method to use to fetch from whitelist.',
    177                       required=True)
    178   parser.add_argument('--path-to-deps', help='Path to DEPS file.')
    179   parser.add_argument('--output-json', help='Name of file to write output to.')
    180   parser.add_argument('verbose', action='store_true', default=False)
    181   opts = parser.parse_args()
    182 
    183   logging.getLogger().setLevel(logging.DEBUG if opts.verbose else logging.WARN)
    184 
    185   deps_whitelist = DepsWhitelist()
    186   blacklist = deps_whitelist.execute_method(opts.method, opts.path_to_deps)
    187 
    188   if (opts.output_json):
    189     output_dict = {
    190         'blacklist' : blacklist
    191     }
    192     with open(opts.output_json, 'w') as output_json_file:
    193       json.dump(output_dict, output_json_file)
    194   else:
    195     print blacklist
    196 
    197   return 0
    198 
    199 
    200 if __name__ == '__main__':
    201   sys.exit(main())
    202