diff --git a/docs/buildscript.md b/docs/buildscript.md index 2655770..d39eab4 100644 --- a/docs/buildscript.md +++ b/docs/buildscript.md @@ -26,7 +26,7 @@ Possible group names: - `tutorial` to process`tutorial/{readme.md,tutorial*.*}` - `demos` to process`examples/demo*.*` - Affected filetypes: `.gv`, `.bom.tsv`, `.png`, `.svg`, `.html` + Affected filetypes: `.gv`, `.tsv`, `.png`, `.svg`, `.html` ## Usage hints diff --git a/src/wireviz/wireviz.py b/src/wireviz/wireviz.py index ec3cde2..5ce37fc 100755 --- a/src/wireviz/wireviz.py +++ b/src/wireviz/wireviz.py @@ -30,6 +30,7 @@ def parse( output_name: Union[None, str] = None, image_paths: Union[Path, str, List] = [], extra_metadata: Dict = {}, + shared_bom: Dict = {}, ) -> Any: """ This function takes an input, parses it as a WireViz Harness file, @@ -114,6 +115,7 @@ def parse( metadata=Metadata(**yaml_data.get("metadata", {}), **extra_metadata), options=Options(**yaml_data.get("options", {})), tweak=Tweak(**yaml_data.get("tweak", {})), + shared_bom=shared_bom, ) # others # store mapping of components to their respective template diff --git a/src/wireviz/wv_bom.py b/src/wireviz/wv_bom.py index 165038f..bd0c861 100644 --- a/src/wireviz/wv_bom.py +++ b/src/wireviz/wv_bom.py @@ -15,7 +15,6 @@ MAX_DESCRIPTION = 40 BomEntry = namedtuple("BomEntry", "category qty designators") BomHash = namedtuple("BomHash", BOM_HASH_FIELDS) -BomHashList = namedtuple("BomHashList", BOM_HASH_FIELDS) PartNumberInfo = namedtuple("PartNumberInfo", "pn manufacturer mpn supplier spn") # TODO: different BOM modes diff --git a/src/wireviz/wv_cli.py b/src/wireviz/wv_cli.py index bdba966..c944242 100644 --- a/src/wireviz/wv_cli.py +++ b/src/wireviz/wv_cli.py @@ -21,6 +21,7 @@ format_codes = { "P": "pdf", "s": "svg", "t": "tsv", + "b": "shared_bom", } @@ -119,6 +120,8 @@ def cli(file, format, prepend, output_dir, output_name, version): else: prepend_input = "" + harness = None + shared_bom = {} sheet_current = 1 # run WireVIz on each input file for file in filepaths: @@ -151,14 +154,20 @@ def cli(file, format, prepend, output_dir, output_name, version): for p in prepend: image_paths.add(Path(p).parent) - wv.parse( + harness = wv.parse( yaml_input, - output_formats=output_formats, + return_types=("harness"), + output_formats=[f for f in output_formats if f != "shared_bom"], output_dir=_output_dir, output_name=_output_name, image_paths=list(image_paths), extra_metadata=extra_metadata, + shared_bom=shared_bom, ) + if "shared_bom" in output_formats: + _output_dir = file.parent if not output_dir else output_dir + harness.output(str(Path(_output_dir) / "shared_bom"), fmt="shared_bom") + shared_bom = harness.shared_bom print() # blank line after execution diff --git a/src/wireviz/wv_harness.py b/src/wireviz/wv_harness.py index ec5fb59..e5bc5fe 100644 --- a/src/wireviz/wv_harness.py +++ b/src/wireviz/wv_harness.py @@ -3,7 +3,7 @@ from collections import defaultdict from dataclasses import dataclass, field from pathlib import Path -from typing import List +from typing import Dict, List from graphviz import Graph @@ -45,6 +45,7 @@ class Harness: options: Options tweak: Tweak additional_bom_items: List[AdditionalComponent] = field(default_factory=list) + shared_bom: Dict = field(default_factory=dict) def __post_init__(self): self.connectors = {} @@ -119,9 +120,21 @@ class Harness: ), # x[0] = key, x[1] = value ) ) - # assign BOM IDs - for id, key in enumerate(self.bom.keys(), 1): - self.bom[key]["id"] = id + + next_id = len(self.shared_bom) + 1 + # TODO: for each harness, track a (harness_name, qty) pair + for key, values in self.bom.items(): + if key in self.shared_bom: + self.shared_bom[key]["qty"] += values["qty"] + values["id"] = self.shared_bom[key]["id"] + continue + self.shared_bom[key] = values + self.shared_bom[key]["id"] = next_id + values["id"] = next_id + next_id += 1 + + # print(f'bom length: {len(self.bom)}, shared_bom length: {len(self.shared_bom)}') # for debugging + # set BOM IDs within components (for BOM bubbles) for item in all_bom_relevant_items: if item.ignore_in_bom: @@ -131,6 +144,12 @@ class Harness: continue item.bom_id = self.bom[item.bom_hash]["id"] + self.bom = dict( + sorted( + self.bom.items(), + key=lambda x: (x[1]["id"],), + ) + ) # print_bom_table(self.bom) # for debugging def _add_to_internal_bom(self, item: Component): @@ -412,6 +431,11 @@ class Harness: if "csv" in fmt: # TODO: implement CSV output (preferrably using CSV library) print("CSV output is not yet supported") + if "shared_bom" in fmt: + shared_bomlist = bom_list(self.shared_bom) + shared_bom_tsv = bom2tsv(shared_bomlist) + open_file_write(f"{filename}.tsv").write(shared_bom_tsv) + # HTML output if "html" in fmt: generate_html_output(filename, bomlist, self.metadata, self.options)