提交 632e328f 编写于 作者: F feilong

补充关键字

上级 658ec48d
{
"type": "code_options",
"author": "kinfey",
"source": "HelloWorld.md"
"type": "code_options",
"author": "kinfey",
"source": "HelloWorld.md",
"exercise_id": "c14e798b0103470db0cb7324e8188149",
"notebook_enable": false
}
\ No newline at end of file
{
"node_id": "",
"keywords": [
"控制台",
"dotnet new",
"程序入口"
],
"children": [],
"export": [
"HelloWorld.json"
],
"title": "Hello World"
}
\ No newline at end of file
"node_id": "csharp-a84d91fb923e4e50810024368a7b2d29",
"keywords": [
"控制台",
"dotnet new",
"程序入口"
],
"children": [],
"export": [
"HelloWorld.json"
],
"title": "Hello World"
}
\ No newline at end of file
{
"type": "code_options",
"author": "kinfey",
"source": "Intro.md"
"type": "code_options",
"author": "kinfey",
"source": "Intro.md",
"exercise_id": "d4fd594548114266957699f12555f9aa",
"notebook_enable": false
}
\ No newline at end of file
{
"node_id": "",
"keywords": [
"dotnet",
".NET",
"跨平台"
],
"export": [
"Intro.json"
]
"node_id": "csharp-a8d22b1b96f648eeb579ac1e8c2623d4",
"keywords": [
"dotnet",
".NET",
"跨平台"
],
"export": [
"Intro.json"
]
}
\ No newline at end of file
{
"type": "code_options",
"author": "huanhuilong",
"source": "Standard.md"
"type": "code_options",
"author": "huanhuilong",
"source": "Standard.md",
"exercise_id": "1a9d1d5fa2ab49b8b50bf4369d482980",
"notebook_enable": false
}
\ No newline at end of file
{
"node_id": "csharp-8f1055780aff4ed8bc5927bac6fb562b",
"keywords": [],
"keywords": [
".NET Standard",
".NET 实现"
],
"children": [],
"export": [
"Standard.json"
......
{
"type": "code_options",
"author": "huanhuilong",
"source": "Lib.md"
"type": "code_options",
"author": "huanhuilong",
"source": "Lib.md",
"exercise_id": "b9f18b80f7b54cd886075df4b08adc14",
"notebook_enable": false
}
\ No newline at end of file
{
"node_id": "csharp-7029a05888534973bfa9656762e0c187",
"keywords": [],
"keywords": [
".NET 共享库",
".NET 类库",
".NET 标准库"
],
"children": [],
"export": [
"Lib.json"
......
{
"type": "code_options",
"author": "huanhuilong",
"source": "StandardQuery.md"
"type": "code_options",
"author": "huanhuilong",
"source": "StandardQuery.md",
"exercise_id": "5785b9a1103b4337a966a06b9d93271c",
"notebook_enable": false
}
\ No newline at end of file
{
"node_id": "csharp-65d2fd88ed1e44a6a646be4f3c302e50",
"keywords": [],
"keywords": [
".NET Standard 版本"
],
"children": [],
"export": [
"StandardQuery.json"
......
{
"type": "code_options",
"author": "huanhuilong",
"source": "HelloWorld2.md"
"type": "code_options",
"author": "huanhuilong",
"source": "HelloWorld2.md",
"exercise_id": "b0997a92c85a467f8b97f99372f9964e",
"notebook_enable": false
}
\ No newline at end of file
{
"node_id": "csharp-8f63c0182bed428cb2c75bc1d10a6502",
"keywords": [],
"keywords": [
"C# HelloWorld"
],
"children": [],
"export": [
"HelloWorld2.json"
......
{
"type": "code_options",
"author": "huanhuilong",
"source": "String.md"
"type": "code_options",
"author": "huanhuilong",
"source": "String.md",
"exercise_id": "12868f4d7570402e82e46901832c437c",
"notebook_enable": false
}
\ No newline at end of file
{
"type": "code_options",
"author": "huanhuilong",
"source": "Variable.md"
"type": "code_options",
"author": "huanhuilong",
"source": "Variable.md",
"exercise_id": "28c24ce184ca4b5bb6cae7e030b76da3",
"notebook_enable": false
}
\ No newline at end of file
{
"node_id": "csharp-052799fae6c2498f9ef2966925377631",
"keywords": [],
"keywords": [
"C# 字符串",
"C# 变量",
"C# 整型",
"C# 基本类型"
],
"children": [],
"export": [
"String.json",
......
{
"type": "code_options",
"author": "huanhuilong",
"source": "Format.md"
"type": "code_options",
"author": "huanhuilong",
"source": "Format.md",
"exercise_id": "fdc21db690b9421da1445d2fe8161bc5",
"notebook_enable": false
}
\ No newline at end of file
{
"type": "code_options",
"author": "Gao996",
"source": "StringFormatting.md"
"type": "code_options",
"author": "Gao996",
"source": "StringFormatting.md",
"exercise_id": "2c3bc6d878274469acd2573b65eecf8c",
"notebook_enable": false
}
\ No newline at end of file
{
"node_id": "csharp-6213732b191f434fb809de14eadee919",
"keywords": [],
"keywords": [
"C# 字符串格式化"
],
"children": [],
"export": [
"Format.json",
......
{
"type": "code_options",
"author": "huanhuilong",
"source": "Calc.md"
"type": "code_options",
"author": "huanhuilong",
"source": "Calc.md",
"exercise_id": "0de228ab99124ef981e2192b705e2ce2",
"notebook_enable": false
}
\ No newline at end of file
{
"node_id": "csharp-8891612a2ed349b4a04dee606c44a292",
"keywords": [],
"keywords": [
"C# 数字运算符",
"C# 四则运算"
],
"children": [],
"export": [
"Calc.json"
......
{
"type": "code_options",
"author": "huanhuilong",
"source": "Guess.md"
"type": "code_options",
"author": "huanhuilong",
"source": "Guess.md",
"exercise_id": "ac74458fcd154ab9b8de45d7f9d3e928",
"notebook_enable": false
}
\ No newline at end of file
{
"node_id": "csharp-ecdbead6dc0f4676b048a3d3d6a31741",
"keywords": [],
"keywords": [
".NET 基础类库"
],
"children": [],
"export": [
"Guess.json"
......
{
"type": "code_options",
"author": "huanhuilong",
"source": "Guard.md"
"type": "code_options",
"author": "huanhuilong",
"source": "Guard.md",
"exercise_id": "4778ac7e3bf24d5fa4d0a516e6f04c97",
"notebook_enable": false
}
\ No newline at end of file
{
"type": "code_options",
"author": "huanhuilong",
"source": "Swtich.md"
"type": "code_options",
"author": "huanhuilong",
"source": "Swtich.md",
"exercise_id": "2b77eacce88e48379fdd557e381ee19a",
"notebook_enable": false
}
\ No newline at end of file
{
"node_id": "csharp-d1ae8aa6b969476db5177062e3980a2f",
"keywords": [],
"keywords": [
"C# 分支判断"
],
"children": [],
"export": [
"Guard.json",
......
{
"type": "code_options",
"author": "huanhuilong",
"source": "Loop.md"
"type": "code_options",
"author": "huanhuilong",
"source": "Loop.md",
"exercise_id": "026be3104cc448e1a34fa60440128374",
"notebook_enable": false
}
\ No newline at end of file
{
"node_id": "csharp-e8990ea17ca34c49b4d0c69b3272bc10",
"keywords": [],
"keywords": [
"C# 数组",
"foreach",
"斐波那契数列"
],
"children": [],
"export": [
"Loop.json"
......
{
"type": "code_options",
"author": "huanhuilong",
"source": "Comments.md"
"type": "code_options",
"author": "huanhuilong",
"source": "Comments.md",
"exercise_id": "c7c906d223b5424685e6133d81eeea8e",
"notebook_enable": false
}
\ No newline at end of file
{
"node_id": "csharp-302a68c721e44f489e00820b5898ec10",
"keywords": [],
"keywords": [
"C# 编码规范",
"C# 注释"
],
"children": [],
"export": [
"Comments.json"
......
{
"node_id": "csharp-202a0f83809340d2b38e8e0d4b00b48c",
"keywords": [],
"keywords": [
"Razor"
],
"children": [],
"export": []
}
\ No newline at end of file
{
"node_id": "csharp-97413a9e08fb4b55a742b45b2d61e13a",
"keywords": [],
"keywords": [
".NET MVC"
],
"children": [],
"export": []
}
\ No newline at end of file
{
"node_id": "csharp-b3c0aaca71c249fa8bc4052980637613",
"keywords": [],
"keywords": [
".NET Blazor"
],
"children": [],
"export": []
}
\ No newline at end of file
{
"node_id": "csharp-e1b867ff5a1344bd9a7e34201343711c",
"keywords": [],
"keywords": [
".NET Web API"
],
"children": [],
"export": []
}
\ No newline at end of file
{
"node_id": "csharp-5ef3b2a32bc344c984bb195b42eae73c",
"keywords": [],
"keywords": [
".NET Minimal API"
],
"children": [],
"export": []
}
\ No newline at end of file
......@@ -15,7 +15,7 @@
"children": [
{
"Hello World": {
"node_id": "",
"node_id": "csharp-a84d91fb923e4e50810024368a7b2d29",
"keywords": [
"控制台",
"dotnet new",
......@@ -26,7 +26,7 @@
},
{
"简介": {
"node_id": "",
"node_id": "csharp-a8d22b1b96f648eeb579ac1e8c2623d4",
"keywords": [
"dotnet",
".NET",
......@@ -38,21 +38,30 @@
{
"体系结构组件": {
"node_id": "csharp-8f1055780aff4ed8bc5927bac6fb562b",
"keywords": [],
"keywords": [
".NET Standard",
".NET 实现"
],
"children": []
}
},
{
".NET类库": {
"node_id": "csharp-7029a05888534973bfa9656762e0c187",
"keywords": [],
"keywords": [
".NET 共享库",
".NET 类库",
".NET 标准库"
],
"children": []
}
},
{
".NET Standard概述": {
"node_id": "csharp-65d2fd88ed1e44a6a646be4f3c302e50",
"keywords": [],
"keywords": [
".NET Standard 版本"
],
"children": []
}
}
......@@ -67,56 +76,79 @@
{
"编写第一个C#代码": {
"node_id": "csharp-8f63c0182bed428cb2c75bc1d10a6502",
"keywords": [],
"keywords": [
"C# HelloWorld"
],
"children": []
}
},
{
"使用C#中的文本值和变量值来存储和检索数据": {
"C#文本值和变量": {
"node_id": "csharp-052799fae6c2498f9ef2966925377631",
"keywords": [],
"keywords": [
"C# 字符串",
"C# 变量",
"C# 整型",
"C# 基本类型"
],
"children": []
}
},
{
"在C#中执行基本字符串格式设置": {
"C#字符串格式设置": {
"node_id": "csharp-6213732b191f434fb809de14eadee919",
"keywords": [],
"keywords": [
"C# 字符串格式化"
],
"children": []
}
},
{
"使用C#对数字执行基本运算操作": {
"C#数字运算操作": {
"node_id": "csharp-8891612a2ed349b4a04dee606c44a292",
"keywords": [],
"keywords": [
"C# 数字运算符",
"C# 四则运算"
],
"children": []
}
},
{
"使用C#从.NET类库调用方法": {
"node_id": "csharp-ecdbead6dc0f4676b048a3d3d6a31741",
"keywords": [],
"keywords": [
".NET 基础类库"
],
"children": []
}
},
{
"在 C# 中使用 if-elseif-else 语句将决策逻辑添加到代码中": {
"C# 中使用 if-elseif-else 分支判断": {
"node_id": "csharp-d1ae8aa6b969476db5177062e3980a2f",
"keywords": [],
"keywords": [
"C# 分支判断"
],
"children": []
}
},
{
"使用C# 中的数组和 foreach 语句来存储和循环访问数据序列": {
"C# 数组和 foreach 语句": {
"node_id": "csharp-e8990ea17ca34c49b4d0c69b3272bc10",
"keywords": [],
"keywords": [
"C# 数组",
"foreach",
"斐波那契数列"
],
"children": []
}
},
{
"使用 C# 创建具有约定、空格和注释的易读代码": {
"C# 编码规范": {
"node_id": "csharp-302a68c721e44f489e00820b5898ec10",
"keywords": [],
"keywords": [
"C# 编码规范",
"C# 注释"
],
"children": []
}
}
......@@ -139,35 +171,45 @@
{
"Razor应用": {
"node_id": "csharp-202a0f83809340d2b38e8e0d4b00b48c",
"keywords": [],
"keywords": [
"Razor"
],
"children": []
}
},
{
"MVC": {
"node_id": "csharp-97413a9e08fb4b55a742b45b2d61e13a",
"keywords": [],
"keywords": [
".NET MVC"
],
"children": []
}
},
{
"Blazor应用": {
"node_id": "csharp-b3c0aaca71c249fa8bc4052980637613",
"keywords": [],
"keywords": [
".NET Blazor"
],
"children": []
}
},
{
"Web API应用": {
"node_id": "csharp-e1b867ff5a1344bd9a7e34201343711c",
"keywords": [],
"keywords": [
".NET Web API"
],
"children": []
}
},
{
"Minimal API 应用": {
"node_id": "csharp-5ef3b2a32bc344c984bb195b42eae73c",
"keywords": [],
"keywords": [
".NET Minimal API"
],
"children": []
}
}
......
# -*- coding: utf-8 -*-
import logging
from genericpath import exists
import json
import logging
import os
import uuid
import re
import sys
import uuid
import re
import git
id_set = set()
logger = logging.getLogger(__name__)
......@@ -14,10 +14,15 @@ handler = logging.StreamHandler(sys.stdout)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
repo = git.Repo(".")
def user_name():
return repo.config_reader().get_value("user", "name")
def load_json(p):
with open(p, 'r', encoding='utf-8') as f:
with open(p, 'r') as f:
return json.loads(f.read())
......@@ -30,7 +35,7 @@ def dump_json(p, j, exist_ok=False, override=False):
logger.error(f"{p} already exist")
sys.exit(0)
with open(p, 'w+', encoding='utf-8') as f:
with open(p, 'w+', encoding="utf8") as f:
f.write(json.dumps(j, indent=2, ensure_ascii=False))
......@@ -92,25 +97,31 @@ class TreeWalker:
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}")
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}")
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}.{section_title}")
chapter_path, f"{index + 1}.{section_title}")
if os.path.isdir(full_path):
self.check_section_keywords(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):
......@@ -167,7 +178,7 @@ class TreeWalker:
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}")
posted = os.path.join(base, f"{index + 1}.{title}")
if origin != posted:
self.logger.info(f"rename [{origin}] to [{posted}]")
os.rename(origin, posted)
......@@ -237,15 +248,25 @@ class TreeWalker:
config = load_json(config_path)
flag, result = self.ensure_node_id(config)
if flag:
dump_json(config_path, config, exist_ok=True, override=True)
dump_json(config_path, result, exist_ok=True, override=True)
return config
def ensure_node_id(self, config):
if "node_id" not in config:
config["node_id"] = self.gen_node_id()
return True, config
else:
return False, 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}"
......@@ -258,7 +279,8 @@ class TreeWalker:
return int(number), title
except Exception as error:
self.logger.error(f"目录 [{path}] 解析失败,结构不合法,可能是缺少序号")
sys.exit(1)
# sys.exit(1)
raise error
def load_chapter_node(self, full_name):
config = self.ensure_chapter_config(full_name)
......@@ -288,9 +310,71 @@ class TreeWalker:
def ensure_exercises(self, section_path):
config = self.ensure_section_config(section_path)
flag = False
for e in os.listdir(section_path):
base, ext = os.path.splitext(e)
_, source = os.path.split(e)
if ext != ".md":
continue
mfile = base + ".json"
meta_path = os.path.join(section_path, mfile)
self.ensure_exercises_meta(meta_path, source)
export = config.get("export", [])
if mfile not in export and self.name != "algorithm":
export.append(mfile)
flag = True
config["export"] = export
if flag:
dump_json(os.path.join(section_path, "config.json"),
config, True, True)
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)
if "exercise_id" not in exercise or exercise.get("exercise_id") in id_set:
eid = uuid.uuid4().hex
exercise["exercise_id"] = eid
dump_json(full_name, exercise, True, True)
else:
id_set.add(exercise["exercise_id"])
def ensure_exercises_meta(self, meta_path, source):
_, mfile = os.path.split(meta_path)
meta = None
if os.path.exists(meta_path):
with open(meta_path) as f:
content = f.read()
if content:
meta = json.loads(content)
if "exercise_id" not in meta:
meta["exercise_id"] = uuid.uuid4().hex
if "notebook_enable" not in meta:
meta["notebook_enable"] = self.default_notebook()
if "source" not in meta:
meta["source"] = source
if "author" not in meta:
meta["author"] = user_name()
if "type" not in meta:
meta["type"] = "code_options"
if meta is None:
meta = {
"type": "code_options",
"author": user_name(),
"source": source,
"notebook_enable": self.default_notebook(),
"exercise_id": uuid.uuid4().hex
}
dump_json(meta_path, meta, True, True)
def default_notebook(self):
if self.name in ["python", "java", "c"]:
return True
else:
return False
def check_section_keywords(self, full_path):
config = self.ensure_section_config(full_path)
if not config.get("keywords", []):
self.logger.error(f"节点 [{full_path}] 的关键字为空,请修改配置文件写入关键字")
sys.exit(1)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册