289 lines
10 KiB
Python
289 lines
10 KiB
Python
"""
|
|
vxsdk.toml document parser
|
|
"""
|
|
import os
|
|
import toml
|
|
|
|
from core.logger import log
|
|
from core.pkg.version import version_get
|
|
|
|
__all__ = [
|
|
'VxProjectMeta'
|
|
]
|
|
|
|
class VxProjectMeta():
|
|
r""" Represente the project meta-information
|
|
|
|
All meta-information is stored in a file named `vxsdk.toml` at the root
|
|
of the project directory.
|
|
|
|
This class exposes:
|
|
|
|
================================== =========================================
|
|
Property Description
|
|
================================== =========================================
|
|
name (str) Project name
|
|
version (str) Project versions
|
|
path (str) Project path
|
|
description (str) Project description
|
|
type (str) Project type
|
|
target_support (list,str) List of all supported target
|
|
================================== =========================================
|
|
Methods Description
|
|
================================== =========================================
|
|
get_dependencies (list,dict) List of all dependencies information
|
|
get_build_rules (dict) Building rules information
|
|
================================== =========================================
|
|
|
|
For the file to be valid, it should expose *at least* the 'project' section
|
|
with the name of the project. Other information like the project type have
|
|
default value:
|
|
|
|
================================== =======================================
|
|
Information Default value
|
|
================================== =======================================
|
|
name (str) Required.
|
|
version (str) auto. (see core.pkg.version.version_get)
|
|
type (str) 'bin'
|
|
description (str) Project description
|
|
target_support (list,str) [<empty>] (support all)
|
|
================================== =======================================
|
|
|
|
Also, this class will perform any vxSDK configuration needed described in
|
|
the "special" section 'config' which can expose "key/value" which will be
|
|
added (if not exist) in the vxSDK's configuration file
|
|
(~/.config/vxsdk/config.toml).
|
|
|
|
Example of a valid 'vxsdk.toml' file:
|
|
```
|
|
[project]
|
|
name = 'project'
|
|
type = 'addin'
|
|
|
|
[dependencies]
|
|
vxkernel = '^1.0.0'
|
|
|
|
[vxkernel.extra]
|
|
build = '--static --verbose'
|
|
|
|
[config]
|
|
'superh.path.sysroot' = '{path.sysroot}/superh'
|
|
'superh.path.sysroot_test' = '{superh.path.sysroot}/test/yes'
|
|
```
|
|
"""
|
|
def __init__(self, path, parent_path=None, extra_conf=None):
|
|
""" Open and parse the vxsdk.toml file
|
|
|
|
@args
|
|
> path (str) : project path which we can find `vxsdk.toml` file
|
|
> parent_path (str) : project parent path
|
|
> extra_conf (dict) : extra flags information about particular steps
|
|
|
|
@todo
|
|
> proper handle exception
|
|
"""
|
|
# try to open the file
|
|
self._path = os.path.abspath(path)
|
|
with open(self._path + '/vxsdk.toml', encoding='utf-8') as file:
|
|
self._toml = toml.loads(file.read())
|
|
|
|
# check mandatory information
|
|
# @notes
|
|
# - 'project' section
|
|
# - project name information
|
|
if 'project' not in self._toml or 'name' not in self._toml['project']:
|
|
raise Exception(f"'{self._path}': missing project name information")
|
|
|
|
# setup information and cache
|
|
self._type = None
|
|
self._target_support = None
|
|
self._parent_path = parent_path
|
|
self._extra_conf = extra_conf
|
|
|
|
def __str__(self):
|
|
""" Display project information """
|
|
content = f"project '{self.name}' - {self.version}\n"
|
|
content += '\n'
|
|
content += 'project meta\n'
|
|
content += ' - path:'.ljust(16) + f'{self.path}\n'
|
|
content += ' - parent:'.ljust(16) + f'{self.parent_path}\n'
|
|
content += ' - type:'.ljust(16) + f'{self.type}\n'
|
|
content += '\n'
|
|
content += 'Build information\n'
|
|
#if not self.build:
|
|
# content += ' default building rules used\n'
|
|
# content += '\n'
|
|
#else:
|
|
# rule_list = self.get_build_rules()
|
|
# for rule in rule_list:
|
|
# content += ' - '
|
|
# content += f'{rule}:'.ljust(16)
|
|
# content += f'{rule_list[rule]}\n'
|
|
# content += '\n'
|
|
#content += 'Dependencies list\n'
|
|
#if not self.dependencies:
|
|
# content += ' No dependencies for this project\n'
|
|
#else:
|
|
# for dep in self.dependencies:
|
|
# content += ' - ' + f'{dep.name}'.ljust(16) + f'({dep.version})\n'
|
|
return content
|
|
|
|
def __repr__(self):
|
|
return f'{self.name}<{self.version}>({self.type})'
|
|
|
|
#---
|
|
# Properties
|
|
#---
|
|
|
|
@property
|
|
def name(self):
|
|
"""<property> get project name"""
|
|
return self._toml['project']['name']
|
|
|
|
@property
|
|
def path(self):
|
|
"""<property> get project path"""
|
|
return self._path
|
|
|
|
@property
|
|
def description(self):
|
|
"""<property> get project description"""
|
|
if 'description' in self._toml['project']:
|
|
return self._toml['project']['description']
|
|
return ''
|
|
|
|
@property
|
|
def parent_path(self):
|
|
"""<property> Return project parent path """
|
|
return self._parent_path if self._parent_path else self._path
|
|
|
|
@property
|
|
def is_original(self):
|
|
"""<property> Return if the project is the target or a dependency"""
|
|
return not self._parent_path
|
|
|
|
@property
|
|
def extra_conf(self):
|
|
"""<property> Return extra pacakge information """
|
|
return self._extra_conf
|
|
|
|
@property
|
|
def type(self):
|
|
"""<property> get project build rules"""
|
|
if self._type:
|
|
return self._type
|
|
if 'type' not in self._toml['project']:
|
|
return 'bin'
|
|
self._type = self._toml['project']['type']
|
|
if self._type not in ['app', 'bin', 'lib', 'addin']:
|
|
log.warn(
|
|
f"{self.path}: project type '{self._type}' is unknown !"
|
|
f" Handled like a 'bin' type project"
|
|
)
|
|
return self._type
|
|
|
|
@property
|
|
def target_support(self):
|
|
"""<property> get supported target list"""
|
|
if not self._target_support:
|
|
self._target_support = []
|
|
if 'target' in self._toml['project']:
|
|
self._target_support = self._toml['project']['target']
|
|
return self._target_support
|
|
|
|
@property
|
|
def version(self):
|
|
"""<property> get current package version"""
|
|
return version_get(self.path)
|
|
|
|
#---
|
|
# Methods
|
|
#---
|
|
|
|
def get_dependencies(self, target=None):
|
|
""" Get project dependency list for a particular board target
|
|
|
|
@args
|
|
> target (str) - target name
|
|
|
|
@return
|
|
> Return a list of dependencies information : [
|
|
{
|
|
'name' : <dep name>,
|
|
'version' : <dep target version>,
|
|
'target' : <dep build target>,
|
|
'extra_conf' : <dep extra configuration>
|
|
},
|
|
...
|
|
]
|
|
"""
|
|
# check mandatory target requirement
|
|
if self.target_support:
|
|
if not target or target not in self.target_support:
|
|
log.warn(f"[{self.name}] target '{target}' not supported")
|
|
return []
|
|
|
|
# help particular section dump
|
|
def section_dep_fetch(section, target):
|
|
if 'dependencies' not in section:
|
|
return []
|
|
dep_list = []
|
|
for dep_name in section['dependencies']:
|
|
extra = None
|
|
if 'extra' in section and dep_name in section['extra']:
|
|
extra = section['extra'][dep_name]
|
|
pkg_target = target
|
|
pkg_version = section['dependencies'][dep_name].split('@')
|
|
if len(pkg_version) >= 2:
|
|
pkg_target = pkg_version[1]
|
|
dep_list.append({
|
|
'name' : dep_name,
|
|
'version' : pkg_version[0],
|
|
'target' : pkg_target,
|
|
'extra_conf' : extra
|
|
})
|
|
return dep_list
|
|
|
|
# fetch dependencies information in common and target-specific section
|
|
dep_list = section_dep_fetch(self._toml, target)
|
|
if target and target in self._toml:
|
|
dep_list += section_dep_fetch(self._toml[target], target)
|
|
return dep_list
|
|
|
|
def get_build_rules(self, target=None):
|
|
""" Get project building rules
|
|
|
|
@args
|
|
> target (str) - target name
|
|
|
|
@return
|
|
> a dictionary with all available building step : {
|
|
'configure' : <configure rule string>,
|
|
'build' : <build rule string>,
|
|
'install' : <install rule string>,
|
|
'uninstall' : <uninstall rule string>,
|
|
}
|
|
"""
|
|
def section_rules_fetch(section):
|
|
if 'build' not in section:
|
|
log.warn(f"[{self.name}] no building rules")
|
|
return {}
|
|
rules = {}
|
|
for rule in section['build']:
|
|
if rule in ['configure', 'build', 'install', 'uninstall']:
|
|
rules[rule] = section['build'][rule]
|
|
continue
|
|
log.warn(
|
|
f"[{self.name}] building rule '{rule}' doesn't exists"
|
|
)
|
|
return rules
|
|
|
|
# check if we need to fetch common rules or target-specific one
|
|
if target:
|
|
if self.target_support and target not in self.target_support:
|
|
log.error(f"[{self.name}] not supported target '{target}'")
|
|
return {}
|
|
if target in self._toml:
|
|
return section_rules_fetch(self._toml[target])
|
|
return section_rules_fetch(self._toml)
|