Files
chinook/chinook/management/_load.py
T

157 lines
4.7 KiB
Python

import yaml
from pathlib import Path
from ..models import Access
from ..models import Accessor
from ..models import Dependency
from ..models import Destination
from ..models import Origination
from ..models import Output
from ..models import Project
from ..models import Target
from ..shell import execute
from .._config import Config
from ._except import NoProjectFoundError
from ._shared import projects_by_name_mapping
from ._shared import targets_by_name_mapping
from ._shared import tests_by_name_mapping
from ._shared import project_by_targets_mapping
def load(path: Path) -> Project:
if path in projects_by_name_mapping:
return projects_by_name_mapping[path]
fullpath = path / "chinookfile"
if not Path.exists(fullpath):
raise NoProjectFoundError(fullpath)
try:
with open(fullpath, 'r') as file:
yamlobj = yaml.load(file.read(), Loader=Project.yaml_loader)
project = Project.from_dict(yamlobj)
project.origination = Origination(path)
project.destination = Destination(path)
_collect_profiles(project)
_collect_required(project)
_collect_targets(project)
_collect_tests(project)
_flatten_targets(project)
_flatten_tests(project)
return project
except Exception as rethrowme:
raise rethrowme
def _collect_profiles(project: Project) -> None:
# TODO: Determine what profile is supposed to be active and load the targets
# so that they will be compiled.
for profile in project.profiles:
...
def _collect_required(project: Project) -> None:
for required in project.requires:
_clone_then_load_required(required)
def _collect_targets(project: Project) -> None:
for target in project.targets:
if target.name not in targets_by_name_mapping:
targets_by_name_mapping[target.name] = target
project_by_targets_mapping[target.name] = project
def _collect_tests(project: Project) -> None:
for test in project.tests:
if test.name not in tests_by_name_mapping:
tests_by_name_mapping[test.name] = test
def _flatten_targets(project: Project) -> None:
for target in project.targets:
_flatten_target(target)
target.incs.includes.add(Accessor(
level = Access.PUBLIC \
if target.name in project.exports \
else Access.PRIVATE,
value = project.origination.src("include")
))
target.incs.libraries.add(Accessor(
level = Access.PUBLIC,
value = project.destination.libpath
))
def _flatten_tests(project: Project) -> None:
for test in project.tests:
_flatten_target(test)
test.incs.includes.add(Accessor(
level = Access.PRIVATE,
value = project.origination.src("include")
))
test.incs.libraries.add(Accessor(
level = Access.PRIVATE,
value = project.destination.libpath
))
def _flatten_target(target: Target) -> None:
for dependency in target.deps:
if (parent:=targets_by_name_mapping.get(dependency.value)) == None:
raise ValueError(f"No such dependable target: {dependency}")
_inherit_target(target, parent)
def _inherit_target(target: Target, parent: Target) -> None:
if parent.name in tests_by_name_mapping:
raise ValueError("Cannot inherit tests")
_flatten_target(parent)
target.incs.includes.update([v for v in parent.incs.includes if v.level != Access.PRIVATE])
target.incs.libraries.update([v for v in parent.incs.libraries if v.level != Access.PRIVATE])
parent_project = project_by_targets_mapping.get(parent.name)
assert parent_project is not None, "Parent project not mapped!"
target.incs.includes.add(Accessor(
level = Access.PUBLIC,
value = parent_project.origination.src("include")
))
target.incs.libraries.add(Accessor(
level = Access.PUBLIC,
value = parent_project.destination.libpath
))
target.opts.update([v for v in parent.opts if v.level != Access.PRIVATE])
target.defs.update([v for v in parent.defs if v.level != Access.PRIVATE])
target.deps.update([v for v in parent.deps if v.level != Access.PRIVATE])
target.libs.update([v for v in parent.libs if v.level != Access.PRIVATE])
target.libs.add(Accessor(
level = Access.PUBLIC,
value = parent.name
))
if parent.type == Output.INT:
target.srcs.update([v for v in parent.srcs if v.level != Access.PRIVATE])
def _clone_then_load_required(required: Dependency) -> None:
reqpath = Config.config_directory / required.cid
if not Path.exists(reqpath):
_clone_required(required, reqpath)
load(reqpath)
def _clone_required(
required: Dependency,
reqpath: Path
) -> None:
# TODO: Clean this up.
def handle_success(retcode: int, cmdstr: str, stdout: str) -> None:
return
errstr = None
def handle_error(retcode: int, cmdstr: str, stderr: str) -> None:
global errstr
errstr = stderr
execute(
f"git clone -b {required.branch} --depth 1 {required.remote} {reqpath}",
handle_success,
handle_error
)
if errstr != None:
raise Exception(errstr)