Better repoting of disabled component to the user.
This commit is contained in:
		
							parent
							
								
									dcde816298
								
							
						
					
					
						commit
						250930c977
					
				
					 5 changed files with 74 additions and 41 deletions
				
			
		|  | @ -40,6 +40,9 @@ def gen(out: TextIO, context: Context): | |||
|     writer.separator("Components") | ||||
| 
 | ||||
|     for instance in context.instances: | ||||
|         if not instance.enabled: | ||||
|             continue | ||||
| 
 | ||||
|         objects = instance.objsfiles(context) | ||||
|         writer.comment(f"Component: {instance.manifest.id}") | ||||
|         writer.comment(f"Resolved: {', '.join(instance.resolved)}") | ||||
|  | @ -76,9 +79,8 @@ def gen(out: TextIO, context: Context): | |||
|         writer.newline() | ||||
| 
 | ||||
| 
 | ||||
| def build(componentSpec: str, targetSpec: str, props: Props =  {}) -> str: | ||||
| def build(componentSpec: str, targetSpec: str, props: Props = {}) -> str: | ||||
|     context = contextFor(targetSpec, props) | ||||
|     target = context.target | ||||
| 
 | ||||
|     shell.mkdir(context.builddir()) | ||||
|     ninjaPath = f"{context.builddir()}/build.ninja" | ||||
|  | @ -91,6 +93,10 @@ def build(componentSpec: str, targetSpec: str, props: Props =  {}) -> str: | |||
|     if instance is None: | ||||
|         raise Exception(f"Component {componentSpec} not found") | ||||
| 
 | ||||
|     if not instance.enabled: | ||||
|         raise Exception( | ||||
|             f"Component {componentSpec} is disabled: {instance.disableReason}") | ||||
| 
 | ||||
|     shell.exec(f"ninja", "-v", "-f", ninjaPath, instance.outfile(context)) | ||||
| 
 | ||||
|     return instance.outfile(context) | ||||
|  |  | |||
|  | @ -155,10 +155,12 @@ def graphCmd(args: Args): | |||
| 
 | ||||
|     scope: str | None = cast(str | None, args.tryConsumeOpt("scope")) | ||||
|     onlyLibs: bool = args.consumeOpt("only-libs", False) == True | ||||
|     showDisabled: bool = args.consumeOpt("show-disabled", False) == True | ||||
| 
 | ||||
|     context = contextFor(targetSpec) | ||||
| 
 | ||||
|     graph.view(context, scope=scope, showExe=not onlyLibs) | ||||
|     graph.view(context, scope=scope, showExe=not onlyLibs, | ||||
|                showDisabled=showDisabled) | ||||
| 
 | ||||
| 
 | ||||
| cmds += [Cmd("g", "graph", "Show dependency graph", graphCmd)] | ||||
|  |  | |||
|  | @ -15,15 +15,21 @@ class IContext(Protocol): | |||
| 
 | ||||
| 
 | ||||
| class ComponentInstance: | ||||
|     enabled: bool = True | ||||
|     disableReason = "" | ||||
|     manifest: ComponentManifest | ||||
|     sources: list[str] = [] | ||||
|     resolved: list[str] = [] | ||||
| 
 | ||||
|     def __init__( | ||||
|             self, | ||||
|             enabled: bool, | ||||
|             disableReason: str, | ||||
|             manifest: ComponentManifest, | ||||
|             sources: list[str], | ||||
|             resolved: list[str]): | ||||
|         self.enabled = enabled | ||||
|         self.disableReason = disableReason | ||||
|         self.manifest = manifest | ||||
|         self.sources = sources | ||||
|         self.resolved = resolved | ||||
|  | @ -112,11 +118,12 @@ def loadAllComponents() -> list[ComponentManifest]: | |||
|             files)) | ||||
| 
 | ||||
| 
 | ||||
| def filterDisabled(components: list[ComponentManifest], target: TargetManifest) -> list[ComponentManifest]: | ||||
|     return list(filter(lambda c: c.isEnabled(target), components)) | ||||
| def filterDisabled(components: list[ComponentManifest], target: TargetManifest) -> tuple[list[ComponentManifest], list[ComponentManifest]]: | ||||
|     return list(filter(lambda c: c.isEnabled(target)[0], components)), \ | ||||
|         list(filter(lambda c: not c.isEnabled(target)[0], components)) | ||||
| 
 | ||||
| 
 | ||||
| def providerFor(what: str, components: list[ComponentManifest]) -> str | None: | ||||
| def providerFor(what: str, components: list[ComponentManifest]) -> tuple[str | None, str]: | ||||
|     result: list[ComponentManifest] = list( | ||||
|         filter(lambda c: c.id == what, components)) | ||||
| 
 | ||||
|  | @ -125,26 +132,27 @@ def providerFor(what: str, components: list[ComponentManifest]) -> str | None: | |||
|         result = list(filter(lambda x: (what in x.provides), components)) | ||||
| 
 | ||||
