151 lines
3.8 KiB
Python
151 lines
3.8 KiB
Python
"""
|
|
Dependencies resolver
|
|
"""
|
|
import os
|
|
|
|
from core.logger import log
|
|
from core.build.meta import VxProjectMeta
|
|
import core.pkg
|
|
|
|
__all__ = [
|
|
'project_dependency_clone'
|
|
]
|
|
|
|
#---
|
|
# Internals
|
|
#---
|
|
|
|
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(parent_path, dep_info, pkg_info, prefix, dep_stack):
|
|
"""Clone all dependency and generate dependency graph
|
|
|
|
@args
|
|
> dep_graph (list) - list dependencies
|
|
> dep_parent_id (int) - parent index in `dep_graph`
|
|
> pkg_info (dict) - package information
|
|
> prefix (str) - prefix for package cloning
|
|
|
|
@return
|
|
> 0 if success, negative value otherwise
|
|
"""
|
|
# fetch info
|
|
dep_graph = dep_info[0]
|
|
dep_parent_id = dep_info[1]
|
|
|
|
# check circular dependency and update the stack
|
|
for dep in dep_stack:
|
|
if dep != pkg_info:
|
|
continue
|
|
log.error(f"circular dependency with '{pkg_info['name']}' detected")
|
|
return -1
|
|
dep_stack.append(pkg_info)
|
|
|
|
# try to clone the package
|
|
pkg_path = core.pkg.clone(
|
|
pkg_info['name'],
|
|
pkg_info['version'],
|
|
prefix
|
|
)
|
|
|
|
# check pacakge validity
|
|
# @todo
|
|
# Find a way to not be dependent of VxProjectMeta to avoid spaghetti code
|
|
target = pkg_info['target']
|
|
pkg_meta = VxProjectMeta(pkg_path, parent_path, pkg_info['extra_conf'])
|
|
if target not in pkg_meta.target_support:
|
|
log.error(f"[{pkg_meta.name}] target '{target}' not supported")
|
|
return -2
|
|
|
|
# generate dependency information
|
|
pkg_dep_id = __dep_graph_update(
|
|
dep_graph,
|
|
dep_parent_id,
|
|
{
|
|
'meta' : pkg_meta,
|
|
'target' : pkg_info['target']
|
|
}
|
|
)
|
|
for dep in pkg_meta.get_dependencies(target):
|
|
__recurs_clone(
|
|
parent_path,
|
|
(dep_graph, pkg_dep_id),
|
|
dep,
|
|
prefix,
|
|
dep_stack.copy()
|
|
)
|
|
return 0
|
|
|
|
#---
|
|
# Public
|
|
#---
|
|
|
|
def project_dependency_clone(pkg, target):
|
|
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
|
|
> target (str) - build target
|
|
|
|
@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.parent_path}/.vxsdk/dependencies"
|
|
if not os.path.exists(prefix):
|
|
os.makedirs(prefix)
|
|
|
|
# clone all dependencies and generate a DAG graph
|
|
# @note
|
|
# we need to manualy bootstrap the current project as a dependency to
|
|
# facilitate graph generation with a unified data structure
|
|
dep_graph = []
|
|
dep_origin_id = __dep_graph_update(
|
|
dep_graph,
|
|
-1,
|
|
{
|
|
'meta' : pkg,
|
|
'target' : target,
|
|
}
|
|
)
|
|
for dep in pkg.get_dependencies(target):
|
|
__recurs_clone(
|
|
pkg.parent_path,
|
|
(dep_graph, dep_origin_id),
|
|
dep,
|
|
prefix,
|
|
[]
|
|
)
|
|
|
|
# return the DAG
|
|
return dep_graph
|