diff --git a/MANIFEST.csv b/MANIFEST.csv index 444b65e..edaa82e 100644 --- a/MANIFEST.csv +++ b/MANIFEST.csv @@ -574,3 +574,5 @@ footprint,/var/folders/cv/lwgyj_k14gx2rc3t2rlt29s80000gn/T/snapeda_d8f9gfkl/CUI_ 3d-model,/var/folders/cv/lwgyj_k14gx2rc3t2rlt29s80000gn/T/snapeda_d8f9gfkl/SJ-3506-SMT-TR.step,3dmodels/other/SJ-3506-SMT-TR.step,NEW,58d533dd8e54e2e1e7c6e02c5b1c1b35df76cdcc30748bce395b0573d5131741,category=other symbol,/var/folders/cv/lwgyj_k14gx2rc3t2rlt29s80000gn/T/ultralibrarian_v0rwnotp/KiCADv6/2026-08-20_07-44-49.kicad_sym,symbols/other/XTAC5212IRGER.kicad_sym,NEW,c85d2d11871a3cbac15e93b1b51b575513853da1bb42789be586b5bb3c6148ae,category=other footprint,/var/folders/cv/lwgyj_k14gx2rc3t2rlt29s80000gn/T/ultralibrarian_v0rwnotp/KiCADv6/footprints.pretty/VQFN24_RGE_CORNERPADS_TEX.kicad_mod,footprints/other/XTAC5212IRGER.pretty/VQFN24_RGE_CORNERPADS_TEX.kicad_mod,NEW,2a2a1a5f831aeeebfde035b88094ccd238802fea4fd53c9bec12a8fc018a39cd,category=other +symbol,/var/folders/cv/lwgyj_k14gx2rc3t2rlt29s80000gn/T/ultralibrarian_u0c0m5kn/KiCADv6/2026-08-20_09-18-34.kicad_sym,symbols/other/XTAC5212IRGER.kicad_sym,UPDATED,5979d707fa7f1b5a0cfa6a1083b300d265d8beb760fc0a957c0090d973a3fd29,category=other +footprint,/var/folders/cv/lwgyj_k14gx2rc3t2rlt29s80000gn/T/ultralibrarian_u0c0m5kn/KiCADv6/footprints.pretty/VQFN24_RGE_CORNERPADS_TEX.kicad_mod,footprints/other/XTAC5212IRGER.pretty/VQFN24_RGE_CORNERPADS_TEX.kicad_mod,UPDATED,2a2a1a5f831aeeebfde035b88094ccd238802fea4fd53c9bec12a8fc018a39cd,category=other diff --git a/scripts/import_component.py b/scripts/import_component.py index 50f7903..70a16fe 100644 --- a/scripts/import_component.py +++ b/scripts/import_component.py @@ -67,14 +67,21 @@ def validate_args(args) -> None: ) -def import_symbol(name: str, category: str, src: Path, manifest_rows: list, report: list) -> Path: +def import_symbol(name: str, category: str, src: Path, manifest_rows: list, report: list, update: bool = False) -> Path: existing = lc.find_symbol_by_name(ROOT, name) if existing is not None: - raise ImportError_( - f"A component named '{name}' already exists: {existing.relative_to(ROOT)}. " - f"Refusing to overwrite -- choose a different --name or remove the existing " - f"component first." - ) + if not update: + raise ImportError_( + f"A component named '{name}' already exists: {existing.relative_to(ROOT)}. " + f"Refusing to overwrite -- choose a different --name, pass --update to " + f"replace it in place, or remove the existing component first." + ) + + digest = lc.sha256_file(src) + shutil.copy2(src, existing) + manifest_rows.append(["symbol", str(src), str(existing.relative_to(ROOT)), "UPDATED", digest, f"category={category}"]) + report.append(f" SYMBOL UPDATED {existing.relative_to(ROOT)}") + return existing dst = ROOT / "symbols" / category / f"{name}.kicad_sym" dst.parent.mkdir(parents=True, exist_ok=True) @@ -87,9 +94,24 @@ def import_symbol(name: str, category: str, src: Path, manifest_rows: list, repo return dst -def import_footprint(name: str, category: str, src: Path, manifest_rows: list, report: list): +def import_footprint(name: str, category: str, src: Path, manifest_rows: list, report: list, update: bool = False): """Returns (footprint_path_or_None_if_reused, fp_nickname, fp_name, status).""" digest = lc.sha256_file(src) + pretty_dir = ROOT / "footprints" / category / f"{name}.pretty" + basename = src.name + + if update and pretty_dir.is_dir(): + stale = [p for p in pretty_dir.glob("*.kicad_mod") if p.name != basename] + for p in stale: + p.unlink() + report.append(f" FOOTPRINT REMOVED stale variant {p.relative_to(ROOT)}") + + target = pretty_dir / basename + pretty_dir.mkdir(parents=True, exist_ok=True) + shutil.copy2(src, target) + manifest_rows.append(["footprint", str(src), str(target.relative_to(ROOT)), "UPDATED", digest, f"category={category}"]) + report.append(f" FOOTPRINT UPDATED {target.relative_to(ROOT)}") + return target, lc.fp_nickname(pretty_dir), target.stem, "UPDATED" existing = lc.find_footprint_by_hash(ROOT, digest) if existing is not None: @@ -102,9 +124,6 @@ def import_footprint(name: str, category: str, src: Path, manifest_rows: list, r report.append(f" FOOTPRINT DUPLICATE reused {existing.relative_to(ROOT)}") return None, nickname, existing.stem, "DUPLICATE" - pretty_dir = ROOT / "footprints" / category / f"{name}.pretty" - basename = src.name - colliding = lc.find_footprints_by_basename(ROOT, basename) if colliding: new_basename = f"{name}_{src.stem}{src.suffix}" @@ -182,6 +201,7 @@ def main() -> int: parser.add_argument("--symbol", required=True, help="Path to the source .kicad_sym file") parser.add_argument("--footprint", help="Path to the source .kicad_mod file") parser.add_argument("--model", help="Path to the source 3D model (.step/.stp/.wrl/.wrz)") + parser.add_argument("--update", action="store_true", help="Replace an existing component's symbol/footprint in place instead of refusing") args = parser.parse_args() try: @@ -196,7 +216,7 @@ def main() -> int: report: list[str] = [f"Importing '{name}' into category '{category}'"] try: - import_symbol(name, category, Path(args.symbol).expanduser().resolve(), manifest_rows, report) + import_symbol(name, category, Path(args.symbol).expanduser().resolve(), manifest_rows, report, update=args.update) except ImportError_ as e: print(f"ERROR: {e}") lc.append_manifest_rows(ROOT, [["symbol", args.symbol, "", "ERROR", "", str(e)]]) @@ -205,7 +225,7 @@ def main() -> int: fp_path = None if args.footprint: fp_path, fp_nick, fp_name, _ = import_footprint( - name, category, Path(args.footprint).expanduser().resolve(), manifest_rows, report + name, category, Path(args.footprint).expanduser().resolve(), manifest_rows, report, update=args.update ) if args.model: diff --git a/scripts/import_snapeda.py b/scripts/import_snapeda.py index 8ecea33..e9fbd0d 100644 --- a/scripts/import_snapeda.py +++ b/scripts/import_snapeda.py @@ -66,6 +66,7 @@ def main() -> int: parser.add_argument("--zip", required=True, help="Path to the SnapEDA .zip download") parser.add_argument("--name", help="Component name (default: taken from the symbol's own name)") parser.add_argument("--category", choices=lc.CATEGORIES, help="MIKILAB category (default: auto-detected)") + parser.add_argument("--update", action="store_true", help="Replace an existing component's symbol/footprint in place instead of refusing") args = parser.parse_args() zip_path = Path(args.zip).expanduser().resolve() @@ -103,14 +104,14 @@ def main() -> int: report.append(f" found {label}: {path.relative_to(tmp_dir) if path else '(none)'}") try: - ic.import_symbol(name, category, symbol, manifest_rows, report) + ic.import_symbol(name, category, symbol, manifest_rows, report, update=args.update) except ic.ImportError_ as e: print(f"ERROR: {e}") lc.append_manifest_rows(ROOT, [["symbol", str(zip_path), "", "ERROR", "", str(e)]]) return 1 if footprint is not None: - fp_path, fp_nick, fp_name, _ = ic.import_footprint(name, category, footprint, manifest_rows, report) + fp_path, fp_nick, fp_name, _ = ic.import_footprint(name, category, footprint, manifest_rows, report, update=args.update) if model is not None: ic.import_model(name, category, model, fp_path, manifest_rows, report) diff --git a/scripts/import_ultralibrarian.py b/scripts/import_ultralibrarian.py index 20ba13a..ad0ca02 100644 --- a/scripts/import_ultralibrarian.py +++ b/scripts/import_ultralibrarian.py @@ -122,6 +122,7 @@ def main() -> int: parser.add_argument("--zip", required=True, help="Path to the UltraLibrarian .zip download") parser.add_argument("--name", help="Component name (default: taken from the symbol's own name)") parser.add_argument("--category", choices=lc.CATEGORIES, help="MIKILAB category (default: auto-detected)") + parser.add_argument("--update", action="store_true", help="Replace an existing component's symbol/footprint in place instead of refusing") args = parser.parse_args() zip_path = Path(args.zip).expanduser().resolve() @@ -178,7 +179,7 @@ def main() -> int: ) try: - ic.import_symbol(name, category, symbol, manifest_rows, report) + ic.import_symbol(name, category, symbol, manifest_rows, report, update=args.update) except ic.ImportError_ as e: print(f"ERROR: {e}") lc.append_manifest_rows(ROOT, [["symbol", str(zip_path), "", "ERROR", "", str(e)]]) @@ -188,7 +189,7 @@ def main() -> int: footprint_ref = symbol_footprint_ref(symbol) footprint = pick_footprint(footprint_candidates, footprint_ref, report) - fp_path, fp_nick, fp_name, _ = ic.import_footprint(name, category, footprint, manifest_rows, report) + fp_path, fp_nick, fp_name, _ = ic.import_footprint(name, category, footprint, manifest_rows, report, update=args.update) if model is not None: ic.import_model(name, category, model, fp_path, manifest_rows, report) diff --git a/symbols/other/XTAC5212IRGER.kicad_sym b/symbols/other/XTAC5212IRGER.kicad_sym index a607f0b..ba5ced6 100644 --- a/symbols/other/XTAC5212IRGER.kicad_sym +++ b/symbols/other/XTAC5212IRGER.kicad_sym @@ -21,26 +21,26 @@ (property "ki_fp_filters" "VQFN24_RGE_CORNERPADS_TEX VQFN24_RGE_CORNERPADS_TEX-M VQFN24_RGE_CORNERPADS_TEX-L" (id 6) (at 0 0 0) (effects (font (size 1.27 1.27)) hide) ) - (symbol "XTAC5212IRGER_1_1" + (symbol "XTAC5212IRGER_0_1" (polyline (pts (xy 7.62 5.08) - (xy 7.62 -48.26) + (xy 7.62 -40.64) ) (stroke (width 0.127) (type default) (color 0 0 0 0)) (fill (type none)) ) (polyline (pts - (xy 7.62 -48.26) - (xy 43.18 -48.26) + (xy 7.62 -40.64) + (xy 43.18 -40.64) ) (stroke (width 0.127) (type default) (color 0 0 0 0)) (fill (type none)) ) (polyline (pts - (xy 43.18 -48.26) + (xy 43.18 -40.64) (xy 43.18 5.08) ) (stroke (width 0.127) (type default) (color 0 0 0 0)) @@ -54,153 +54,119 @@ (stroke (width 0.127) (type default) (color 0 0 0 0)) (fill (type none)) ) - (pin bidirectional line (at 0 -30.48 0) (length 7.62) - (name "BCLK" (effects (font (size 1.27 1.27)))) - (number "2" (effects (font (size 1.27 1.27)))) - ) - (pin bidirectional line (at 0 -38.1 0) (length 7.62) - (name "FSYNC" (effects (font (size 1.27 1.27)))) - (number "3" (effects (font (size 1.27 1.27)))) - ) - (pin bidirectional line (at 0 -33.02 0) (length 7.62) - (name "DOUT" (effects (font (size 1.27 1.27)))) - (number "4" (effects (font (size 1.27 1.27)))) - ) - (pin input line (at 0 -2.54 0) (length 7.62) - (name "DIN" (effects (font (size 1.27 1.27)))) - (number "5" (effects (font (size 1.27 1.27)))) - ) - (pin input line (at 0 -22.86 0) (length 7.62) - (name "SCL" (effects (font (size 1.27 1.27)))) - (number "7" (effects (font (size 1.27 1.27)))) - ) - (pin input line (at 0 -25.4 0) (length 7.62) - (name "SDA" (effects (font (size 1.27 1.27)))) - (number "8" (effects (font (size 1.27 1.27)))) - ) - (pin bidirectional line (at 50.8 -17.78 180) (length 7.62) - (name "GPIO1" (effects (font (size 1.27 1.27)))) - (number "9" (effects (font (size 1.27 1.27)))) - ) - (pin bidirectional line (at 50.8 -20.32 180) (length 7.62) - (name "GPIO2" (effects (font (size 1.27 1.27)))) - (number "10" (effects (font (size 1.27 1.27)))) - ) - (pin output line (at 50.8 0 180) (length 7.62) - (name "GPO1" (effects (font (size 1.27 1.27)))) - (number "11" (effects (font (size 1.27 1.27)))) - ) - (pin input line (at 0 -7.62 0) (length 7.62) - (name "GPI1" (effects (font (size 1.27 1.27)))) - (number "12" (effects (font (size 1.27 1.27)))) - ) - (pin input line (at 0 0 0) (length 7.62) - (name "ADDR" (effects (font (size 1.27 1.27)))) - (number "13" (effects (font (size 1.27 1.27)))) - ) - (pin unspecified line (at 0 -40.64 0) (length 7.62) - (name "MICBIAS" (effects (font (size 1.27 1.27)))) - (number "14" (effects (font (size 1.27 1.27)))) - ) - (pin input line (at 0 -15.24 0) (length 7.62) - (name "IN1P" (effects (font (size 1.27 1.27)))) - (number "15" (effects (font (size 1.27 1.27)))) - ) - (pin input line (at 0 -12.7 0) (length 7.62) - (name "IN1M" (effects (font (size 1.27 1.27)))) - (number "16" (effects (font (size 1.27 1.27)))) - ) - (pin input line (at 0 -20.32 0) (length 7.62) - (name "IN2P" (effects (font (size 1.27 1.27)))) - (number "17" (effects (font (size 1.27 1.27)))) - ) - (pin input line (at 0 -17.78 0) (length 7.62) - (name "IN2M" (effects (font (size 1.27 1.27)))) - (number "18" (effects (font (size 1.27 1.27)))) - ) - (pin output line (at 50.8 -2.54 180) (length 7.62) - (name "OUT1M" (effects (font (size 1.27 1.27)))) - (number "19" (effects (font (size 1.27 1.27)))) - ) - (pin output line (at 50.8 -5.08 180) (length 7.62) - (name "OUT1P" (effects (font (size 1.27 1.27)))) - (number "20" (effects (font (size 1.27 1.27)))) - ) - (pin output line (at 50.8 -12.7 180) (length 7.62) - (name "OUT2P" (effects (font (size 1.27 1.27)))) - (number "21" (effects (font (size 1.27 1.27)))) - ) - (pin output line (at 50.8 -10.16 180) (length 7.62) - (name "OUT2M" (effects (font (size 1.27 1.27)))) - (number "22" (effects (font (size 1.27 1.27)))) - ) - (pin unspecified line (at 0 -43.18 0) (length 7.62) - (name "VREF" (effects (font (size 1.27 1.27)))) - (number "24" (effects (font (size 1.27 1.27)))) - ) - (pin unspecified line (at 0 -35.56 0) (length 7.62) - (name "EPAD" (effects (font (size 1.27 1.27)))) - (number "29" (effects (font (size 1.27 1.27)))) - ) - ) - (symbol "XTAC5212IRGER_2_1" - (polyline - (pts - (xy 7.62 5.08) - (xy 7.62 -12.7) - ) - (stroke (width 0.127) (type default) (color 0 0 0 0)) - (fill (type none)) - ) - (polyline - (pts - (xy 7.62 -12.7) - (xy 33.02 -12.7) - ) - (stroke (width 0.127) (type default) (color 0 0 0 0)) - (fill (type none)) - ) - (polyline - (pts - (xy 33.02 -12.7) - (xy 33.02 5.08) - ) - (stroke (width 0.127) (type default) (color 0 0 0 0)) - (fill (type none)) - ) - (polyline - (pts - (xy 33.02 5.08) - (xy 7.62 5.08) - ) - (stroke (width 0.127) (type default) (color 0 0 0 0)) - (fill (type none)) - ) - (pin power_in line (at 0 -2.54 0) (length 7.62) + (pin power_in line (at 0 0 0) (length 7.62) (name "DREG" (effects (font (size 1.27 1.27)))) (number "1" (effects (font (size 1.27 1.27)))) ) - (pin power_in line (at 0 -5.08 0) (length 7.62) + (pin bidirectional line (at 0 -2.54 0) (length 7.62) + (name "BCLK" (effects (font (size 1.27 1.27)))) + (number "2" (effects (font (size 1.27 1.27)))) + ) + (pin bidirectional line (at 0 -5.08 0) (length 7.62) + (name "FSYNC" (effects (font (size 1.27 1.27)))) + (number "3" (effects (font (size 1.27 1.27)))) + ) + (pin bidirectional line (at 0 -7.62 0) (length 7.62) + (name "DOUT" (effects (font (size 1.27 1.27)))) + (number "4" (effects (font (size 1.27 1.27)))) + ) + (pin input line (at 0 -10.16 0) (length 7.62) + (name "DIN" (effects (font (size 1.27 1.27)))) + (number "5" (effects (font (size 1.27 1.27)))) + ) + (pin power_in line (at 0 -12.7 0) (length 7.62) (name "IOVDD" (effects (font (size 1.27 1.27)))) (number "6" (effects (font (size 1.27 1.27)))) ) - (pin power_in line (at 0 0 0) (length 7.62) + (pin input line (at 0 -15.24 0) (length 7.62) + (name "SCL" (effects (font (size 1.27 1.27)))) + (number "7" (effects (font (size 1.27 1.27)))) + ) + (pin input line (at 0 -17.78 0) (length 7.62) + (name "SDA" (effects (font (size 1.27 1.27)))) + (number "8" (effects (font (size 1.27 1.27)))) + ) + (pin bidirectional line (at 0 -20.32 0) (length 7.62) + (name "GPIO1" (effects (font (size 1.27 1.27)))) + (number "9" (effects (font (size 1.27 1.27)))) + ) + (pin bidirectional line (at 0 -22.86 0) (length 7.62) + (name "GPIO2" (effects (font (size 1.27 1.27)))) + (number "10" (effects (font (size 1.27 1.27)))) + ) + (pin output line (at 0 -25.4 0) (length 7.62) + (name "GPO1" (effects (font (size 1.27 1.27)))) + (number "11" (effects (font (size 1.27 1.27)))) + ) + (pin input line (at 0 -27.94 0) (length 7.62) + (name "GPI1" (effects (font (size 1.27 1.27)))) + (number "12" (effects (font (size 1.27 1.27)))) + ) + (pin input line (at 0 -30.48 0) (length 7.62) + (name "ADDR" (effects (font (size 1.27 1.27)))) + (number "13" (effects (font (size 1.27 1.27)))) + ) + (pin unspecified line (at 0 -33.02 0) (length 7.62) + (name "MICBIAS" (effects (font (size 1.27 1.27)))) + (number "14" (effects (font (size 1.27 1.27)))) + ) + (pin input line (at 50.8 -35.56 180) (length 7.62) + (name "IN1P" (effects (font (size 1.27 1.27)))) + (number "15" (effects (font (size 1.27 1.27)))) + ) + (pin input line (at 50.8 -33.02 180) (length 7.62) + (name "IN1M" (effects (font (size 1.27 1.27)))) + (number "16" (effects (font (size 1.27 1.27)))) + ) + (pin input line (at 50.8 -30.48 180) (length 7.62) + (name "IN2P" (effects (font (size 1.27 1.27)))) + (number "17" (effects (font (size 1.27 1.27)))) + ) + (pin input line (at 50.8 -27.94 180) (length 7.62) + (name "IN2M" (effects (font (size 1.27 1.27)))) + (number "18" (effects (font (size 1.27 1.27)))) + ) + (pin output line (at 50.8 -25.4 180) (length 7.62) + (name "OUT1M" (effects (font (size 1.27 1.27)))) + (number "19" (effects (font (size 1.27 1.27)))) + ) + (pin output line (at 50.8 -22.86 180) (length 7.62) + (name "OUT1P" (effects (font (size 1.27 1.27)))) + (number "20" (effects (font (size 1.27 1.27)))) + ) + (pin output line (at 50.8 -20.32 180) (length 7.62) + (name "OUT2P" (effects (font (size 1.27 1.27)))) + (number "21" (effects (font (size 1.27 1.27)))) + ) + (pin output line (at 50.8 -17.78 180) (length 7.62) + (name "OUT2M" (effects (font (size 1.27 1.27)))) + (number "22" (effects (font (size 1.27 1.27)))) + ) + (pin power_in line (at 50.8 -15.24 180) (length 7.62) (name "AVDD" (effects (font (size 1.27 1.27)))) (number "23" (effects (font (size 1.27 1.27)))) ) - (pin power_out line (at 40.64 0 180) (length 7.62) + (pin unspecified line (at 50.8 -12.7 180) (length 7.62) + (name "VREF" (effects (font (size 1.27 1.27)))) + (number "24" (effects (font (size 1.27 1.27)))) + ) + (pin unspecified line (at 50.8 -10.16 180) (length 7.62) + (name "EPAD" (effects (font (size 1.27 1.27)))) + (number "29" (effects (font (size 1.27 1.27)))) + ) + (pin power_out line (at 50.8 -7.62 180) (length 7.62) (name "VSS" (effects (font (size 1.27 1.27)))) (number "A1" (effects (font (size 1.27 1.27)))) ) - (pin power_out line (at 40.64 -2.54 180) (length 7.62) + (pin power_out line (at 50.8 -5.08 180) (length 7.62) (name "VSS" (effects (font (size 1.27 1.27)))) (number "A2" (effects (font (size 1.27 1.27)))) ) - (pin power_out line (at 40.64 -5.08 180) (length 7.62) + (pin power_out line (at 50.8 -2.54 180) (length 7.62) (name "VSS" (effects (font (size 1.27 1.27)))) (number "A3" (effects (font (size 1.27 1.27)))) ) - (pin power_out line (at 40.64 -7.62 180) (length 7.62) + (pin power_out line (at 50.8 0 180) (length 7.62) (name "VSS" (effects (font (size 1.27 1.27)))) (number "A4" (effects (font (size 1.27 1.27)))) )