|     if len(result) == 0: | ||||
|         logger.error(f"No provider for {what}") | ||||
|         return None | ||||
|         logger.error(f"No provider for '{what}'") | ||||
|         return (None, f"No provider for '{what}'") | ||||
| 
 | ||||
|     if len(result) > 1: | ||||
|         logger.error(f"Multiple providers for {what}: {result}") | ||||
|         return None | ||||
|         ids = list(map(lambda x: x.id, result)) | ||||
|         logger.error(f"Multiple providers for '{what}': {result}") | ||||
|         return (None, f"Multiple providers for '{what}': {','.join(ids)}") | ||||
| 
 | ||||
|     return result[0].id | ||||
|     return (result[0].id, "") | ||||
| 
 | ||||
| 
 | ||||
| def resolveDeps(componentSpec: str, components: list[ComponentManifest], target: TargetManifest) -> tuple[bool,  list[str]]: | ||||
| def resolveDeps(componentSpec: str, components: list[ComponentManifest], target: TargetManifest) -> tuple[bool, str,  list[str]]: | ||||
|     mapping = dict(map(lambda c: (c.id, c), components)) | ||||
| 
 | ||||
|     def resolveInner(what: str, stack: list[str] = []) -> tuple[bool,  list[str]]: | ||||
|     def resolveInner(what: str, stack: list[str] = []) -> tuple[bool, str,  list[str]]: | ||||
|         result: list[str] = [] | ||||
|         what = target.route(what) | ||||
|         resolved = providerFor(what, components) | ||||
|         resolved, unresolvedReason = providerFor(what, components) | ||||
| 
 | ||||
|         if resolved is None: | ||||
|             return False,  [] | ||||
|             return False, unresolvedReason,  [] | ||||
| 
 | ||||
