Coverage for klayout_pex/klayout/repair_rdb.py: 16%
79 statements
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-17 17:24 +0000
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-17 17:24 +0000
1#
2# --------------------------------------------------------------------------------
3# SPDX-FileCopyrightText: 2024 Martin Jan Köhler and Harald Pretl
4# Johannes Kepler University, Institute for Integrated Circuits.
5#
6# This file is part of KPEX
7# (see https://github.com/martinjankoehler/klayout-pex).
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <http://www.gnu.org/licenses/>.
21# SPDX-License-Identifier: GPL-3.0-or-later
22# --------------------------------------------------------------------------------
23#
24import gzip
25import io
26import os.path
27import shutil
28import sys
29from typing import *
30import xml.etree.ElementTree as ET
32import klayout.rdb as rdb
33from ..log import (
34 LogLevel,
35 set_log_level,
36 register_additional_handler,
37 deregister_additional_handler,
38 # console,
39 # debug,
40 info,
41 warning,
42 subproc,
43 error,
44 rule
45)
48def parse_category_path(category_path: str) -> List[str]:
49 within_escaped = False
50 within_backslash = False
51 current_word = ''
52 path_list = []
53 for c in category_path:
54 match c:
55 case '.':
56 if within_backslash:
57 current_word += c
58 within_backslash = False
59 elif within_escaped:
60 current_word += c
61 else:
62 path_list.append(current_word)
63 current_word = ''
64 case '\\':
65 if within_backslash:
66 current_word += c
67 within_backslash = False
68 else:
69 within_backslash = True
70 case '\'':
71 if within_backslash:
72 current_word += c
73 within_backslash = False
74 else:
75 within_escaped = not within_escaped
76 case _:
77 current_word += c
78 if len(current_word) >= 1:
79 path_list.append(current_word)
80 return path_list
82def repair_rdb_xml(xml_file: io.IOBase, new_xml_path: str):
83 et = ET.parse(xml_file)
84 root = et.getroot()
86 categories: Set[str] = set(
87 [e.text for e in root.findall('./items/item/category')]
88 )
89 category_paths = [parse_category_path(c) for c in categories]
90 category_paths.sort()
91 # print(category_paths)
92 for p in category_paths:
93 elem = root
94 for c in p:
95 elemcats = elem.find("./categories")
96 subelem = elemcats.find("./category/name[.='{0}']/..".format(c))
97 if subelem is None:
98 warning(f"In category path {p}, can't find element for component {c}")
99 new_category = ET.SubElement(elemcats, "category")
100 new_cname = ET.SubElement(new_category, "name")
101 new_cname.text = c
102 ET.SubElement(new_category, 'description')
103 ET.SubElement(new_category, 'categories')
104 elem = new_category
105 else:
106 elem = subelem
108 et.write(new_xml_path)
111def repair_rdb(rdb_path: str):
112 rdb_file: io.IOBase
113 suffix = os.path.splitext(rdb_path)[-1]
114 new_xml_path = rdb_path + '.repair.xml'
116 if suffix == '.gz':
117 with gzip.open(rdb_path, 'r') as f:
118 repair_rdb_xml(f, new_xml_path)
119 else:
120 with open(rdb_path, 'r') as f:
121 repair_rdb_xml(f, new_xml_path)
123 report = rdb.ReportDatabase('')
124 try:
125 report.load(new_xml_path)
126 info(f"Succeeded in repairing broken marker database {rdb_path} under {new_xml_path}")
128 except Exception as e:
129 error(f"Failed to repair broken marker database {rdb_path} due to exception: {e}")
132if __name__ == "__main__":
133 if len(sys.argv) < 2:
134 print(f"Usage: {sys.argv[0]} file.rdb.gz")
135 sys.exit(1)
137 repair_rdb(sys.argv[1])