Skip to content

Commit 16c164c

Browse files
authored
Use common tagging strategy for boards and packages (#348)
* Use common tagging strategy for boards and packages * Canonicalize json for snapshots * Fix clippy lints
1 parent f9640e9 commit 16c164c

31 files changed

+4071
-3954
lines changed

crates/pcb-layout/src/scripts/update_layout_file.py

Lines changed: 49 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,24 @@ def convert(part):
7171
return [convert(c) for c in re.split("([0-9]+)", text)]
7272

7373

74+
def canonicalize_json(obj: Any) -> Any:
75+
"""
76+
Recursively canonicalize a JSON-serializable object for deterministic output.
77+
78+
- Dicts are converted to sorted dicts (by key)
79+
- Lists are sorted by their JSON string representation
80+
- Primitives are returned as-is
81+
"""
82+
if isinstance(obj, dict):
83+
return {k: canonicalize_json(v) for k, v in sorted(obj.items())}
84+
elif isinstance(obj, list):
85+
canonicalized = [canonicalize_json(item) for item in obj]
86+
# Sort by JSON representation for stable ordering
87+
return sorted(canonicalized, key=lambda x: json.dumps(x, sort_keys=True))
88+
else:
89+
return obj
90+
91+
7492
# Read PYTHONPATH environment variable and add all folders to the search path
7593
python_path = os.environ.get("PYTHONPATH", "")
7694
path_separator = (
@@ -3327,36 +3345,33 @@ def _get_footprint_data(self, fp: pcbnew.FOOTPRINT) -> dict:
33273345
}
33283346
for pad in fp.Pads()
33293347
],
3330-
"graphical_items": sorted(
3331-
[
3332-
{
3333-
"type": item.GetClass(),
3334-
"layer": item.GetLayerName(),
3335-
"position": {
3336-
"x": item.GetPosition().x,
3337-
"y": item.GetPosition().y,
3338-
},
3339-
"start": (
3340-
{"x": item.GetStart().x, "y": item.GetStart().y}
3341-
if hasattr(item, "GetStart")
3342-
else None
3343-
),
3344-
"end": (
3345-
{"x": item.GetEnd().x, "y": item.GetEnd().y}
3346-
if hasattr(item, "GetEnd")
3347-
else None
3348-
),
3349-
"angle": (
3350-
item.GetAngle() if hasattr(item, "GetAngle") else None
3351-
),
3352-
"text": item.GetText() if hasattr(item, "GetText") else None,
3353-
"shape": item.GetShape() if hasattr(item, "GetShape") else None,
3354-
"width": item.GetWidth() if hasattr(item, "GetWidth") else None,
3355-
}
3356-
for item in fp.GraphicalItems()
3357-
],
3358-
key=lambda g: (g["position"]["x"], g["position"]["y"]),
3359-
),
3348+
"graphical_items": [
3349+
{
3350+
"type": item.GetClass(),
3351+
"layer": item.GetLayerName(),
3352+
"position": {
3353+
"x": item.GetPosition().x,
3354+
"y": item.GetPosition().y,
3355+
},
3356+
"start": (
3357+
{"x": item.GetStart().x, "y": item.GetStart().y}
3358+
if hasattr(item, "GetStart")
3359+
else None
3360+
),
3361+
"end": (
3362+
{"x": item.GetEnd().x, "y": item.GetEnd().y}
3363+
if hasattr(item, "GetEnd")
3364+
else None
3365+
),
3366+
"angle": (
3367+
item.GetAngle() if hasattr(item, "GetAngle") else None
3368+
),
3369+
"text": item.GetText() if hasattr(item, "GetText") else None,
3370+
"shape": item.GetShape() if hasattr(item, "GetShape") else None,
3371+
"width": item.GetWidth() if hasattr(item, "GetWidth") else None,
3372+
}
3373+
for item in fp.GraphicalItems()
3374+
],
33603375
}
33613376

33623377
def _get_group_data(self, group: pcbnew.PCB_GROUP) -> dict:
@@ -3499,37 +3514,16 @@ def _export_layout_snapshot(self):
34993514
self.board.Groups(), key=lambda g: g.GetName() or ""
35003515
)
35013516
],
3502-
"zones": [
3503-
self._get_zone_data(zone)
3504-
for zone in sorted(
3505-
self.board.Zones(), key=lambda z: z.GetZoneName() or ""
3506-
)
3507-
],
3508-
"tracks": [
3509-
self._get_track_data(track)
3510-
for track in sorted(
3511-
tracks, key=lambda t: (t.GetNetname() or "", t.GetLayerName() or "")
3512-
)
3513-
],
3514-
"vias": [
3515-
self._get_via_data(via)
3516-
for via in sorted(
3517-
vias,
3518-
key=lambda v: (
3519-
v.GetNetname() or "",
3520-
v.GetPosition().x,
3521-
v.GetPosition().y,
3522-
),
3523-
)
3524-
],
3517+
"zones": [self._get_zone_data(zone) for zone in self.board.Zones()],
3518+
"tracks": [self._get_track_data(track) for track in tracks],
3519+
"vias": [self._get_via_data(via) for via in vias],
35253520
}
35263521

35273522
with self.snapshot_path.open("w", encoding="utf-8") as f:
35283523
json.dump(
3529-
snapshot,
3524+
canonicalize_json(snapshot),
35303525
f,
35313526
indent=2,
3532-
sort_keys=True, # Ensure all dictionaries are sorted by key
35333527
ensure_ascii=False,
35343528
)
35353529

0 commit comments

Comments
 (0)