Skip to content

Commit

Permalink
SuperSize: Add support for METADATA.chromium
Browse files Browse the repository at this point in the history
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: Samuel Huang <huangs@chromium.org>
Cr-Commit-Position: refs/heads/master@{#783012}
  • Loading branch information
agrieve authored and Commit Bot committed Jun 26, 2020
1 parent 914ce0a commit 6647cbb
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 64 deletions.
145 changes: 82 additions & 63 deletions tools/binary_size/libsupersize/archive.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,14 @@
sys.path.insert(1, os.path.join(path_util.TOOLS_SRC_ROOT, 'tools', 'grit'))
from grit.format import data_pack

_METADATA_FILENAME = 'METADATA.chromium'
_METADATA_COMPONENT_REGEX = re.compile(r'^\s*component:\s*"(.*?)"',
re.MULTILINE)
_OWNERS_FILENAME = 'OWNERS'
_COMPONENT_REGEX = re.compile(r'\s*#\s*COMPONENT\s*:\s*(\S+)')
_FILE_PATH_REGEX = re.compile(r'\s*file://(\S+)')
_OWNERS_COMPONENT_REGEX = re.compile(r'^\s*#\s*COMPONENT:\s*(\S+)',
re.MULTILINE)
_OWNERS_FILE_PATH_REGEX = re.compile(r'^\s*file://(\S+)', re.MULTILINE)

_UNCOMPRESSED_COMPRESSION_RATIO_THRESHOLD = 0.9
_APKS_MAIN_APK = 'splits/base-master.apk'

Expand Down Expand Up @@ -536,90 +541,104 @@ def _CreateMergeStringsReplacements(merge_string_syms,
return ret


def _ParseComponentFromOwners(filename, opts):
"""Searches an OWNERS file for lines that start with `# COMPONENT:`.
def _ParseComponentFromMetadata(path):
"""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
file, follows the reference and checks that file instead.
def _ParseComponentFromOwners(path):
"""Extracts COMPONENT and file:// from an OWNERS file.
Args:
filename: Path to the file to parse.
opts: Instance of ContainerArchiveOptions.
path: Path to the file to parse.
Returns:
The text that follows the `# COMPONENT:` prefix, such as 'component>name'.
Empty string if no component found or the file doesn't exist.
(component, None) if COMPONENT: line was found.
('', path) if a single file:// was found.
('', None) if neither was found.
"""
seen = set()
while True:
seen.add(filename)
reference_paths = []
try:
with open(filename) as f:
for line in f:
component_matches = _COMPONENT_REGEX.match(line)
path_matches = _FILE_PATH_REGEX.match(line)
if component_matches:
return component_matches.group(1)
elif path_matches:
reference_paths.append(path_matches.group(1))
except IOError:
break
if len(reference_paths) != 1:
break
filename = os.path.join(opts.src_root, reference_paths[0])
if filename in seen:
logging.warning('OWNER dependence loop found for %s' % filename)
break
return ''


def _FindComponentRoot(start_path, cache, opts):
try:
with open(path) as f:
data = f.read()

m = _OWNERS_COMPONENT_REGEX.search(data)
if m:
return m.group(1), None
aliases = _OWNERS_FILE_PATH_REGEX.findall(data)
if len(aliases) == 1:
return '', aliases[0]
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 '', None


def _FindComponentRoot(path, cache, src_root):
"""Searches all parent directories for COMPONENT in OWNERS files.
Args:
start_path: Path of directory to start searching from. Must be relative to
|opts.src_root|.
path: Path of directory to start searching from. Must be relative to
|src_root|.
cache: Dict of OWNERS paths. Used instead of filesystem if paths are present
in the dict.
opts: Instance of ContainerArchiveOptions.
src_root: Directory to use as the root.
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
test_dir = start_path
# This loop will traverse the directory structure upwards until reaching
# |opts.src_root|, where |test_dir| and |prev_dir| will both equal an empty
# string.
while test_dir != prev_dir:
cached_component = cache.get(test_dir)
if cached_component:
return cached_component
if cached_component is None: # Excludes ''.
owners_path = os.path.join(opts.src_root, test_dir, _OWNERS_FILENAME)
component = _ParseComponentFromOwners(owners_path, opts)
cache[test_dir] = component
if component:
return component
prev_dir = test_dir
test_dir = os.path.dirname(test_dir)
return ''


def _PopulateComponents(raw_symbols, opts):
assert not os.path.isabs(path)
component = cache.get(path)
if component is not None:
return component

metadata_path = os.path.join(src_root, path, _METADATA_FILENAME)
component = _ParseComponentFromMetadata(metadata_path)
if not component:
owners_path = os.path.join(src_root, path, _OWNERS_FILENAME)
component, path_alias = _ParseComponentFromOwners(owners_path)

if not component:
# Store in cache before recursing to prevent cycles.
cache[path] = ''
if path_alias:
alias_dir = os.path.dirname(path_alias)
component = _FindComponentRoot(alias_dir, cache, src_root)

if not component:
parent_path = os.path.dirname(path)
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|.
Symbols without a |source_path| are skipped.
Args:
raw_symbols: list of Symbol objects.
opts: Instance of ContainerArchiveOptions.
src_root: Directory to use as the root.
"""
seen_paths = {}
for symbol in raw_symbols:
if 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):
Expand Down Expand Up @@ -1607,7 +1626,7 @@ def CreateContainerAndSymbols(knobs=None,
raw_symbols.extend(pak_raw_symbols)

_ExtractSourcePathsAndNormalizeObjectPaths(raw_symbols, source_mapper)
_PopulateComponents(raw_symbols, opts)
_PopulateComponents(raw_symbols, opts.src_root)
logging.info('Converting excessive aliases into shared-path symbols')
_CompactLargeAliasesIntoSharedSymbols(raw_symbols, knobs)
logging.debug('Connecting nm aliases')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
monorail {
project: "chromium"
component: "Blink>Internal"
}
team_email: "team@chromium.org"
os: OS_LINUX
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
file://OWNERS

# COMPONENT: Blink>Internal
# COMPONENT: ignored

0 comments on commit 6647cbb

Please sign in to comment.