|
|
|
#!/usr/bin/env python3
|
|
|
|
# Copyright 2023 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.
|
|
|
|
|
|
|
|
import os
|
|
|
|
import re
|
|
|
|
import sys
|
|
|
|
from typing import List
|
|
|
|
|
|
|
|
_THIS_DIR = os.path.abspath(os.path.dirname(__file__))
|
|
|
|
# The repo's root directory.
|
|
|
|
_ROOT_DIR = os.path.abspath(os.path.join(_THIS_DIR, ".."))
|
|
|
|
|
|
|
|
# Add the repo's root directory for clearer imports.
|
|
|
|
sys.path.insert(0, _ROOT_DIR)
|
|
|
|
|
|
|
|
import metadata.fields.known as known_fields
|
|
|
|
import metadata.dependency_metadata as dm
|
|
|
|
|
|
|
|
# Line used to separate dependencies within the same metadata file.
|
|
|
|
DEPENDENCY_DIVIDER = re.compile(r"^-{20} DEPENDENCY DIVIDER -{20}$")
|
|
|
|
|
|
|
|
# Delimiter used to separate a field's name from its value.
|
|
|
|
FIELD_DELIMITER = ":"
|
|
|
|
|
|
|
|
# Pattern used to check if a line from a metadata file declares a new
|
|
|
|
# field.
|
|
|
|
_PATTERN_FIELD_DECLARATION = re.compile(
|
|
|
|
"^({}){}".format("|".join(known_fields.ALL_FIELD_NAMES), FIELD_DELIMITER),
|
|
|
|
re.IGNORECASE)
|
|
|
|
|
|
|
|
|
|
|
|
def parse_content(content: str) -> List[dm.DependencyMetadata]:
|
|
|
|
"""Reads and parses the metadata from the given string.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
content: the string to parse metadata from.
|
|
|
|
|
|
|
|
Returns: all the metadata, which may be for zero or more
|
|
|
|
dependencies, from the given string.
|
|
|
|
"""
|
|
|
|
dependencies = []
|
|
|
|
current_metadata = dm.DependencyMetadata()
|
|
|
|
current_field_name = None
|
|
|
|
current_field_value = ""
|
|
|
|
for line in content.splitlines(keepends=True):
|
|
|
|
# Check if a new dependency is being described.
|
|
|
|
if DEPENDENCY_DIVIDER.match(line):
|
|
|
|
if current_field_name:
|
|
|
|
# Save the field value for the previous dependency.
|
|
|
|
current_metadata.add_entry(current_field_name,
|
|
|
|
current_field_value)
|
|
|
|
if current_metadata.has_entries():
|
|
|
|
# Add the previous dependency to the results.
|
|
|
|
dependencies.append(current_metadata)
|
|
|
|
# Reset for the new dependency's metadata,
|
|
|
|
# and reset the field state.
|
|
|
|
current_metadata = dm.DependencyMetadata()
|
|
|
|
current_field_name = None
|
|
|
|
current_field_value = ""
|
|
|
|
|
|
|
|
elif _PATTERN_FIELD_DECLARATION.match(line):
|
|
|
|
# Save the field value to the current dependency's metadata.
|
|
|
|
if current_field_name:
|
|
|
|
current_metadata.add_entry(current_field_name,
|
|
|
|
current_field_value)
|
|
|
|
|
|
|
|
current_field_name, current_field_value = line.split(
|
|
|
|
FIELD_DELIMITER, 1)
|
|
|
|
field = known_fields.get_field(current_field_name)
|
|
|
|
if field and field.is_one_liner():
|
|
|
|
# The field should be on one line, so add it now.
|
|
|
|
current_metadata.add_entry(current_field_name,
|
|
|
|
current_field_value)
|
|
|
|
# Reset the field state.
|
|
|
|
current_field_name = None
|
|
|
|
current_field_value = ""
|
|
|
|
|
|
|
|
elif current_field_name:
|
|
|
|
# The field is on multiple lines, so add this line to the
|
|
|
|
# field value.
|
|
|
|
current_field_value += line
|
|
|
|
|
|
|
|
# At this point, the end of the file has been reached.
|
|
|
|
# Save any remaining field data and metadata.
|
|
|
|
if current_field_name:
|
|
|
|
current_metadata.add_entry(current_field_name, current_field_value)
|
|
|
|
if current_metadata.has_entries():
|
|
|
|
dependencies.append(current_metadata)
|
|
|
|
|
|
|
|
return dependencies
|