Hash :
7108e069
Author :
Date :
2021-06-08T09:55:11
Roll Chromium from 3bcc8fd7c291 to 6c5859c895f5 (510 revisions)
https://chromium.googlesource.com/chromium/src.git/+log/3bcc8fd7c291..6c5859c895f5
If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/chromium-angle-autoroll
Please CC syoussefi@google.com on the revert to ensure that a human
is aware of the problem.
To report a problem with the AutoRoller itself, please file a bug:
https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug
Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/master/autoroll/README.md
Changed dependencies
* build: https://chromium.googlesource.com/chromium/src/build.git/+log/e353b02625..8870cb4120
* buildtools: https://chromium.googlesource.com/chromium/src/buildtools.git/+log/0b443d31ef..c793cca886
* testing: https://chromium.googlesource.com/chromium/src/testing/+log/a45949a818..a62f8260df
* third_party/android_deps: https://chromium.googlesource.com/chromium/src/third_party/android_deps/+log/42884eb2ac..887e8d9009
* third_party/catapult: https://chromium.googlesource.com/catapult.git/+log/{catapult_..d598390f02
* third_party/depot_tools: https://chromium.googlesource.com/chromium/tools/depot_tools.git/+log/a5b6b2f8b7..b508ecd932
* third_party/protobuf: https://chromium.googlesource.com/chromium/src/third_party/protobuf/+log/9523daa51d..82f8803671
* tools/clang: https://chromium.googlesource.com/chromium/src/tools/clang.git/+log/0c64e8349d..09481f56be
* tools/mb: https://chromium.googlesource.com/chromium/src/tools/mb/+log/d5d794a9f5..94630dfc19
* tools/memory: https://chromium.googlesource.com/chromium/src/tools/memory/+log/71214b910d..84ad259424
No update to Clang.
Manually added tools/android/modularization/convenience/lookup_dep.py
from crrev.com/889754
And updated .gn to use python3 in GN build by default
Bug: angleproject:6042
Tbr: syoussefi@google.com
Change-Id: I00384f4d38d14b54778d334aec9c633f54d619bb
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2946825
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Yuly Novikov <ynovikov@chromium.org>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
#!/usr/bin/env python3
# Copyright 2021 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.
r'''Finds which build target(s) contain a particular Java class.
This is a utility script for finding out which build target dependency needs to
be added to import a given Java class.
It is a best-effort script.
Example:
Find build target with class FooUtil:
tools/android/modularization/convenience/lookup_dep.py FooUtil
'''
import argparse
import collections
import dataclasses
import json
import logging
import os
import pathlib
import subprocess
import sys
import zipfile
from typing import Dict, List, Set
_SRC_DIR = pathlib.Path(__file__).parents[4].resolve()
sys.path.append(str(_SRC_DIR / 'build' / 'android'))
from pylib import constants
# Import list_java_targets so that the dependency is found by print_python_deps.
import list_java_targets
def main():
arg_parser = argparse.ArgumentParser(
description='Finds which build target contains a particular Java class.')
arg_parser.add_argument('-C', '--output-directory', help='Build output directory.')
arg_parser.add_argument('--build', action='store_true', help='Build all .build_config files.')
arg_parser.add_argument('classes', nargs='+', help='Java classes to search for')
arg_parser.add_argument('-v', '--verbose', action='store_true', help='Verbose logging.')
arguments = arg_parser.parse_args()
logging.basicConfig(
level=logging.DEBUG if arguments.verbose else logging.WARNING,
format='%(asctime)s.%(msecs)03d %(levelname).1s %(message)s',
datefmt='%H:%M:%S')
if arguments.output_directory:
constants.SetOutputDirectory(arguments.output_directory)
constants.CheckOutputDirectory()
abs_out_dir: pathlib.Path = pathlib.Path(constants.GetOutDirectory()).resolve()
index = ClassLookupIndex(abs_out_dir, arguments.build)
matches = {c: index.match(c) for c in arguments.classes}
if not arguments.build:
# Try finding match without building because it is faster.
for class_name, match_list in matches.items():
if len(match_list) == 0:
arguments.build = True
break
if arguments.build:
index = ClassLookupIndex(abs_out_dir, True)
matches = {c: index.match(c) for c in arguments.classes}
if not arguments.build:
print('Showing potentially stale results. Run lookup.dep.py with --build '
'(slower) to build any unbuilt GN targets and get full results.')
print()
for (class_name, class_entries) in matches.items():
if not class_entries:
print(f'Could not find build target for class "{class_name}"')
elif len(class_entries) == 1:
class_entry = class_entries[0]
print(f'Class {class_entry.full_class_name} found:')
print(f' "{class_entry.target}"')
else:
print(f'Multiple targets with classes that match "{class_name}":')
print()
for class_entry in class_entries:
print(f' "{class_entry.target}"')
print(f' contains {class_entry.full_class_name}')
print()
@dataclasses.dataclass(frozen=True)
class ClassEntry:
"""An assignment of a Java class to a build target."""
full_class_name: str
target: str
class ClassLookupIndex:
"""A map from full Java class to its build targets.
A class might be in multiple targets if it's bytecode rewritten."""
def __init__(self, abs_build_output_dir: pathlib.Path, should_build: bool):
self._abs_build_output_dir = abs_build_output_dir
self._should_build = should_build
self._class_index = self._index_root()
def match(self, search_string: str) -> List[ClassEntry]:
"""Get class/target entries where the class matches search_string"""
# Priority 1: Exact full matches
if search_string in self._class_index:
return self._entries_for(search_string)
# Priority 2: Match full class name (any case), if it's a class name
matches = []
lower_search_string = search_string.lower()
if '.' not in lower_search_string:
for full_class_name in self._class_index:
package_and_class = full_class_name.rsplit('.', 1)
if len(package_and_class) < 2:
continue
class_name = package_and_class[1]
class_lower = class_name.lower()
if class_lower == lower_search_string:
matches.extend(self._entries_for(full_class_name))
if matches:
return matches
# Priority 3: Match anything
for full_class_name in self._class_index:
if lower_search_string in full_class_name.lower():
matches.extend(self._entries_for(full_class_name))
return matches
def _entries_for(self, class_name) -> List[ClassEntry]:
return [ClassEntry(class_name, target) for target in self._class_index.get(class_name)]
def _index_root(self) -> Dict[str, List[str]]:
"""Create the class to target index."""
logging.debug('Running list_java_targets.py...')
list_java_targets_command = [
'build/android/list_java_targets.py', '--gn-labels', '--print-build-config-paths',
f'--output-directory={self._abs_build_output_dir}'
]
if self._should_build:
list_java_targets_command += ['--build']
list_java_targets_run = subprocess.run(
list_java_targets_command, cwd=_SRC_DIR, capture_output=True, text=True, check=True)
logging.debug('... done.')
# Parse output of list_java_targets.py with mapping of build_target to
# build_config
root_build_targets = list_java_targets_run.stdout.split('\n')
class_index = collections.defaultdict(list)
for target_line in root_build_targets:
# Skip empty lines
if not target_line:
continue
target_line_parts = target_line.split(': ')
assert len(target_line_parts) == 2, target_line_parts
target, build_config_path = target_line_parts
if not os.path.exists(build_config_path):
assert not self._should_build
continue
with open(build_config_path) as build_config_contents:
build_config: Dict = json.load(build_config_contents)
deps_info = build_config['deps_info']
# Checking the library type here instead of in list_java_targets.py avoids
# reading each .build_config file twice.
if deps_info['type'] != 'java_library':
continue
target = self._compute_toplevel_target(target)
full_class_names = self._compute_full_class_names_for_build_config(deps_info)
for full_class_name in full_class_names:
class_index[full_class_name].append(target)
return class_index
@staticmethod
def _compute_toplevel_target(target: str) -> str:
"""Computes top level target from the passed-in sub-target."""
if target.endswith('_java'):
return target
# Handle android_aar_prebuilt() sub targets.
index = target.find('_java__subjar')
if index >= 0:
return target[0:index + 5]
index = target.find('_java__classes')
if index >= 0:
return target[0:index + 5]
return target
def _compute_full_class_names_for_build_config(self, deps_info: Dict) -> Set[str]:
"""Returns set of fully qualified class names for build config."""
full_class_names = set()
# Read the location of the java_sources_file from the build_config
sources_path = deps_info.get('java_sources_file')
if sources_path:
# Read the java_sources_file, indexing the classes found
with open(self._abs_build_output_dir / sources_path) as sources_contents:
for source_line in sources_contents:
source_path = pathlib.Path(source_line.strip())
java_class = self._parse_full_java_class(source_path)
if java_class:
full_class_names.add(java_class)
# |unprocessed_jar_path| is set for prebuilt targets. (ex:
# android_aar_prebuilt())
# |unprocessed_jar_path| might be set but not exist if not all targets have
# been built.
unprocessed_jar_path = deps_info.get('unprocessed_jar_path')
if unprocessed_jar_path:
abs_unprocessed_jar_path = (self._abs_build_output_dir / unprocessed_jar_path)
if abs_unprocessed_jar_path.exists():
# Normalize path but do not follow symlink if .jar is symlink.
abs_unprocessed_jar_path = (
abs_unprocessed_jar_path.parent.resolve() / abs_unprocessed_jar_path.name)
full_class_names.update(
self._extract_full_class_names_from_jar(self._abs_build_output_dir,
abs_unprocessed_jar_path))
return full_class_names
@staticmethod
def _extract_full_class_names_from_jar(abs_build_output_dir: pathlib.Path,
abs_jar_path: pathlib.Path) -> Set[str]:
"""Returns set of fully qualified class names in passed-in jar."""
out = set()
jar_namelist = ClassLookupIndex._read_jar_namelist(abs_build_output_dir, abs_jar_path)
for zip_entry_name in jar_namelist:
if not zip_entry_name.endswith('.class'):
continue
# Remove .class suffix
full_java_class = zip_entry_name[:-6]
full_java_class = full_java_class.replace('/', '.')
dollar_index = full_java_class.find('$')
if dollar_index >= 0:
full_java_class[0:dollar_index]
out.add(full_java_class)
return out
@staticmethod
def _read_jar_namelist(abs_build_output_dir: pathlib.Path,
abs_jar_path: pathlib.Path) -> List[str]:
"""Returns list of jar members by name."""
# Caching namelist speeds up lookup_dep.py runtime by 1.5s.
cache_path = abs_jar_path.with_suffix(abs_jar_path.suffix + '.namelist_cache')
if (not ClassLookupIndex._is_path_relative_to(abs_jar_path, abs_build_output_dir)):
cache_path = (abs_build_output_dir / 'gen' / cache_path.relative_to(_SRC_DIR))
if (cache_path.exists() and os.path.getmtime(cache_path) > os.path.getmtime(abs_jar_path)):
with open(cache_path) as f:
return [s.strip() for s in f.readlines()]
with zipfile.ZipFile(abs_jar_path) as z:
namelist = z.namelist()
cache_path.parent.mkdir(parents=True, exist_ok=True)
with open(cache_path, 'w') as f:
f.write('\n'.join(namelist))
return namelist
@staticmethod
def _is_path_relative_to(path: pathlib.Path, other: pathlib.Path) -> bool:
# PurePath.is_relative_to() was introduced in Python 3.9
resolved_path = path.resolve()
resolved_other = other.resolve()
return str(resolved_path).startswith(str(resolved_other))
@staticmethod
def _parse_full_java_class(source_path: pathlib.Path) -> str:
"""Guess the fully qualified class name from the path to the source file."""
if source_path.suffix != '.java':
logging.warning(f'"{source_path}" does not have the .java suffix')
return None
directory_path: pathlib.Path = source_path.parent
package_list_reversed = []
for part in reversed(directory_path.parts):
if part == 'java':
break
package_list_reversed.append(part)
if part in ('com', 'org'):
break
else:
logging.debug(f'File {source_path} not in a subdir of "org" or "com", '
'cannot detect package heuristically.')
return None
package = '.'.join(reversed(package_list_reversed))
class_name = source_path.stem
return f'{package}.{class_name}'
if __name__ == '__main__':
main()