diff --git "a/data/1.gml\345\210\235\351\230\266/1.Git\345\205\245\351\227\250/1.Git\347\256\200\344\273\213/config.json" "b/data/1.gml\345\210\235\351\230\266/1.Git\345\205\245\351\227\250/1.Git\347\256\200\344\273\213/config.json" new file mode 100644 index 0000000000000000000000000000000000000000..294b736dad9057e58df2d224365c21721df9119d --- /dev/null +++ "b/data/1.gml\345\210\235\351\230\266/1.Git\345\205\245\351\227\250/1.Git\347\256\200\344\273\213/config.json" @@ -0,0 +1,6 @@ +{ + "node_id": "gml-62c30f9c31f64a1d96af732c47c93f04", + "keywords": [], + "children": [], + "export": [] +} \ No newline at end of file diff --git "a/data/1.gml\345\210\235\351\230\266/1.Git\345\205\245\351\227\250/2.Git\345\256\211\350\243\205/config.json" "b/data/1.gml\345\210\235\351\230\266/1.Git\345\205\245\351\227\250/2.Git\345\256\211\350\243\205/config.json" new file mode 100644 index 0000000000000000000000000000000000000000..0fc69c4b905f156579ed2e8a8cc09dd3becbf442 --- /dev/null +++ "b/data/1.gml\345\210\235\351\230\266/1.Git\345\205\245\351\227\250/2.Git\345\256\211\350\243\205/config.json" @@ -0,0 +1,6 @@ +{ + "node_id": "gml-17121b66f9a942629bc455f320b28910", + "keywords": [], + "children": [], + "export": [] +} \ No newline at end of file diff --git "a/data/1.gml\345\210\235\351\230\266/1.Git\345\205\245\351\227\250/3.Git\344\275\277\347\224\250/config.json" "b/data/1.gml\345\210\235\351\230\266/1.Git\345\205\245\351\227\250/3.Git\344\275\277\347\224\250/config.json" new file mode 100644 index 0000000000000000000000000000000000000000..cf21bd10389ea68b6ac5b42e92c248e49bb6dc77 --- /dev/null +++ "b/data/1.gml\345\210\235\351\230\266/1.Git\345\205\245\351\227\250/3.Git\344\275\277\347\224\250/config.json" @@ -0,0 +1,6 @@ +{ + "node_id": "gml-598d225d1a78453d8992345f8f7902ba", + "keywords": [], + "children": [], + "export": [] +} \ No newline at end of file diff --git "a/data/1.gml\345\210\235\351\230\266/1.Git\345\205\245\351\227\250/4.\347\211\210\346\234\254\347\256\241\347\220\206/config.json" "b/data/1.gml\345\210\235\351\230\266/1.Git\345\205\245\351\227\250/4.\347\211\210\346\234\254\347\256\241\347\220\206/config.json" new file mode 100644 index 0000000000000000000000000000000000000000..7d97b0f67941f783e322c11bce9f9bbe91ccf847 --- /dev/null +++ "b/data/1.gml\345\210\235\351\230\266/1.Git\345\205\245\351\227\250/4.\347\211\210\346\234\254\347\256\241\347\220\206/config.json" @@ -0,0 +1,6 @@ +{ + "node_id": "gml-f0d68868583b48d0851c7add33e2f8ff", + "keywords": [], + "children": [], + "export": [] +} \ No newline at end of file diff --git "a/data/1.gml\345\210\235\351\230\266/1.Git\345\205\245\351\227\250/5.\345\210\206\346\224\257\347\256\241\347\220\206/config.json" "b/data/1.gml\345\210\235\351\230\266/1.Git\345\205\245\351\227\250/5.\345\210\206\346\224\257\347\256\241\347\220\206/config.json" new file mode 100644 index 0000000000000000000000000000000000000000..0babf8af3af3c878cd58b652204acd537a795008 --- /dev/null +++ "b/data/1.gml\345\210\235\351\230\266/1.Git\345\205\245\351\227\250/5.\345\210\206\346\224\257\347\256\241\347\220\206/config.json" @@ -0,0 +1,6 @@ +{ + "node_id": "gml-5b37ae204b1f4183b1a2853f32698407", + "keywords": [], + "children": [], + "export": [] +} \ No newline at end of file diff --git "a/data/1.gml\345\210\235\351\230\266/1.Git\345\205\245\351\227\250/6.Git\346\240\207\347\255\276/config.json" "b/data/1.gml\345\210\235\351\230\266/1.Git\345\205\245\351\227\250/6.Git\346\240\207\347\255\276/config.json" new file mode 100644 index 0000000000000000000000000000000000000000..09beccba18fcadad6693c5576c0a4bc91fa3aa3a --- /dev/null +++ "b/data/1.gml\345\210\235\351\230\266/1.Git\345\205\245\351\227\250/6.Git\346\240\207\347\255\276/config.json" @@ -0,0 +1,6 @@ +{ + "node_id": "gml-7b2351b6989f4ec19655498bbb4bafb1", + "keywords": [], + "children": [], + "export": [] +} \ No newline at end of file diff --git "a/data/1.gml\345\210\235\351\230\266/1.Git\345\205\245\351\227\250/config.json" "b/data/1.gml\345\210\235\351\230\266/1.Git\345\205\245\351\227\250/config.json" new file mode 100644 index 0000000000000000000000000000000000000000..6c4f26403e91c6558bac17062633530d9b29c44e --- /dev/null +++ "b/data/1.gml\345\210\235\351\230\266/1.Git\345\205\245\351\227\250/config.json" @@ -0,0 +1,4 @@ +{ + "node_id": "gml-426d7dad0f844c6d9bc1d6c4c860585c", + "keywords": [] +} \ No newline at end of file diff --git "a/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/1.MarkDown\344\273\213\347\273\215/config.json" "b/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/1.MarkDown\344\273\213\347\273\215/config.json" new file mode 100644 index 0000000000000000000000000000000000000000..dc01f751bde8a90743807059fe0638a861c46a89 --- /dev/null +++ "b/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/1.MarkDown\344\273\213\347\273\215/config.json" @@ -0,0 +1,6 @@ +{ + "node_id": "gml-e67e64c1c880432ab6bc1b0452124ec0", + "keywords": [], + "children": [], + "export": [] +} \ No newline at end of file diff --git "a/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/2.\346\256\265\350\220\275\345\217\212\345\274\272\350\260\203/config.json" "b/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/2.\346\256\265\350\220\275\345\217\212\345\274\272\350\260\203/config.json" new file mode 100644 index 0000000000000000000000000000000000000000..99e7b7213023be580985ea58c9d9a29e1cc95304 --- /dev/null +++ "b/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/2.\346\256\265\350\220\275\345\217\212\345\274\272\350\260\203/config.json" @@ -0,0 +1,6 @@ +{ + "node_id": "gml-627f564073834c8d86e45f126ac628df", + "keywords": [], + "children": [], + "export": [] +} \ No newline at end of file diff --git "a/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/3.\346\240\207\351\242\230/config.json" "b/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/3.\346\240\207\351\242\230/config.json" new file mode 100644 index 0000000000000000000000000000000000000000..bf43f50c304d38a38eb6d6c821205e64cf880c7c --- /dev/null +++ "b/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/3.\346\240\207\351\242\230/config.json" @@ -0,0 +1,6 @@ +{ + "node_id": "gml-30e9989f9a5f44fab349734a8e4479a3", + "keywords": [], + "children": [], + "export": [] +} \ No newline at end of file diff --git "a/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/4.\351\223\276\346\216\245/config.json" "b/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/4.\351\223\276\346\216\245/config.json" new file mode 100644 index 0000000000000000000000000000000000000000..4570191eb82648b8273a90f60ea3e44b8cad1bf4 --- /dev/null +++ "b/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/4.\351\223\276\346\216\245/config.json" @@ -0,0 +1,6 @@ +{ + "node_id": "gml-3cb459e3d1a147a8b89291c1ef4147c7", + "keywords": [], + "children": [], + "export": [] +} \ No newline at end of file diff --git "a/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/5.\345\233\276\347\211\207/config.json" "b/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/5.\345\233\276\347\211\207/config.json" new file mode 100644 index 0000000000000000000000000000000000000000..bf5d39eec7673e499d82d03aa78fe6376862e928 --- /dev/null +++ "b/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/5.\345\233\276\347\211\207/config.json" @@ -0,0 +1,6 @@ +{ + "node_id": "gml-2f1e2810b721429dba664414438b6d87", + "keywords": [], + "children": [], + "export": [] +} \ No newline at end of file diff --git "a/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/6.\345\210\227\350\241\250/config.json" "b/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/6.\345\210\227\350\241\250/config.json" new file mode 100644 index 0000000000000000000000000000000000000000..288ef70cd6218297bbfe062ce5cf11cc283b5573 --- /dev/null +++ "b/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/6.\345\210\227\350\241\250/config.json" @@ -0,0 +1,6 @@ +{ + "node_id": "gml-b4a4f06aa5114c3fa6a590d659037370", + "keywords": [], + "children": [], + "export": [] +} \ No newline at end of file diff --git "a/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/7.\345\210\206\351\232\224\347\272\277\345\217\212\345\274\225\347\224\250/config.json" "b/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/7.\345\210\206\351\232\224\347\272\277\345\217\212\345\274\225\347\224\250/config.json" new file mode 100644 index 0000000000000000000000000000000000000000..af4ddfb68d28ec74f1a260bba8ae9a8d9b498c68 --- /dev/null +++ "b/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/7.\345\210\206\351\232\224\347\272\277\345\217\212\345\274\225\347\224\250/config.json" @@ -0,0 +1,6 @@ +{ + "node_id": "gml-b6b6f01fb86141768c5b242327f1e0fa", + "keywords": [], + "children": [], + "export": [] +} \ No newline at end of file diff --git "a/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/8.\344\273\243\347\240\201\345\235\227/config.json" "b/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/8.\344\273\243\347\240\201\345\235\227/config.json" new file mode 100644 index 0000000000000000000000000000000000000000..e7db5538d342f1195c89cd8daa991daf4dcf2b62 --- /dev/null +++ "b/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/8.\344\273\243\347\240\201\345\235\227/config.json" @@ -0,0 +1,6 @@ +{ + "node_id": "gml-2e87affacacd4078a3ba55a5a15a8f7a", + "keywords": [], + "children": [], + "export": [] +} \ No newline at end of file diff --git "a/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/9.\350\241\250\346\240\274/config.json" "b/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/9.\350\241\250\346\240\274/config.json" new file mode 100644 index 0000000000000000000000000000000000000000..5e46ffd1d6cb8855a27ccd5b9222822b7e31d283 --- /dev/null +++ "b/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/9.\350\241\250\346\240\274/config.json" @@ -0,0 +1,6 @@ +{ + "node_id": "gml-11620ba793c74faa9a5117ca07d748d6", + "keywords": [], + "children": [], + "export": [] +} \ No newline at end of file diff --git "a/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/config.json" "b/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/config.json" new file mode 100644 index 0000000000000000000000000000000000000000..7b8d40d8084148f56cb3fac13c5e48c9d476e74b --- /dev/null +++ "b/data/1.gml\345\210\235\351\230\266/2.MarkDown\345\205\245\351\227\250/config.json" @@ -0,0 +1,4 @@ +{ + "node_id": "gml-e5b1eb56008b451699a9e7e6d941c8ca", + "keywords": [] +} \ No newline at end of file diff --git "a/data/1.gml\345\210\235\351\230\266/config.json" "b/data/1.gml\345\210\235\351\230\266/config.json" new file mode 100644 index 0000000000000000000000000000000000000000..b05d3fd39b8c7553c8034225839b0688b1c368d1 --- /dev/null +++ "b/data/1.gml\345\210\235\351\230\266/config.json" @@ -0,0 +1,4 @@ +{ + "node_id": "gml-3acda6f103e94664800f91494aff4099", + "keywords": [] +} \ No newline at end of file diff --git "a/data/2.gml\344\270\255\351\230\266/config.json" "b/data/2.gml\344\270\255\351\230\266/config.json" new file mode 100644 index 0000000000000000000000000000000000000000..a4e896712ff90017776fa1da4b033fcfb17ba131 --- /dev/null +++ "b/data/2.gml\344\270\255\351\230\266/config.json" @@ -0,0 +1,4 @@ +{ + "node_id": "gml-a94f8931a29e42749c65af33b5f00ffa", + "keywords": [] +} \ No newline at end of file diff --git "a/data/3.gml\351\253\230\351\230\266/config.json" "b/data/3.gml\351\253\230\351\230\266/config.json" new file mode 100644 index 0000000000000000000000000000000000000000..6cc25fca75326ee1192e3d98a5eae54235741be9 --- /dev/null +++ "b/data/3.gml\351\253\230\351\230\266/config.json" @@ -0,0 +1,4 @@ +{ + "node_id": "gml-ec7eb3a512204261a14eafc36bc55188", + "keywords": [] +} \ No newline at end of file diff --git a/data/config.json b/data/config.json new file mode 100644 index 0000000000000000000000000000000000000000..7dfbabe72afb28e6fd03d003ad9e79c637dbefe6 --- /dev/null +++ b/data/config.json @@ -0,0 +1,5 @@ +{ + "tree_name": "gml", + "keywords": [], + "node_id": "gml-2edf9242568f4812bda2dd5913c09bd3" +} \ No newline at end of file diff --git a/data/tree.json b/data/tree.json new file mode 100644 index 0000000000000000000000000000000000000000..cf1248d0b7524e9d58785a09815845ddb9caaf67 --- /dev/null +++ b/data/tree.json @@ -0,0 +1,151 @@ +{ + "gml": { + "node_id": "gml-2edf9242568f4812bda2dd5913c09bd3", + "keywords": [], + "children": [ + { + "gml初阶": { + "node_id": "gml-3acda6f103e94664800f91494aff4099", + "keywords": [], + "children": [ + { + "Git入门": { + "node_id": "gml-426d7dad0f844c6d9bc1d6c4c860585c", + "keywords": [], + "children": [ + { + "Git简介": { + "node_id": "gml-62c30f9c31f64a1d96af732c47c93f04", + "keywords": [], + "children": [] + } + }, + { + "Git安装": { + "node_id": "gml-17121b66f9a942629bc455f320b28910", + "keywords": [], + "children": [] + } + }, + { + "Git使用": { + "node_id": "gml-598d225d1a78453d8992345f8f7902ba", + "keywords": [], + "children": [] + } + }, + { + "版本管理": { + "node_id": "gml-f0d68868583b48d0851c7add33e2f8ff", + "keywords": [], + "children": [] + } + }, + { + "分支管理": { + "node_id": "gml-5b37ae204b1f4183b1a2853f32698407", + "keywords": [], + "children": [] + } + }, + { + "Git标签": { + "node_id": "gml-7b2351b6989f4ec19655498bbb4bafb1", + "keywords": [], + "children": [] + } + } + ] + } + }, + { + "MarkDown入门": { + "node_id": "gml-e5b1eb56008b451699a9e7e6d941c8ca", + "keywords": [], + "children": [ + { + "MarkDown介绍": { + "node_id": "gml-e67e64c1c880432ab6bc1b0452124ec0", + "keywords": [], + "children": [] + } + }, + { + "段落及强调": { + "node_id": "gml-627f564073834c8d86e45f126ac628df", + "keywords": [], + "children": [] + } + }, + { + "标题": { + "node_id": "gml-30e9989f9a5f44fab349734a8e4479a3", + "keywords": [], + "children": [] + } + }, + { + "链接": { + "node_id": "gml-3cb459e3d1a147a8b89291c1ef4147c7", + "keywords": [], + "children": [] + } + }, + { + "图片": { + "node_id": "gml-2f1e2810b721429dba664414438b6d87", + "keywords": [], + "children": [] + } + }, + { + "列表": { + "node_id": "gml-b4a4f06aa5114c3fa6a590d659037370", + "keywords": [], + "children": [] + } + }, + { + "分隔线及引用": { + "node_id": "gml-b6b6f01fb86141768c5b242327f1e0fa", + "keywords": [], + "children": [] + } + }, + { + "代码块": { + "node_id": "gml-2e87affacacd4078a3ba55a5a15a8f7a", + "keywords": [], + "children": [] + } + }, + { + "表格": { + "node_id": "gml-11620ba793c74faa9a5117ca07d748d6", + "keywords": [], + "children": [] + } + } + ] + } + } + ] + } + }, + { + "gml中阶": { + "node_id": "gml-a94f8931a29e42749c65af33b5f00ffa", + "keywords": [], + "children": [] + } + }, + { + "gml高阶": { + "node_id": "gml-ec7eb3a512204261a14eafc36bc55188", + "keywords": [], + "children": [] + } + } + ] + } +} \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000000000000000000000000000000000000..d9c6c020a3da13787cbfe8c73f8d09790bea0871 --- /dev/null +++ b/main.py @@ -0,0 +1,5 @@ +from src.tree import TreeWalker + +if __name__ == '__main__': + walker = TreeWalker("data", "gml", "Git,MarkDown,Linux 入门") + walker.walk() diff --git a/src/__pycache__/tree.cpython-38.pyc b/src/__pycache__/tree.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f769f2142b67da7ac1a425a8aa8400139b37cf3e Binary files /dev/null and b/src/__pycache__/tree.cpython-38.pyc differ diff --git a/src/tree.py b/src/tree.py new file mode 100644 index 0000000000000000000000000000000000000000..f6fb31a332e770902c7a5a590cdad446edf9e960 --- /dev/null +++ b/src/tree.py @@ -0,0 +1,310 @@ +import json +import logging +import os +import re +import sys +import uuid + +id_set = set() +logger = logging.getLogger(__name__) +logger.setLevel(logging.INFO) +handler = logging.StreamHandler(sys.stdout) +formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') +handler.setFormatter(formatter) +logger.addHandler(handler) + + +def load_json(p): + with open(p, 'r') as f: + return json.loads(f.read()) + + +def dump_json(p, j, exist_ok=False, override=False): + if os.path.exists(p): + if exist_ok: + if not override: + return + else: + logger.error(f"{p} already exist") + sys.exit(0) + + with open(p, 'w+', encoding="utf8") as f: + f.write(json.dumps(j, indent=2, ensure_ascii=False)) + + +def ensure_config(path): + config_path = os.path.join(path, "config.json") + if not os.path.exists(config_path): + node = {"keywords": []} + dump_json(config_path, node, exist_ok=True, override=False) + return node + else: + return load_json(config_path) + + +def parse_no_name(d): + p = r'(\d+)\.(.*)' + m = re.search(p, d) + + try: + no = int(m.group(1)) + dir_name = m.group(2) + except: + sys.exit(0) + + return no, dir_name + + +def check_export(base, cfg): + flag = False + exports = [] + for export in cfg.get('export', []): + ecfg_path = os.path.join(base, export) + if os.path.exists(ecfg_path): + exports.append(export) + else: + flag = True + if flag: + cfg["export"] = exports + return flag + + +class TreeWalker: + def __init__(self, root, tree_name, title=None, log=None): + self.name = tree_name + self.root = root + self.title = tree_name if title is None else title + self.tree = {} + self.logger = logger if log is None else log + + def walk(self): + root = self.load_root() + root_node = { + "node_id": root["node_id"], + "keywords": root["keywords"], + "children": [] + } + self.tree[root["tree_name"]] = root_node + self.load_levels(root_node) + self.load_chapters(self.root, root_node) + for index, level in enumerate(root_node["children"]): + level_title = list(level.keys())[0] + level_node = list(level.values())[0] + level_path = os.path.join(self.root, f"{index + 1}.{level_title}") + self.load_chapters(level_path, level_node) + for index, chapter in enumerate(level_node["children"]): + chapter_title = list(chapter.keys())[0] + chapter_node = list(chapter.values())[0] + chapter_path = os.path.join( + level_path, f"{index + 1}.{chapter_title}") + self.load_sections(chapter_path, chapter_node) + for index, section_node in enumerate(chapter_node["children"]): + section_title = list(section_node.keys())[0] + full_path = os.path.join( + chapter_path, f"{index + 1}.{section_title}") + if os.path.isdir(full_path): + self.ensure_exercises(full_path) + + tree_path = os.path.join(self.root, "tree.json") + dump_json(tree_path, self.tree, exist_ok=True, override=True) + return self.tree + + def sort_dir_list(self, dirs): + result = [self.extract_node_env(dir) for dir in dirs] + result.sort(key=lambda item: item[0]) + return result + + def load_levels(self, root_node): + levels = [] + for level in os.listdir(self.root): + if not os.path.isdir(level): + continue + level_path = os.path.join(self.root, level) + num, config = self.load_level_node(level_path) + levels.append((num, config)) + + levels = self.resort_children(self.root, levels) + root_node["children"] = [item[1] for item in levels] + return root_node + + def load_level_node(self, level_path): + config = self.ensure_level_config(level_path) + num, name = self.extract_node_env(level_path) + + result = { + name: { + "node_id": config["node_id"], + "keywords": config["keywords"], + "children": [], + } + } + + return num, result + + def load_chapters(self, base, level_node): + chapters = [] + for name in os.listdir(base): + full_name = os.path.join(base, name) + if os.path.isdir(full_name): + num, chapter = self.load_chapter_node(full_name) + chapters.append((num, chapter)) + + chapters = self.resort_children(base, chapters) + level_node["children"] = [item[1] for item in chapters] + return level_node + + def load_sections(self, base, chapter_node): + sections = [] + for name in os.listdir(base): + full_name = os.path.join(base, name) + if os.path.isdir(full_name): + num, section = self.load_section_node(full_name) + sections.append((num, section)) + + sections = self.resort_children(base, sections) + chapter_node["children"] = [item[1] for item in sections] + return chapter_node + + def resort_children(self, base, children): + children.sort(key=lambda item: item[0]) + for index, [number, element] in enumerate(children): + title = list(element.keys())[0] + origin = os.path.join(base, f"{number}.{title}") + posted = os.path.join(base, f"{index + 1}.{title}") + if origin != posted: + self.logger.info(f"rename [{origin}] to [{posted}]") + os.rename(origin, posted) + return children + + def ensure_chapters(self): + for subdir in os.listdir(self.root): + self.ensure_level_config(subdir) + + def load_root(self): + config_path = os.path.join(self.root, "config.json") + if not os.path.exists(config_path): + config = { + "tree_name": self.name, + "keywords": [], + "node_id": self.gen_node_id(), + } + dump_json(config_path, config, exist_ok=True, override=True) + else: + config = load_json(config_path) + flag, result = self.ensure_node_id(config) + if flag: + dump_json(config_path, result, exist_ok=True, override=True) + + return config + + def ensure_level_config(self, path): + config_path = os.path.join(path, "config.json") + if not os.path.exists(config_path): + config = { + "node_id": self.gen_node_id() + } + dump_json(config_path, config, exist_ok=True, override=True) + else: + config = load_json(config_path) + flag, result = self.ensure_node_id(config) + if flag: + dump_json(config_path, config, exist_ok=True, override=True) + return config + + def ensure_chapter_config(self, path): + config_path = os.path.join(path, "config.json") + if not os.path.exists(config_path): + config = { + "node_id": self.gen_node_id(), + "keywords": [] + } + dump_json(config_path, config, exist_ok=True, override=True) + else: + config = load_json(config_path) + flag, result = self.ensure_node_id(config) + if flag: + dump_json(config_path, config, exist_ok=True, override=True) + return config + + def ensure_section_config(self, path): + config_path = os.path.join(path, "config.json") + if not os.path.exists(config_path): + config = { + "node_id": self.gen_node_id(), + "keywords": [], + "children": [], + "export": [] + } + dump_json(config_path, config, exist_ok=True, override=True) + else: + config = load_json(config_path) + flag, result = self.ensure_node_id(config) + if flag: + dump_json(config_path, result, exist_ok=True, override=True) + return config + + def ensure_node_id(self, config): + flag = False + if "node_id" not in config or \ + not config["node_id"].startswith(f"{self.name}-") or \ + config["node_id"] in id_set: + new_id = self.gen_node_id() + id_set.add(new_id) + config["node_id"] = new_id + flag = True + + for child in config.get("children", []): + child_node = list(child.values())[0] + f, _ = self.ensure_node_id(child_node) + flag = flag or f + + return flag, config + + def gen_node_id(self): + return f"{self.name}-{uuid.uuid4().hex}" + + def extract_node_env(self, path): + try: + _, dir = os.path.split(path) + self.logger.info(path) + number, title = dir.split(".", 1) + return int(number), title + except Exception as error: + self.logger.error(f"目录 [{path}] 解析失败,结构不合法,可能是缺少序号") + # sys.exit(1) + raise error + + def load_chapter_node(self, full_name): + config = self.ensure_chapter_config(full_name) + num, name = self.extract_node_env(full_name) + result = { + name: { + "node_id": config["node_id"], + "keywords": config["keywords"], + "children": [], + } + } + return num, result + + def load_section_node(self, full_name): + config = self.ensure_section_config(full_name) + num, name = self.extract_node_env(full_name) + result = { + name: { + "node_id": config["node_id"], + "keywords": config["keywords"], + "children": config.get("children", []) + } + } + # if "children" in config: + # result["children"] = config["children"] + return num, result + + def ensure_exercises(self, section_path): + config = self.ensure_section_config(section_path) + for e in config.get("export", []): + full_name = os.path.join(section_path, e) + exercise = load_json(full_name) + if "exercise_id" not in exercise: + exercise["exercise_id"] = uuid.uuid4().hex + dump_json(full_name, exercise, True, True)