## @file
# Copyright (c) 2023, The OCE Build Authors. All rights reserved.
# SPDX-License-Identifier: BSD-3-Clause
##
"""Methods for handling and manipulating the build configuration."""
from shutil import unpack_archive
from tempfile import mkdtemp
from typing import Iterator, List, Optional, Tuple
from ocebuild.filesystem import copy
from ocebuild.filesystem.archives import extract_archive
from ocebuild.filesystem.cache import UNPACK_DIR
from ocebuild.parsers.dict import nested_get, nested_set
from ocebuild.parsers.yaml import parse_yaml
#NOTE: This import was remapped from 'third_party' to 'ocebuild.third_party'.
from ocebuild.third_party.cpython.pathlib import Path
def _set_var_default(build_vars: dict, name: str, default: str):
"""Set a variable to a default value if it is not already set."""
if not (variable := nested_get(build_vars, ['variables', name])):
variable = default
nested_set(build_vars, ['variables', name], variable)
return variable
[docs]def read_build_file(filepath: str,
normalize_entries: bool=True
) -> Tuple[dict, dict, List[str]]:
"""Read the build configuration from the specified build file.
Args:
filepath: The path to the build file.
normalize_entries: Whether to normalize the entries in the build file.
Returns:
A tuple containing:
- The build configuration.
- The build variables.
- The build flags.
"""
with open(filepath, 'r', encoding='UTF-8') as f:
build_config, build_vars = parse_yaml(f, frontmatter=True)
# Extract the OpenCore build configuration
version = _set_var_default(build_vars, 'version', 'latest')
build = _set_var_default(build_vars, 'build', 'RELEASE')
target = _set_var_default(build_vars, 'target', 'X64')
# Add additional flags from the build configuration
flags = nested_get(build_vars, ['flags'])
if build not in flags: flags += [build]
if target not in flags: flags += [target]
# Normalize the entries in the build configuration
if normalize_entries:
build_config['OpenCorePkg'] = {
'OpenCore': {
'__filepath': 'EFI/OC/OpenCore.efi',
'specifier': version,
'repository': 'acidanthera/OpenCorePkg',
'build': build
},
'OcBinaryData': {
'__filepath': 'EFI/OC/.',
'specifier': 'latest',
'repository': 'acidanthera/OcBinaryData',
'branch': 'master',
'build': build,
'tarball': True
}
}
for category, entries in build_config.items():
# Reconstruct an equivalent dictionary entry
if isinstance(entries, list):
build_config[category] = {}
entries = { k: '*' for k in entries }
# Normalize the specifier for each entry
if isinstance(entries, dict):
for name, entry in entries.items():
# Handle string specifiers
if not isinstance(entry, dict):
build_config[category][name] = {}
nested_set(build_config, [category, name, 'specifier'], entry)
return build_config, build_vars, flags
[docs]def unpack_build_entries(resolvers: List[dict],
project_dir: Path,
*args,
__wrapper: Optional[Iterator]=None,
**kwargs) -> dict:
"""Unpacks the build entries from the build configuration."""
# Handle interactive mode for iterator
iterator = resolvers
if __wrapper is not None: iterator = __wrapper(iterator, *args, **kwargs)
extracted = {}
for entry in iterator:
tmpdir: Path
# Handle extracting remote entries
if (url := entry.get('url')):
with extract_archive(url, persist=True) as tmpdir:
for archive in tmpdir.glob('**/*.zip'):
unpack_archive(archive, tmpdir.joinpath(archive.name))
# Handle extracting local entries
elif (path := entry.get('path')):
tmpdir = Path(mkdtemp(dir=UNPACK_DIR))
src = project_dir.joinpath(path)
copy(src, tmpdir.joinpath(tmpdir, src.name))
# Skip wildcard specifiers
elif entry.get('specifier') == '*': continue
# Update extracted paths
entry['__extracted'] = tmpdir
nested_set(extracted, [entry['__category'], entry['name']], tmpdir)
return extracted
__all__ = [
# Functions (2)
"read_build_file",
"unpack_build_entries"
]