|
22 | 22 |
|
23 | 23 | DEFAULT_RULES_REF = "main" |
24 | 24 | DEFAULT_RULE_DETAILS_REF = "v4" |
| 25 | +MIN_EXPECTED_SDK_ICON_COUNT = 50 |
25 | 26 |
|
26 | 27 | RELEVANT_RULE_TYPES = {0, 1, 2, 3, 4, 9} |
27 | 28 |
|
|
65 | 66 |
|
66 | 67 |
|
67 | 68 | def main() -> int: |
| 69 | + if "--self-test" in sys.argv[1:]: |
| 70 | + run_self_test() |
| 71 | + return 0 |
| 72 | + |
68 | 73 | rules_ref = parse_rules_ref(sys.argv[1:]) |
69 | 74 | rules_root = build_rules_bundle_root(rules_ref) |
70 | 75 | rule_db_url = f"{rules_root}/assets/lcrules/rules.db" |
@@ -106,6 +111,12 @@ def main() -> int: |
106 | 111 | for icon_name, svg in list(icon_svgs.items()): |
107 | 112 | if not svg: |
108 | 113 | icon_svgs[icon_name] = placeholder_svg |
| 114 | + |
| 115 | + if len(icon_svgs) < MIN_EXPECTED_SDK_ICON_COUNT: |
| 116 | + raise ValueError( |
| 117 | + f"parsed only {len(icon_svgs)} SDK icons from IconResMap; " |
| 118 | + "update parse_icon_res_map for the upstream format" |
| 119 | + ) |
109 | 120 | except Exception as exc: |
110 | 121 | print(f"Failed to sync rules bundle from GitHub: {exc}", file=sys.stderr) |
111 | 122 | return 1 |
@@ -188,14 +199,62 @@ def parse_icon_res_map(text: str) -> tuple[dict[int, str], set[int]]: |
188 | 199 | index = int(match.group(1)) |
189 | 200 | icon_map[index] = match.group(2) |
190 | 201 |
|
191 | | - set_match = re.search(r"SINGLE_COLOR_ICON_SET = setOf\((.*?)\)", text, flags=re.S) |
| 202 | + array_match = re.search(r"iconResIds\s*=\s*intArrayOf\((.*?)\)", text, flags=re.S) |
| 203 | + if array_match: |
| 204 | + array_body = array_match.group(1) |
| 205 | + indexed_matches = list(re.finditer(r"/\*\s*(-?\d+)\s*\*/\s*R\.drawable\.(\w+)", array_body)) |
| 206 | + if indexed_matches: |
| 207 | + for match in indexed_matches: |
| 208 | + icon_map[int(match.group(1))] = match.group(2) |
| 209 | + else: |
| 210 | + for index, icon_name in enumerate(re.findall(r"R\.drawable\.(\w+)", array_body)): |
| 211 | + icon_map[index] = icon_name |
| 212 | + |
| 213 | + set_match = re.search( |
| 214 | + r"(?:SINGLE_COLOR_ICON_SET|singleColorIconIndexes)\s*=\s*setOf\((.*?)\)", |
| 215 | + text, |
| 216 | + flags=re.S, |
| 217 | + ) |
192 | 218 | if set_match: |
193 | | - for number in re.findall(r"-?\d+", set_match.group(1)): |
| 219 | + set_body = set_match.group(1).replace("PLACEHOLDER_INDEX", "-1") |
| 220 | + for number in re.findall(r"-?\d+", set_body): |
194 | 221 | single_color.add(int(number)) |
195 | 222 |
|
196 | 223 | return icon_map, single_color |
197 | 224 |
|
198 | 225 |
|
| 226 | +def run_self_test() -> None: |
| 227 | + old_format = """ |
| 228 | + object IconResMap { |
| 229 | + val SINGLE_COLOR_ICON_SET = setOf(-1, 2) |
| 230 | + init { |
| 231 | + put(-1, R.drawable.ic_sdk_placeholder) |
| 232 | + put(2, R.drawable.ic_lib_old) |
| 233 | + } |
| 234 | + } |
| 235 | + """ |
| 236 | + old_map, old_single_color = parse_icon_res_map(old_format) |
| 237 | + assert old_map == {-1: "ic_sdk_placeholder", 2: "ic_lib_old"} |
| 238 | + assert old_single_color == {-1, 2} |
| 239 | + |
| 240 | + new_format = """ |
| 241 | + object IconResMap { |
| 242 | + private const val PLACEHOLDER_INDEX = -1 |
| 243 | + private val iconResIds = intArrayOf( |
| 244 | + /* 0 */ R.drawable.ic_lib_zero, |
| 245 | + /* 1 */ R.drawable.ic_lib_one, |
| 246 | + ) |
| 247 | + private val singleColorIconIndexes = setOf( |
| 248 | + PLACEHOLDER_INDEX, 1, |
| 249 | + ) |
| 250 | + } |
| 251 | + """ |
| 252 | + new_map, new_single_color = parse_icon_res_map(new_format) |
| 253 | + assert new_map == {0: "ic_lib_zero", 1: "ic_lib_one"} |
| 254 | + assert new_single_color == {-1, 1} |
| 255 | + print("generate_libchecker_bundle self-test passed") |
| 256 | + |
| 257 | + |
199 | 258 | def load_rules( |
200 | 259 | db_path: Path, |
201 | 260 | icon_index_map: dict[int, str], |
|
0 commit comments