Skip to content

Commit dcff769

Browse files
committed
update_readme.py UPDATE
1 parent 8698523 commit dcff769

1 file changed

Lines changed: 44 additions & 29 deletions

File tree

.github/scripts/update_readme.py

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
#!/usr/bin/env python3
22
# .github/scripts/update_readme.py
3-
# Debug/verbose version — 폴더/파일/매칭/entries 정보 전부 출력 & 로그파일 작성
3+
# Debug + Robust + Conflict-resolution version
4+
# - verbose logging (update_readme_debug.log)
5+
# - certifi verify for requests
6+
# - normalize unicode/spaces
7+
# - fetch from solved.ac & programmers
8+
# - parse existing README table
9+
# - detect files bj_/pg_ and prefer file-based platform (remove conflicting entry)
10+
# - preserve pre/post content and write README
411

512
import os, re, time, unicodedata, requests, sys
613
from bs4 import BeautifulSoup
@@ -81,7 +88,7 @@ def fetch_programmers_info(pid):
8188
log("[fetch_programmers_info] exception:", e)
8289
return {"title":"UNKNOWN","level":"Lv.?","link":url}
8390

84-
# find table block (same robust logic)
91+
# find table block (robust)
8592
def find_table_block(lines):
8693
header_idx = None
8794
for i, line in enumerate(lines):
@@ -107,13 +114,24 @@ def find_table_block(lines):
107114
post = lines[rows_end:]
108115
return pre, header, rows, post
109116

117+
# parse a table row -> normalized platform, number, title, level, status
110118
def parse_row_line(line):
111119
cols = [c.strip() for c in line.strip().split("|")[1:-1]]
112120
status = cols[1] if len(cols) > 1 else "⬜"
113-
platform = cols[2] if len(cols) > 2 else ""
121+
raw_platform = cols[2] if len(cols) > 2 else ""
122+
raw_platform_l = raw_platform.lower()
123+
# normalize platform to exact tokens used internally
124+
if "백준" in raw_platform or "acmicpc" in raw_platform_l or "baek" in raw_platform_l:
125+
platform = "백준"
126+
elif "프로그래머스" in raw_platform or "programmers" in raw_platform_l or "pg" in raw_platform_l:
127+
platform = "프로그래머스"
128+
else:
129+
platform = raw_platform.strip() or "UNKNOWN"
130+
114131
number_cell = cols[3] if len(cols) > 3 else ""
115132
title_cell = cols[4] if len(cols) > 4 else ""
116133
level = cols[5] if len(cols) > 5 else ""
134+
117135
num = None; num_link = ""
118136
m = re.search(r"\[(\d+)\]\(([^)]+)\)", number_cell)
119137
if m:
@@ -122,15 +140,18 @@ def parse_row_line(line):
122140
m2 = re.search(r"(\d+)", number_cell)
123141
if m2:
124142
num = m2.group(1)
143+
125144
title = ""
126145
m = re.search(r"\[(.*?)\]\(([^)]+)\)", title_cell)
127146
if m:
128147
title = m.group(1)
129148
else:
130149
title = title_cell
150+
131151
return {"platform": platform, "number": num, "number_link": num_link, "title": title, "level": level, "status": status, "raw": line}
132152

133153
def platform_rank(p): return 0 if p.strip()=="백준" else 1
154+
134155
def level_rank(p, lvl):
135156
lvl = normalize_spaces(lvl or "")
136157
if p.strip()=="백준":
@@ -145,7 +166,7 @@ def level_rank(p, lvl):
145166
except: pass
146167
return 999
147168

148-
# core: process_directory with verbose logging
169+
# core: process_directory with verbose logging + conflict resolution
149170
def process_directory(dir_path):
150171
readme_path = os.path.join(dir_path, "README.md")
151172
log(f"[start] folder={dir_path} (readme_exists={os.path.isfile(readme_path)})")
@@ -199,28 +220,38 @@ def process_directory(dir_path):
199220
}
200221
log(f"[existing_entries] count={len(entries)}")
201222

202-
# incorporate matched files
223+
# incorporate matched files (file-based additions) and collect found sets
224+
found_bj = set()
225+
found_pg = set()
203226
for item in matched:
204227
fn = item["file"]; name,_ = os.path.splitext(fn)
205228
if item["bj"]:
206229
pid = re.search(r"bj_(\d+)", name).group(1)
207230
status = "❌" if "_FAIL" in name else "✅"
208231
key = ("백준", pid)
209-
if key in entries:
210-
entries[key]["status"] = status
211-
else:
212-
entries[key] = {"platform":"백준","number":pid,"number_link":"","title":"","level":"","status":status}
232+
entries[key] = {"platform":"백준","number":pid,"number_link":"","title":"","level":"","status":status}
233+
found_bj.add(pid)
213234
if item["pg"]:
214235
pid = re.search(r"pg_(\d+)", name).group(1)
215236
status = "❌" if "_FAIL" in name else "✅"
216237
key = ("프로그래머스", pid)
217-
if key in entries:
218-
entries[key]["status"] = status
219-
else:
220-
entries[key] = {"platform":"프로그래머스","number":pid,"number_link":"","title":"","level":"","status":status}
238+
entries[key] = {"platform":"프로그래머스","number":pid,"number_link":"","title":"","level":"","status":status}
239+
found_pg.add(pid)
221240

222241
log(f"[after_scan_entries] count={len(entries)} keys={list(entries.keys())}")
223242

243+
# --- CONFLICT RESOLUTION: prefer file-based platform
244+
# If both platforms exist for same number, remove the one without a corresponding file.
245+
# i.e., if pg file exists -> remove ('백준', num) entry; if bj file exists -> remove ('프로그래머스', num) entry
246+
for num in list(found_pg):
247+
if ("백준", num) in entries and ("프로그래머스", num) in entries and num in found_pg:
248+
log(f"[conflict] removing 백준 entry for {num} because pg file exists")
249+
entries.pop(("백준", num), None)
250+
for num in list(found_bj):
251+
if ("프로그래머스", num) in entries and ("백준", num) in entries and num in found_bj:
252+
log(f"[conflict] removing 프로그래머스 entry for {num} because bj file exists")
253+
entries.pop(("프로그래머스", num), None)
254+
224255
# if no entries and no existing readme -> nothing to do
225256
if not entries and not os.path.isfile(readme_path):
226257
log(f"[skip] no entries and no readme -> nothing to do for {dir_path}")
@@ -292,22 +323,6 @@ def process_directory(dir_path):
292323
log(f"[ERROR] writing README {readme_path}: {e}")
293324
return False
294325

295-
def platform_rank(p): return 0 if p.strip()=="백준" else 1
296-
297-
def level_rank(p, lvl):
298-
lvl = normalize_spaces(lvl or "")
299-
if p.strip()=="백준":
300-
return BOJ_LEVEL_RANK.get(lvl, 999)
301-
m = re.search(r"(?:Lv\.?|Level)?\s*\.?\s*(\d+)", lvl, re.IGNORECASE)
302-
if m:
303-
try: return int(m.group(1))
304-
except: pass
305-
m2 = re.search(r"(\d+)", lvl)
306-
if m2:
307-
try: return int(m2.group(1))
308-
except: pass
309-
return 999
310-
311326
def main():
312327
# clear log
313328
try:

0 commit comments

Comments
 (0)