Commit 6647cbbc authored by Andrew Grieve's avatar Andrew Grieve Committed by Commit Bot

SuperSize: Add support for METADATA.chromium

There is an upcoming migration that will move component information
OWNERS -> METADATA.chromium

See: https://chromium-review.googlesource.com/c/chromium/src/+/2248340

For the interim, support both.

Bug: None
Change-Id: Icb03b8b7b69a509f760c3b15a69f2d16eec3801d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2269698
Commit-Queue: Andrew Grieve <agrieve@chromium.org>
Reviewed-by: default avatarSamuel Huang <huangs@chromium.org>
Cr-Commit-Position: refs/heads/master@{#783012}
parent 914ce0a7
...@@ -42,9 +42,14 @@ import zip_util ...@@ -42,9 +42,14 @@ import zip_util
sys.path.insert(1, os.path.join(path_util.TOOLS_SRC_ROOT, 'tools', 'grit')) sys.path.insert(1, os.path.join(path_util.TOOLS_SRC_ROOT, 'tools', 'grit'))
from grit.format import data_pack from grit.format import data_pack
_METADATA_FILENAME = 'METADATA.chromium'
_METADATA_COMPONENT_REGEX = re.compile(r'^\s*component:\s*"(.*?)"',
re.MULTILINE)
_OWNERS_FILENAME = 'OWNERS' _OWNERS_FILENAME = 'OWNERS'
_COMPONENT_REGEX = re.compile(r'\s*#\s*COMPONENT\s*:\s*(\S+)') _OWNERS_COMPONENT_REGEX = re.compile(r'^\s*#\s*COMPONENT:\s*(\S+)',
_FILE_PATH_REGEX = re.compile(r'\s*file://(\S+)') re.MULTILINE)
_OWNERS_FILE_PATH_REGEX = re.compile(r'^\s*file://(\S+)', re.MULTILINE)
_UNCOMPRESSED_COMPRESSION_RATIO_THRESHOLD = 0.9 _UNCOMPRESSED_COMPRESSION_RATIO_THRESHOLD = 0.9
_APKS_MAIN_APK = 'splits/base-master.apk' _APKS_MAIN_APK = 'splits/base-master.apk'
...@@ -536,90 +541,104 @@ def _CreateMergeStringsReplacements(merge_string_syms, ...@@ -536,90 +541,104 @@ def _CreateMergeStringsReplacements(merge_string_syms,
return ret return ret
def _ParseComponentFromOwners(filename, opts): def _ParseComponentFromMetadata(path):
"""Searches an OWNERS file for lines that start with `# COMPONENT:`. """Extracts Component from METADATA.chromium."""
try:
with open(path) as f:
data = f.read()
m = _METADATA_COMPONENT_REGEX.search(data)
if m:
return m.group(1)
except IOError:
# Need to catch both FileNotFoundError and NotADirectoryError since
# source_paths for .aar files look like: /path/to/lib.aar/path/within/zip
pass
return ''
If an OWNERS file has no COMPONENT but references exactly one other OWNERS def _ParseComponentFromOwners(path):
file, follows the reference and checks that file instead. """Extracts COMPONENT and file:// from an OWNERS file.
Args: Args:
filename: Path to the file to parse. path: Path to the file to parse.
opts: Instance of ContainerArchiveOptions.
Returns: Returns:
The text that follows the `# COMPONENT:` prefix, such as 'component>name'. (component, None) if COMPONENT: line was found.
Empty string if no component found or the file doesn't exist. ('', path) if a single file:// was found.
('', None) if neither was found.
""" """
seen = set() try:
while True: with open(path) as f:
seen.add(filename) data = f.read()
reference_paths = []
try: m = _OWNERS_COMPONENT_REGEX.search(data)
with open(filename) as f: if m:
for line in f: return m.group(1), None
component_matches = _COMPONENT_REGEX.match(line) aliases = _OWNERS_FILE_PATH_REGEX.findall(data)
path_matches = _FILE_PATH_REGEX.match(line) if len(aliases) == 1:
if component_matches: return '', aliases[0]
return component_matches.group(1) except IOError:
elif path_matches: # Need to catch both FileNotFoundError and NotADirectoryError since
reference_paths.append(path_matches.group(1)) # source_paths for .aar files look like: /path/to/lib.aar/path/within/zip
except IOError: pass
break return '', None
if len(reference_paths) != 1:
break
filename = os.path.join(opts.src_root, reference_paths[0]) def _FindComponentRoot(path, cache, src_root):
if filename in seen:
logging.warning('OWNER dependence loop found for %s' % filename)
break
return ''
def _FindComponentRoot(start_path, cache, opts):
"""Searches all parent directories for COMPONENT in OWNERS files. """Searches all parent directories for COMPONENT in OWNERS files.
Args: Args:
start_path: Path of directory to start searching from. Must be relative to path: Path of directory to start searching from. Must be relative to
|opts.src_root|. |src_root|.
cache: Dict of OWNERS paths. Used instead of filesystem if paths are present cache: Dict of OWNERS paths. Used instead of filesystem if paths are present
in the dict. in the dict.
opts: Instance of ContainerArchiveOptions. src_root: Directory to use as the root.
Returns: Returns:
COMPONENT belonging to |start_path|, or empty string if not found. COMPONENT belonging to |path|, or empty string if not found.
""" """
prev_dir = None assert not os.path.isabs(path)
test_dir = start_path component = cache.get(path)
# This loop will traverse the directory structure upwards until reaching if component is not None:
# |opts.src_root|, where |test_dir| and |prev_dir| will both equal an empty return component
# string.
while test_dir != prev_dir: metadata_path = os.path.join(src_root, path, _METADATA_FILENAME)
cached_component = cache.get(test_dir) component = _ParseComponentFromMetadata(metadata_path)
if cached_component: if not component:
return cached_component owners_path = os.path.join(src_root, path, _OWNERS_FILENAME)
if cached_component is None: # Excludes ''. component, path_alias = _ParseComponentFromOwners(owners_path)
owners_path = os.path.join(opts.src_root, test_dir, _OWNERS_FILENAME)
component = _ParseComponentFromOwners(owners_path, opts) if not component:
cache[test_dir] = component # Store in cache before recursing to prevent cycles.
if component: cache[path] = ''
return component if path_alias:
prev_dir = test_dir alias_dir = os.path.dirname(path_alias)
test_dir = os.path.dirname(test_dir) component = _FindComponentRoot(alias_dir, cache, src_root)
return ''
if not component:
parent_path = os.path.dirname(path)
def _PopulateComponents(raw_symbols, opts): if parent_path:
component = _FindComponentRoot(parent_path, cache, src_root)
cache[path] = component
return component
def _PopulateComponents(raw_symbols, src_root):
"""Populates the |component| field based on |source_path|. """Populates the |component| field based on |source_path|.
Symbols without a |source_path| are skipped. Symbols without a |source_path| are skipped.
Args: Args:
raw_symbols: list of Symbol objects. raw_symbols: list of Symbol objects.
opts: Instance of ContainerArchiveOptions. src_root: Directory to use as the root.
""" """
seen_paths = {} seen_paths = {}
for symbol in raw_symbols: for symbol in raw_symbols:
if symbol.source_path: if symbol.source_path:
folder_path = os.path.dirname(symbol.source_path) folder_path = os.path.dirname(symbol.source_path)
symbol.component = _FindComponentRoot(folder_path, seen_paths, opts) symbol.component = _FindComponentRoot(folder_path, seen_paths, src_root)
def _UpdateSymbolNamesFromNm(raw_symbols, names_by_address): def _UpdateSymbolNamesFromNm(raw_symbols, names_by_address):
...@@ -1607,7 +1626,7 @@ def CreateContainerAndSymbols(knobs=None, ...@@ -1607,7 +1626,7 @@ def CreateContainerAndSymbols(knobs=None,
raw_symbols.extend(pak_raw_symbols) raw_symbols.extend(pak_raw_symbols)
_ExtractSourcePathsAndNormalizeObjectPaths(raw_symbols, source_mapper) _ExtractSourcePathsAndNormalizeObjectPaths(raw_symbols, source_mapper)
_PopulateComponents(raw_symbols, opts) _PopulateComponents(raw_symbols, opts.src_root)
logging.info('Converting excessive aliases into shared-path symbols') logging.info('Converting excessive aliases into shared-path symbols')
_CompactLargeAliasesIntoSharedSymbols(raw_symbols, knobs) _CompactLargeAliasesIntoSharedSymbols(raw_symbols, knobs)
logging.debug('Connecting nm aliases') logging.debug('Connecting nm aliases')
......
monorail {
project: "chromium"
component: "Blink>Internal"
}
team_email: "team@chromium.org"
os: OS_LINUX
file://OWNERS file://OWNERS
# COMPONENT: Blink>Internal # COMPONENT: ignored
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment