Updated
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
@dataclass
|
||||
class PdkAsset:
|
||||
component: str
|
||||
yaml_path: Optional[str] = None
|
||||
gds_path: Optional[str] = None
|
||||
metadata: Optional[dict] = None
|
||||
|
||||
|
||||
class PdkRegistry:
|
||||
"""Resolve public PDK component names to metadata and public GDS assets."""
|
||||
|
||||
def __init__(self, public_root: str):
|
||||
self.public_root = os.path.abspath(public_root)
|
||||
self._asset_cache = {}
|
||||
|
||||
def resolve(self, component: str) -> PdkAsset:
|
||||
key = (component or "").strip().replace("\\", "/").strip("/")
|
||||
if not key:
|
||||
return PdkAsset(component=component)
|
||||
if key in self._asset_cache:
|
||||
return self._asset_cache[key]
|
||||
|
||||
yaml_path = self._find_yaml(key)
|
||||
gds_path = self._find_gds(key, yaml_path)
|
||||
metadata = self._load_yaml(yaml_path) if yaml_path else None
|
||||
asset = PdkAsset(component=component, yaml_path=yaml_path, gds_path=gds_path, metadata=metadata)
|
||||
self._asset_cache[key] = asset
|
||||
return asset
|
||||
|
||||
def _find_yaml(self, key: str) -> Optional[str]:
|
||||
direct = os.path.join(self.public_root, *key.split("/"))
|
||||
candidates = []
|
||||
if direct.lower().endswith((".yml", ".yaml")):
|
||||
candidates.append(direct)
|
||||
else:
|
||||
name = key.split("/")[-1]
|
||||
candidates.append(os.path.join(direct, f"{name}.yml"))
|
||||
candidates.append(os.path.join(direct, f"{name}.yaml"))
|
||||
|
||||
for candidate in candidates:
|
||||
if self._inside_root(candidate) and os.path.exists(candidate):
|
||||
return os.path.abspath(candidate)
|
||||
|
||||
name = key.split("/")[-1]
|
||||
for root, dirs, files in os.walk(self.public_root):
|
||||
if os.path.basename(root) == name:
|
||||
for filename in files:
|
||||
if filename.lower().endswith((".yml", ".yaml")):
|
||||
return os.path.join(root, filename)
|
||||
dirs.clear()
|
||||
return None
|
||||
|
||||
def _find_gds(self, key: str, yaml_path: Optional[str]) -> Optional[str]:
|
||||
search_dir = os.path.dirname(yaml_path) if yaml_path else os.path.join(self.public_root, *key.split("/"))
|
||||
name = key.split("/")[-1]
|
||||
candidates = [
|
||||
os.path.join(search_dir, f"{name}_BB.gds"),
|
||||
os.path.join(search_dir, f"{name}.gds"),
|
||||
]
|
||||
for candidate in candidates:
|
||||
if self._inside_root(candidate) and os.path.exists(candidate):
|
||||
return os.path.abspath(candidate)
|
||||
if os.path.isdir(search_dir):
|
||||
for filename in sorted(os.listdir(search_dir)):
|
||||
if filename.lower().endswith("_bb.gds"):
|
||||
return os.path.join(search_dir, filename)
|
||||
for filename in sorted(os.listdir(search_dir)):
|
||||
if filename.lower().endswith(".gds"):
|
||||
return os.path.join(search_dir, filename)
|
||||
return None
|
||||
|
||||
def _load_yaml(self, yaml_path: Optional[str]) -> Optional[dict]:
|
||||
if not yaml_path:
|
||||
return None
|
||||
with open(yaml_path, "r", encoding="utf-8") as file:
|
||||
return yaml.safe_load(file) or {}
|
||||
|
||||
def _inside_root(self, path: str) -> bool:
|
||||
target = os.path.abspath(path)
|
||||
return target == self.public_root or target.startswith(self.public_root + os.sep)
|
||||
Reference in New Issue
Block a user