Files
nx_post_support/server/src/tools/file_sourcing.py
T

89 lines
2.8 KiB
Python

import xml.etree.ElementTree as ET
import os
from dataclasses import dataclass, field
from typing import List, Optional
from pathlib import Path
@dataclass
class SourcedFile:
layer_name: str
subfolder: Optional[str]
files: List[str]
defined_events: List[str] = field(default_factory=list)
def read_psc_file(psc_file: Path) -> List[SourcedFile]:
tree = ET.parse(psc_file)
root = tree.getroot()
# PSC exports may use a default XML namespace.
for element in root.iter():
element.tag = element.tag.rsplit("}", 1)[-1]
layers = root.findall(".//Layer")
layer_info_list: List[SourcedFile] = []
for layer in layers:
layer_name = layer.attrib.get("Name")
subfolder = layer.attrib.get("SubFolder")
# Scripts-Filenames
scripts = layer.find("Scripts")
script_names = []
if scripts is not None:
for filename in scripts.findall("Filename"):
name = filename.attrib.get("Name")
if name:
script_names.append(name)
# DefinedEvents-Filenames (.def files)
defined_events = layer.find("DefinedEvents")
event_names = []
if defined_events is not None:
for filename in defined_events.findall("Filename"):
name = filename.attrib.get("Name")
if name:
event_names.append(name)
layer_info_list.append(
SourcedFile(
layer_name=layer_name,
subfolder=subfolder,
files=script_names,
defined_events=event_names,
)
)
return layer_info_list
def get_all_psc_files(root_path: Path) -> list[Path]:
return sorted(root_path.rglob("*.psc"), key=lambda path: str(path).casefold())
def _expanded(value) -> Path:
return Path(os.path.expandvars(value).replace("\\", "/"))
def _layer_files(psc_file: Path, attribute: str, suffix: str) -> list[Path]:
paths = []
for layer in read_psc_file(psc_file):
folder = layer.subfolder or "."
base = psc_file.parent / _expanded(os.environ.get(folder, folder))
for name in getattr(layer, attribute):
filename = _expanded(name)
if not filename.suffix:
filename = filename.with_suffix(suffix)
path = (base / filename).resolve()
if path.suffix.lower() == suffix:
paths.append(path)
return paths
def psc_script_files(psc_file: Path) -> list[Path]:
"""Resolve layer script paths relative to the PSC, preserving load order."""
return _layer_files(psc_file, "files", ".tcl")
def psc_defined_event_files(psc_file: Path) -> list[Path]:
"""Resolve the layers' DefinedEvents (.def) paths relative to the PSC."""
return _layer_files(psc_file, "defined_events", ".def")