|         if resolved in stack: | ||||
|             raise Exception(f"Dependency loop: {stack} -> {resolved}") | ||||
|  | @ -152,35 +160,37 @@ def resolveDeps(componentSpec: str, components: list[ComponentManifest], target: | |||
|         stack.append(resolved) | ||||
| 
 | ||||
|         for req in mapping[resolved].requires: | ||||
|             keep, reqs = resolveInner(req, stack) | ||||
|             keep, unresolvedReason,  reqs = resolveInner(req, stack) | ||||
| 
 | ||||
|             if not keep: | ||||
|                 stack.pop() | ||||
|                 logger.error(f"Dependency {req} not met for {resolved}") | ||||
|                 return False,  [] | ||||
|                 logger.error(f"Dependency '{req}' not met for '{resolved}'") | ||||
|                 return False, unresolvedReason,  [] | ||||
| 
 | ||||
|             result.extend(reqs) | ||||
| 
 | ||||
|         stack.pop() | ||||
|         result.insert(0, resolved) | ||||
| 
 | ||||
|         return True, result | ||||
|         return True, "", result | ||||
| 
 | ||||
|     enabled, resolved = resolveInner(componentSpec) | ||||
|     enabled, unresolvedReason, resolved = resolveInner(componentSpec) | ||||
| 
 | ||||
|     return enabled, resolved | ||||
|     return enabled, unresolvedReason, resolved | ||||
| 
 | ||||
| 
 | ||||
| def instanciate(componentSpec: str, components: list[ComponentManifest], target: TargetManifest) -> ComponentInstance | None: | ||||
|     manifest = next(filter(lambda c: c.id == componentSpec, components)) | ||||
|     sources = shell.find( | ||||
|         manifest.dirname(), ["*.c", "*.cpp", "*.s", "*.asm"], recusive=False) | ||||
|     enabled, resolved = resolveDeps(componentSpec, components, target) | ||||
|     enabled, unresolvedReason, resolved = resolveDeps( | ||||
|         componentSpec, components, target) | ||||
| 
 | ||||
|     if not enabled: | ||||
|         return None | ||||
|     return ComponentInstance(enabled, unresolvedReason, manifest, sources, resolved[1:]) | ||||
| 
 | ||||
|     return ComponentInstance(manifest, sources, resolved[1:]) | ||||
| 
 | ||||
| def instanciateDisabled(component: ComponentManifest,  target: TargetManifest) -> ComponentInstance: | ||||
|     return ComponentInstance(False, component.isEnabled(target)[1], component, [], []) | ||||
| 
 | ||||
| 
 | ||||
| context: dict = {} | ||||
|  | @ -190,7 +200,7 @@ def contextFor(targetSpec: str, props: Props = {}) -> Context: | |||
|     if targetSpec in context: | ||||
|         return context[targetSpec] | ||||
| 
 | ||||
|     logger.log(f"Loading context for {targetSpec}") | ||||
|     logger.log(f"Loading context for '{targetSpec}'") | ||||
| 
 | ||||
|     targetEls = targetSpec.split(":") | ||||
| 
 | ||||
|  | @ -201,7 +211,7 @@ def contextFor(targetSpec: str, props: Props = {}) -> Context: | |||
|     target.props |= props | ||||
| 
 | ||||
|     components = loadAllComponents() | ||||
|     components = filterDisabled(components, target) | ||||
|     components, disabled = filterDisabled(components, target) | ||||
| 
 | ||||
|     tools: Tools = {} | ||||
| 
 | ||||
|  | @ -225,7 +235,10 @@ def contextFor(targetSpec: str, props: Props = {}) -> Context: | |||
|             tool = component.tools[toolSpec] | ||||
|             tools[toolSpec].args += tool.args | ||||
| 
 | ||||
|     instances = cast(list[ComponentInstance], list(filter(lambda e: e != None, map(lambda c: instanciate( | ||||
|     instances: list[ComponentInstance] = list( | ||||
|         map(lambda c: instanciateDisabled(c, target), disabled)) | ||||
| 
 | ||||
|     instances += cast(list[ComponentInstance], list(filter(lambda e: e != None, map(lambda c: instanciate( | ||||
|         c.id, components, target), components)))) | ||||
| 
 | ||||
|     context[targetSpec] = Context( | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ from osdk.context import Context | |||
| from osdk import vt100 | ||||
| 
 | ||||
| 
 | ||||
| def view(context: Context, scope: str | None = None, showExe: bool = True): | ||||
| def view(context: Context, scope: str | None = None, showExe: bool = True, showDisabled: bool = False): | ||||
|     from graphviz import Digraph | ||||
| 
 | ||||
|     g = Digraph(context.target.id, filename='graph.gv') | ||||
|  | @ -26,16 +26,27 @@ def view(context: Context, scope: str | None = None, showExe: bool = True): | |||
|                 instance.manifest.id not in scopeInstance.resolved: | ||||
|             continue | ||||
| 
 | ||||
|         fillcolor = "lightgrey" if instance.isLib() else "lightblue" | ||||
|         shape = "plaintext" if not scope == instance.manifest.id else 'box' | ||||
|         if instance.enabled: | ||||
|             fillcolor = "lightgrey" if instance.isLib() else "lightblue" | ||||
|             shape = "plaintext" if not scope == instance.manifest.id else 'box' | ||||
| 
 | ||||
|         g.node(instance.manifest.id, f"<<B>{instance.manifest.id}</B><BR/>{vt100.wordwrap(instance.manifest.decription, 40,newline='<BR/>')}>", | ||||
|                shape=shape, style="filled", fillcolor=fillcolor) | ||||
|             g.node(instance.manifest.id, f"<<B>{instance.manifest.id}</B><BR/>{vt100.wordwrap(instance.manifest.decription, 40,newline='<BR/>')}>", | ||||
|                    shape=shape, style="filled", fillcolor=fillcolor) | ||||
| 
 | ||||
|         for req in instance.manifest.requires: | ||||
|             g.edge(instance.manifest.id, req) | ||||
|             for req in instance.manifest.requires: | ||||
|                 g.edge(instance.manifest.id, req) | ||||
| 
 | ||||
|         for req in instance.manifest.provides: | ||||
|             g.edge(req, instance.manifest.id, arrowhead="none") | ||||
|             for req in instance.manifest.provides: | ||||
|                 g.edge(req, instance.manifest.id, arrowhead="none") | ||||
|         elif showDisabled: | ||||
|             g.node(instance.manifest.id, f"<<B>{instance.manifest.id}</B><BR/>{vt100.wordwrap(instance.manifest.decription, 40,newline='<BR/>')}<BR/><BR/><I>{vt100.wordwrap(instance.disableReason, 40,newline='<BR/>')}</I>>", | ||||
|                    shape="plaintext", style="filled",   fontcolor="#999999", fillcolor="#eeeeee") | ||||
| 
 | ||||
|             for req in instance.manifest.requires: | ||||
|                 g.edge(instance.manifest.id, req, color="#aaaaaa") | ||||
| 
 | ||||
|             for req in instance.manifest.provides: | ||||
|                 g.edge(req, instance.manifest.id, | ||||
|                        arrowhead="none", color="#aaaaaa") | ||||
| 
 | ||||
|     g.view(filename=f"{context.builddir()}/graph.gv") | ||||
|  |  | |||
|  | @ -154,16 +154,17 @@ class ComponentManifest(Manifest): | |||
|     def __repr__(self): | ||||
|         return f"ComponentManifest({self.id})" | ||||
| 
 | ||||
|     def isEnabled(self, target: TargetManifest): | ||||
|     def isEnabled(self, target: TargetManifest) -> tuple[bool, str]: | ||||
|         for k, v in self.enableIf.items(): | ||||
|             if not k in target.props: | ||||
|                 logger.log( | ||||
|                     f"Component {self.id} disabled by missing {k} in target") | ||||
|                 return False | ||||
|                 return False, f"Missing props '{k}' in target" | ||||
| 
 | ||||
|             if not target.props[k] in v: | ||||
|                 vStrs = [f"'{str(x)}'" for x in v] | ||||
|                 logger.log( | ||||
|                     f"Component {self.id} disabled by {k}={target.props[k]} not in {v}") | ||||
|                 return False | ||||
|                 return False, f"Props missmatch for '{k}': Got '{target.props[k]}' but expected {', '.join(vStrs)}" | ||||
| 
 | ||||
|         return True | ||||
|         return True, "" | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue