174 lines
4.8 KiB
Python
174 lines
4.8 KiB
Python
"""
|
|
core.build.dependency - Dependencies resolver
|
|
"""
|
|
import os
|
|
import sys
|
|
|
|
import core.pkg
|
|
|
|
from core.logger import log
|
|
from core.build.meta import VxProjectMeta
|
|
from core.build.env import env_config_merge, env_pkg_configure
|
|
|
|
__all__ = [
|
|
'dependency_project_clone'
|
|
]
|
|
|
|
#---
|
|
# Internals
|
|
#---
|
|
|
|
## DAG struct handling
|
|
|
|
def _dep_graph_update(dep_graph, dep_parent_id, pkg_info):
|
|
"""
|
|
Update dependency graph
|
|
"""
|
|
# inject new pkg information and gues its ID
|
|
dep_id = len(dep_graph)
|
|
dep_graph.append({
|
|
'info' : pkg_info,
|
|
'completed' : False,
|
|
'dependencies' : []
|
|
})
|
|
|
|
# update internal parent ID
|
|
if dep_parent_id >= 0:
|
|
dep_graph[dep_parent_id]['dependencies'].append(dep_id)
|
|
return dep_id
|
|
|
|
def _recurs_clone(build_prefix, dep_info, pkg_info, prefix):
|
|
"""Clone all dependency and generate dependency graph
|
|
|
|
@args
|
|
> build_prefix (str) - build prefix information
|
|
> dep_info (list) - contains dependencies list, stack and parent ID
|
|
> pkg_info (dict) - package information
|
|
> prefix (str) - prefix for package cloning
|
|
|
|
@return
|
|
> The current public env of the package
|
|
"""
|
|
# fetch info
|
|
dep_graph, dep_parent_id, dep_stack = dep_info
|
|
|
|
# check circular dependency error and update the stack
|
|
for dep in dep_stack:
|
|
if dep != pkg_info:
|
|
continue
|
|
log.error(f"circular dependency with '{pkg_info['name']}' detected")
|
|
sys.exit(84)
|
|
dep_stack.append(pkg_info)
|
|
|
|
# try to clone the package
|
|
pkg_path = core.pkg.clone(
|
|
pkg_info['name'],
|
|
pkg_info['version'],
|
|
f"{prefix}/"
|
|
)
|
|
if not pkg_path:
|
|
log.error(
|
|
'unable to clone the dependency '
|
|
f"{pkg_info['name']}@{pkg_info['version']}"
|
|
)
|
|
sys.exit(84)
|
|
log.debug(f"pkg path = {pkg_path}")
|
|
|
|
# check pacakge validity
|
|
pkg_meta = VxProjectMeta(
|
|
pkg_path,
|
|
build_prefix,
|
|
pkg_info['target'],
|
|
pkg_info['extra_conf']
|
|
)
|
|
|
|
# generate dependency information
|
|
pkg_env_config = pkg_meta.get_env_config()
|
|
pkg_depinfo = {
|
|
'meta' : pkg_meta,
|
|
'target' : pkg_info['target'],
|
|
'env' : None
|
|
}
|
|
pkg_dep_id = _dep_graph_update(dep_graph, dep_parent_id, pkg_depinfo)
|
|
|
|
# Handle dependencies and update the ENV information
|
|
dep_env_commit = {}
|
|
for dep in pkg_meta.get_dependencies():
|
|
dep_env_commit[dep['name']] = _recurs_clone(
|
|
build_prefix,
|
|
(dep_graph, pkg_dep_id, dep_stack.copy()),
|
|
dep,
|
|
prefix
|
|
)
|
|
|
|
# Generate env configuration and return the "current" package env
|
|
# configuration
|
|
log.debug(f"[{pkg_meta.name}] dep pre-env = {pkg_env_config['public']}")
|
|
pkg_depinfo['env'] = env_pkg_configure(
|
|
pkg_meta,
|
|
pkg_env_config['private'],
|
|
dep_env_commit
|
|
)
|
|
env_config_merge(pkg_env_config['public'], dep_env_commit)
|
|
log.debug(f"[{pkg_meta.name}] dep post-env = {pkg_env_config['public']}")
|
|
return pkg_env_config['public']
|
|
|
|
#---
|
|
# Public
|
|
#---
|
|
|
|
def dependency_project_clone(pkg):
|
|
r""" Clone dependencies of package and generate a DAG graph
|
|
|
|
This function will clone all dependency of a package optimised for a
|
|
particular target a `Direct Acyclic Graph` (DAG) graph will be generated to
|
|
facilitate project compilation later.
|
|
|
|
@args
|
|
> pkg (dict) - first pacakge information
|
|
|
|
@return
|
|
> A list with package and dependency information : [
|
|
{
|
|
'meta' : <:obj:VxProjectMeta>
|
|
'extra_conf' : <extra configuration information>
|
|
'target' : build target
|
|
},
|
|
...
|
|
]
|
|
"""
|
|
# create the package "storage" folder
|
|
# @note
|
|
# All dependencies will be cloned in "global" path, only symbolic link will
|
|
# be generated here
|
|
prefix = f"{pkg.build_prefix}/dependencies/"
|
|
if not os.path.exists(prefix):
|
|
os.makedirs(prefix)
|
|
|
|
# generate the root DAG node
|
|
dep_graph = []
|
|
pkg_env_config = pkg.get_env_config()
|
|
pkg_depinfo = {'meta' : pkg, 'target' : pkg.target, 'env' : None}
|
|
dep_origin_id = _dep_graph_update(dep_graph, -1, pkg_depinfo)
|
|
|
|
# clone all dependencies and update the DAG
|
|
# @note
|
|
# we need to manualy bootstrap the current project as a dependency to
|
|
# facilitate graph generation with a unified data structure
|
|
dep_env_commit = {}
|
|
for dep in pkg.get_dependencies():
|
|
dep_env_commit[dep['name']] = _recurs_clone(
|
|
pkg.build_prefix,
|
|
(dep_graph, dep_origin_id, []),
|
|
dep,
|
|
prefix
|
|
)
|
|
|
|
# generate package env configuration
|
|
env = env_pkg_configure(pkg, pkg_env_config['private'], dep_env_commit)
|
|
log.debug(f"[{pkg.name}] generated env = {env}")
|
|
pkg_depinfo['env'] = env
|
|
|
|
# return the DAG
|
|
return dep_graph
|