import os import sys import tomli from dependency import * from cmake import CMakeBuildSystem from publish import Publish from build import UnknownBuildSystemError from env import Environment from source_only import SourceOnlyBuildSystem from generic import GenericBuildSystem all_seeds = {} class SeedParseError(Exception): pass class Seed(DependencyItem): def all_seeds(): return all_seeds def get(name): if name in all_seeds: return all_seeds[name] return None def load_file(self, path): with open(path, mode='rb') as f: self.__data = tomli.load(f) def __init_dependencies(self): self.__dependencies = {} if 'dependency' not in self.__data: return dependency = self.__data['dependency'] if 'seeds' in dependency: seeds = dependency['seeds'] self.__dependencies = {} for s in seeds: self.__dependencies[s] = SeedDependency(parent=self.name(), name=s) def __init_build_system(self): self.__build_system = None if 'build' not in self.__data: return build = self.__data['build'] if 'build_system' not in build: return source_dir = os.path.dirname(self.__seed_path) bin_dir = os.path.join(Environment.build_root(), self.name()) install = self.__data.get('install', None) if 'source_dir' in build: source_dir = build['source_dir'] match build['build_system']: case 'none': self.__build_system = None case 'cmake': self.__build_system = CMakeBuildSystem( parent=self, name=self.name(), source_dir=source_dir, bin_dir=bin_dir, install=install, data=build) case 'source-only': self.__build_system = SourceOnlyBuildSystem( parent=self, name=self.name(), source_dir=source_dir, bin_dir=bin_dir, install=install, data=build) case 'generic': self.__build_system = GenericBuildSystem( parent=self, name=self.name(), source_dir=source_dir, bin_dir=bin_dir, install=install, data=build) case _: raise UnknownBuildSystemError( 'Seed {} has unrecognised build system "{}"'.format(self.name(), build['build_system'])) def __init_publish(self): install_path = Environment.system_root() if 'build' in self.__data and 'build_for' in self.__data['build']: build_for = self.__data['build']['build_for'] if build_for == 'host': install_path = Environment.native_root() self.__publish = None if 'publish' not in self.__data: return self.__publish = Publish(install_path=install_path, data=self.__data['publish']) def add_dependency(self, name, dep): self.__dependencies[name] = dep def collect_dependencies(self, **kwargs): ctx = None if 'ctx' in kwargs: ctx = kwargs['ctx'] else: ctx = {} for k, d in self.__dependencies.items(): if k in ctx: continue ctx[d.name()] = d.target() if isinstance(d.target(), Seed): d.target().collect_dependencies(ctx=ctx) return list(ctx.values()) def __init__(self, **kwargs): super().__init__() if not 'path' in kwargs: return self.__seed_path = kwargs['path'] self.load_file(kwargs['path']) self.__init_dependencies() self.__init_build_system() self.__init_publish() def seed_path(self): return self.__seed_path def name(self): if not 'seed' in self.__data: return None s = self.__data['seed'] if 'name' in s: return s['name'] return None def type(self): if not 'seed' in self.__data: return None s = self.__data['seed'] if 'type' in s: return s['type'] return 'component' def dependencies(self): return self.__dependencies def publish(self): return self.__publish def install(self): return self.__data.get('install', None) def should_include_standard_dependencies(self): if 'dependency' not in self.__data: return True s = self.__data['dependency'] if 'no_standard_dependencies' in s: return not s['no_standard_dependencies'] return True def build_system(self): return self.__build_system def scan_directory(paths): for p in paths: for root, dirs, files in os.walk(p): for f in files: if not f.endswith('.seed'): continue seed_path = os.path.join(root, f) seed = None try: seed = Seed(path=seed_path) except tomli.TOMLDecodeError as e: raise SeedParseError('Err: Failed to parse seed file {}: {}'.format(seed_path, e)) all_seeds[seed.name()] = seed def resolve_all(): for s in all_seeds.values(): deps = s.dependencies() for k, v in deps.items(): v.resolve()