from pathlib import Path from typing import List, MutableMapping, Optional, Iterator from ee import EeException from ee.xml import types from ee.xml.bom_file_utils import find_pn, find_dpn, find_root_tag __all__ = [ "PartDb", "load_db", "save_db", ] class Entry(object): def __init__(self, new: bool, part: types.Part): self.new = new self.part = part self.pn = find_pn(part) def dpn(self, uri: str): return find_dpn(self.part, uri) class PartDb(object): def __init__(self): self.parts = [] # type: List[Entry] self.pn_index = {} # type: MutableMapping[str, Entry] self.dpn_indexes = {} # type: MutableMapping[str, MutableMapping[str, Entry]] self.new_entries = 0 def add_entry(self, part: types.Part, new: bool): e = Entry(new, part) self.parts.append(e) if e.pn: self.pn_index[e.pn] = e if e.new: self.new_entries = self.new_entries + 1 def iterparts(self, sort=False) -> Iterator[types.Part]: it = (e.part for e in self.parts) return sorted(it, key=lambda p: p.idProp) if sort else it def size(self) -> int: return len(self.parts) def find_by_pn(self, pn: str) -> Optional[types.Part]: entry = self.pn_index.get(pn, None) return entry.part if entry else None def find_by_dpn(self, distributor: str, pn: str) -> types.Part: idx = self.dpn_indexes.get(distributor) if idx is None: tmp = [(find_dpn(entry.part, distributor), entry) for entry in self.parts] idx = {dpn: entry for dpn, entry in tmp if dpn is not None} self.dpn_indexes[distributor] = idx return idx[pn].part def load_db(dir_path: Path) -> PartDb: db = PartDb() for file in dir_path.iterdir(): if not file.is_file() or not file.name.endswith(".xml") or file.name == "index.xml": continue part = types.parse(str(file), silence=True) # type: types.Part db.add_entry(part, False) return db def save_db(dir_path: Path, db: PartDb): if dir_path.exists(): if not dir_path.is_dir(): raise EeException("The given db path is not a directory") idx_path = dir_path / "index.xml" if not idx_path.is_file(): # Ninja creates the parent directories out the output.. if len(list(dir_path.iterdir())) > 0: raise EeException("The given db directory exists, but does not look like a part db dir") for p in dir_path.iterdir(): if not p.is_file(): raise EeException("Non-file: {}".format(p)) p.unlink() dir_path.rmdir() dir_path.mkdir(parents=True, exist_ok=True) idx = types.IndexFile() idx.filesProp = types.FileList() files = idx.filesProp.fileProp parts = db.iterparts() parts = sorted(parts, key=lambda p: p.idProp) for part in parts: id_ = part.id path = dir_path / "{}.xml".format(id_.replace("/", "_")) with path.open("w") as f: part.export(outfile=f, level=0, name_=find_root_tag(part)) files.append(types.File(path=str(path))) with (dir_path / "index.xml").open("w") as f: idx.export(f, level=0, name_=find_root_tag(idx))