aicodestat 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aicodestat-0.0.1.dist-info/METADATA +110 -0
- aicodestat-0.0.1.dist-info/RECORD +34 -0
- aicodestat-0.0.1.dist-info/WHEEL +5 -0
- aicodestat-0.0.1.dist-info/entry_points.txt +5 -0
- aicodestat-0.0.1.dist-info/top_level.txt +10 -0
- cli/__init__.py +2 -0
- cli/exporter.py +111 -0
- cli/main.py +213 -0
- cli/menus.py +540 -0
- cli/views.py +277 -0
- compute/__init__.py +2 -0
- compute/cache.py +90 -0
- compute/diff_engine.py +69 -0
- compute/lcs_engine.py +73 -0
- compute/metrics_service.py +362 -0
- config.py +120 -0
- local_mcp_server.py +260 -0
- logging_config.py +68 -0
- main.py +164 -0
- mcp/__init__.py +2 -0
- mcp/agent_adapter.py +69 -0
- mcp/api_schemas.py +26 -0
- mcp/routes_after.py +121 -0
- mcp/routes_before.py +68 -0
- mcp/routes_tools.py +100 -0
- service_manager.py +221 -0
- storage/__init__.py +2 -0
- storage/backup.py +185 -0
- storage/db.py +156 -0
- storage/models.py +338 -0
- storage/scheduler.py +111 -0
- utils/__init__.py +2 -0
- utils/port_utils.py +59 -0
- utils/time_utils.py +37 -0
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
"""指标服务层:对外提供统一指标计算接口"""
|
|
2
|
+
import logging
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Dict, Any, List, Optional
|
|
5
|
+
from storage.models import get_session_summaries, get_code_diff_lines
|
|
6
|
+
from compute.lcs_engine import lcs_calculate, calculate_adoption_rate, calculate_generation_rate
|
|
7
|
+
from compute.cache import get_cache
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def read_file_lines(file_path: str) -> List[str]:
|
|
13
|
+
"""
|
|
14
|
+
从文件系统读取最新文件内容,分割为行
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
file_path: 文件路径
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
文件行列表
|
|
21
|
+
"""
|
|
22
|
+
try:
|
|
23
|
+
file = Path(file_path)
|
|
24
|
+
if not file.exists():
|
|
25
|
+
logger.warning(f"File not found: {file_path}")
|
|
26
|
+
return []
|
|
27
|
+
|
|
28
|
+
with open(file, 'r', encoding='utf-8', errors='ignore') as f:
|
|
29
|
+
return f.readlines()
|
|
30
|
+
except Exception as e:
|
|
31
|
+
logger.error(f"Failed to read file {file_path}: {e}")
|
|
32
|
+
return []
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def calculate_session_metrics(session_id: str) -> Dict[str, Any]:
|
|
36
|
+
"""
|
|
37
|
+
计算会话维度的指标
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
session_id: 会话ID
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
指标字典,包含:
|
|
44
|
+
- ai_total_lines: AI生成总行数
|
|
45
|
+
- adopted_lines: 采纳行数
|
|
46
|
+
- adoption_rate: 采纳率
|
|
47
|
+
- generation_rate: 生成率(按所有涉及文件的总行数计算)
|
|
48
|
+
- file_count: 涉及文件数
|
|
49
|
+
- summaries: 会话汇总列表
|
|
50
|
+
- diff_lines: 差异行列表
|
|
51
|
+
"""
|
|
52
|
+
cache = get_cache()
|
|
53
|
+
cache_key = f"session_metrics:{session_id}"
|
|
54
|
+
|
|
55
|
+
# 检查缓存
|
|
56
|
+
cached_result = cache.get(cache_key)
|
|
57
|
+
if cached_result is not None:
|
|
58
|
+
logger.debug(f"Using cached metrics for session {session_id}")
|
|
59
|
+
return cached_result
|
|
60
|
+
|
|
61
|
+
# 获取会话汇总
|
|
62
|
+
summaries = get_session_summaries(session_id=session_id)
|
|
63
|
+
|
|
64
|
+
if not summaries:
|
|
65
|
+
return {
|
|
66
|
+
"session_id": session_id,
|
|
67
|
+
"ai_total_lines": 0,
|
|
68
|
+
"adopted_lines": 0,
|
|
69
|
+
"adoption_rate": 0.0,
|
|
70
|
+
"generation_rate": 0.0,
|
|
71
|
+
"file_count": 0,
|
|
72
|
+
"summaries": [],
|
|
73
|
+
"diff_lines": []
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
# 获取所有差异行
|
|
77
|
+
all_diff_lines = get_code_diff_lines(session_id=session_id)
|
|
78
|
+
|
|
79
|
+
# 计算AI生成总行数
|
|
80
|
+
ai_total_lines = len(all_diff_lines)
|
|
81
|
+
|
|
82
|
+
# 按文件分组计算采纳行数
|
|
83
|
+
file_groups: Dict[str, List[Dict[str, Any]]] = {}
|
|
84
|
+
for diff_line in all_diff_lines:
|
|
85
|
+
file_path = diff_line["file_path"]
|
|
86
|
+
if file_path not in file_groups:
|
|
87
|
+
file_groups[file_path] = []
|
|
88
|
+
file_groups[file_path].append(diff_line)
|
|
89
|
+
|
|
90
|
+
total_adopted_lines = 0
|
|
91
|
+
total_file_lines = 0
|
|
92
|
+
|
|
93
|
+
for file_path, diff_lines in file_groups.items():
|
|
94
|
+
# 读取文件最新内容
|
|
95
|
+
latest_lines = read_file_lines(file_path)
|
|
96
|
+
total_file_lines += len(latest_lines)
|
|
97
|
+
|
|
98
|
+
# 提取AI生成的差异行内容
|
|
99
|
+
ai_diff_content = [d["line_content"] for d in diff_lines]
|
|
100
|
+
|
|
101
|
+
# 计算LCS(采纳行数)
|
|
102
|
+
adopted = lcs_calculate(ai_diff_content, latest_lines)
|
|
103
|
+
total_adopted_lines += adopted
|
|
104
|
+
|
|
105
|
+
# 计算指标
|
|
106
|
+
adoption_rate = calculate_adoption_rate(ai_total_lines, total_adopted_lines)
|
|
107
|
+
generation_rate = calculate_generation_rate(ai_total_lines, total_file_lines) if total_file_lines > 0 else 0.0
|
|
108
|
+
|
|
109
|
+
result = {
|
|
110
|
+
"session_id": session_id,
|
|
111
|
+
"ai_total_lines": ai_total_lines,
|
|
112
|
+
"adopted_lines": total_adopted_lines,
|
|
113
|
+
"adoption_rate": adoption_rate,
|
|
114
|
+
"generation_rate": generation_rate,
|
|
115
|
+
"file_count": len(file_groups),
|
|
116
|
+
"summaries": summaries,
|
|
117
|
+
"diff_lines": all_diff_lines
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
# 缓存结果
|
|
121
|
+
cache.set(cache_key, result)
|
|
122
|
+
|
|
123
|
+
return result
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def calculate_file_metrics(file_path: str) -> Dict[str, Any]:
|
|
127
|
+
"""
|
|
128
|
+
计算文件维度的指标
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
file_path: 文件路径
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
指标字典
|
|
135
|
+
"""
|
|
136
|
+
cache = get_cache()
|
|
137
|
+
cache_key = f"file_metrics:{file_path}"
|
|
138
|
+
|
|
139
|
+
# 检查缓存
|
|
140
|
+
cached_result = cache.get(cache_key)
|
|
141
|
+
if cached_result is not None:
|
|
142
|
+
logger.debug(f"Using cached metrics for file {file_path}")
|
|
143
|
+
return cached_result
|
|
144
|
+
|
|
145
|
+
# 获取文件相关的所有会话汇总
|
|
146
|
+
summaries = get_session_summaries(file_path=file_path)
|
|
147
|
+
|
|
148
|
+
if not summaries:
|
|
149
|
+
return {
|
|
150
|
+
"file_path": file_path,
|
|
151
|
+
"ai_total_lines": 0,
|
|
152
|
+
"adopted_lines": 0,
|
|
153
|
+
"adoption_rate": 0.0,
|
|
154
|
+
"generation_rate": 0.0,
|
|
155
|
+
"session_count": 0,
|
|
156
|
+
"summaries": [],
|
|
157
|
+
"diff_lines": []
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
# 获取所有差异行
|
|
161
|
+
all_diff_lines = get_code_diff_lines(file_path=file_path)
|
|
162
|
+
|
|
163
|
+
# 计算AI生成总行数
|
|
164
|
+
ai_total_lines = len(all_diff_lines)
|
|
165
|
+
|
|
166
|
+
# 读取文件最新内容
|
|
167
|
+
latest_lines = read_file_lines(file_path)
|
|
168
|
+
total_file_lines = len(latest_lines)
|
|
169
|
+
|
|
170
|
+
# 提取AI生成的差异行内容
|
|
171
|
+
ai_diff_content = [d["line_content"] for d in all_diff_lines]
|
|
172
|
+
|
|
173
|
+
# 计算LCS(采纳行数)
|
|
174
|
+
adopted_lines = lcs_calculate(ai_diff_content, latest_lines)
|
|
175
|
+
|
|
176
|
+
# 计算指标
|
|
177
|
+
adoption_rate = calculate_adoption_rate(ai_total_lines, adopted_lines)
|
|
178
|
+
generation_rate = calculate_generation_rate(ai_total_lines, total_file_lines) if total_file_lines > 0 else 0.0
|
|
179
|
+
|
|
180
|
+
result = {
|
|
181
|
+
"file_path": file_path,
|
|
182
|
+
"ai_total_lines": ai_total_lines,
|
|
183
|
+
"adopted_lines": adopted_lines,
|
|
184
|
+
"adoption_rate": adoption_rate,
|
|
185
|
+
"generation_rate": generation_rate,
|
|
186
|
+
"session_count": len(summaries),
|
|
187
|
+
"summaries": summaries,
|
|
188
|
+
"diff_lines": all_diff_lines
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
# 缓存结果
|
|
192
|
+
cache.set(cache_key, result)
|
|
193
|
+
|
|
194
|
+
return result
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def calculate_project_metrics(project_root: str) -> Dict[str, Any]:
|
|
198
|
+
"""
|
|
199
|
+
计算项目维度的指标
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
project_root: 项目根目录路径
|
|
203
|
+
|
|
204
|
+
Returns:
|
|
205
|
+
指标字典
|
|
206
|
+
"""
|
|
207
|
+
cache = get_cache()
|
|
208
|
+
cache_key = f"project_metrics:{project_root}"
|
|
209
|
+
|
|
210
|
+
# 检查缓存
|
|
211
|
+
cached_result = cache.get(cache_key)
|
|
212
|
+
if cached_result is not None:
|
|
213
|
+
logger.debug(f"Using cached metrics for project {project_root}")
|
|
214
|
+
return cached_result
|
|
215
|
+
|
|
216
|
+
# 获取所有会话汇总
|
|
217
|
+
all_summaries = get_session_summaries()
|
|
218
|
+
|
|
219
|
+
# 过滤出项目内的文件
|
|
220
|
+
project_path = Path(project_root).resolve()
|
|
221
|
+
project_summaries = [
|
|
222
|
+
s for s in all_summaries
|
|
223
|
+
if Path(s["file_path"]).resolve().is_relative_to(project_path)
|
|
224
|
+
]
|
|
225
|
+
|
|
226
|
+
if not project_summaries:
|
|
227
|
+
return {
|
|
228
|
+
"project_root": project_root,
|
|
229
|
+
"ai_total_lines": 0,
|
|
230
|
+
"adopted_lines": 0,
|
|
231
|
+
"adoption_rate": 0.0,
|
|
232
|
+
"generation_rate": 0.0,
|
|
233
|
+
"file_count": 0,
|
|
234
|
+
"session_count": 0,
|
|
235
|
+
"summaries": [],
|
|
236
|
+
"diff_lines": []
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
# 获取所有相关差异行
|
|
240
|
+
project_files = {s["file_path"] for s in project_summaries}
|
|
241
|
+
all_diff_lines = []
|
|
242
|
+
for file_path in project_files:
|
|
243
|
+
all_diff_lines.extend(get_code_diff_lines(file_path=file_path))
|
|
244
|
+
|
|
245
|
+
# 计算AI生成总行数
|
|
246
|
+
ai_total_lines = len(all_diff_lines)
|
|
247
|
+
|
|
248
|
+
# 按文件分组计算采纳行数
|
|
249
|
+
total_adopted_lines = 0
|
|
250
|
+
total_file_lines = 0
|
|
251
|
+
|
|
252
|
+
file_groups: Dict[str, List[Dict[str, Any]]] = {}
|
|
253
|
+
for diff_line in all_diff_lines:
|
|
254
|
+
file_path = diff_line["file_path"]
|
|
255
|
+
if file_path not in file_groups:
|
|
256
|
+
file_groups[file_path] = []
|
|
257
|
+
file_groups[file_path].append(diff_line)
|
|
258
|
+
|
|
259
|
+
for file_path, diff_lines in file_groups.items():
|
|
260
|
+
latest_lines = read_file_lines(file_path)
|
|
261
|
+
total_file_lines += len(latest_lines)
|
|
262
|
+
|
|
263
|
+
ai_diff_content = [d["line_content"] for d in diff_lines]
|
|
264
|
+
adopted = lcs_calculate(ai_diff_content, latest_lines)
|
|
265
|
+
total_adopted_lines += adopted
|
|
266
|
+
|
|
267
|
+
# 计算指标
|
|
268
|
+
adoption_rate = calculate_adoption_rate(ai_total_lines, total_adopted_lines)
|
|
269
|
+
generation_rate = calculate_generation_rate(ai_total_lines, total_file_lines) if total_file_lines > 0 else 0.0
|
|
270
|
+
|
|
271
|
+
result = {
|
|
272
|
+
"project_root": project_root,
|
|
273
|
+
"ai_total_lines": ai_total_lines,
|
|
274
|
+
"adopted_lines": total_adopted_lines,
|
|
275
|
+
"adoption_rate": adoption_rate,
|
|
276
|
+
"generation_rate": generation_rate,
|
|
277
|
+
"file_count": len(file_groups),
|
|
278
|
+
"session_count": len(set(s["session_id"] for s in project_summaries)),
|
|
279
|
+
"summaries": project_summaries,
|
|
280
|
+
"diff_lines": all_diff_lines
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
# 缓存结果
|
|
284
|
+
cache.set(cache_key, result)
|
|
285
|
+
|
|
286
|
+
return result
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def calculate_global_metrics() -> Dict[str, Any]:
|
|
290
|
+
"""
|
|
291
|
+
计算全局(所有项目 / 会话)的总体指标,用于全局看板。
|
|
292
|
+
"""
|
|
293
|
+
cache = get_cache()
|
|
294
|
+
cache_key = "global_metrics"
|
|
295
|
+
|
|
296
|
+
cached_result = cache.get(cache_key)
|
|
297
|
+
if cached_result is not None:
|
|
298
|
+
logger.debug("Using cached global metrics")
|
|
299
|
+
return cached_result
|
|
300
|
+
|
|
301
|
+
# 获取所有会话汇总
|
|
302
|
+
all_summaries = get_session_summaries()
|
|
303
|
+
if not all_summaries:
|
|
304
|
+
result = {
|
|
305
|
+
"ai_total_lines": 0,
|
|
306
|
+
"adopted_lines": 0,
|
|
307
|
+
"adoption_rate": 0.0,
|
|
308
|
+
"generation_rate": 0.0,
|
|
309
|
+
"file_count": 0,
|
|
310
|
+
"session_count": 0,
|
|
311
|
+
"summaries": [],
|
|
312
|
+
"diff_lines": [],
|
|
313
|
+
}
|
|
314
|
+
cache.set(cache_key, result)
|
|
315
|
+
return result
|
|
316
|
+
|
|
317
|
+
# 关联所有文件与差异行
|
|
318
|
+
all_files = {s["file_path"] for s in all_summaries}
|
|
319
|
+
all_diff_lines: List[Dict[str, Any]] = []
|
|
320
|
+
for file_path in all_files:
|
|
321
|
+
all_diff_lines.extend(get_code_diff_lines(file_path=file_path))
|
|
322
|
+
|
|
323
|
+
ai_total_lines = len(all_diff_lines)
|
|
324
|
+
|
|
325
|
+
total_adopted_lines = 0
|
|
326
|
+
total_file_lines = 0
|
|
327
|
+
file_groups: Dict[str, List[Dict[str, Any]]] = {}
|
|
328
|
+
|
|
329
|
+
for diff_line in all_diff_lines:
|
|
330
|
+
file_path = diff_line["file_path"]
|
|
331
|
+
if file_path not in file_groups:
|
|
332
|
+
file_groups[file_path] = []
|
|
333
|
+
file_groups[file_path].append(diff_line)
|
|
334
|
+
|
|
335
|
+
for file_path, diff_lines in file_groups.items():
|
|
336
|
+
latest_lines = read_file_lines(file_path)
|
|
337
|
+
total_file_lines += len(latest_lines)
|
|
338
|
+
|
|
339
|
+
ai_diff_content = [d["line_content"] for d in diff_lines]
|
|
340
|
+
adopted = lcs_calculate(ai_diff_content, latest_lines)
|
|
341
|
+
total_adopted_lines += adopted
|
|
342
|
+
|
|
343
|
+
adoption_rate = calculate_adoption_rate(ai_total_lines, total_adopted_lines)
|
|
344
|
+
generation_rate = (
|
|
345
|
+
calculate_generation_rate(ai_total_lines, total_file_lines)
|
|
346
|
+
if total_file_lines > 0
|
|
347
|
+
else 0.0
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
result = {
|
|
351
|
+
"ai_total_lines": ai_total_lines,
|
|
352
|
+
"adopted_lines": total_adopted_lines,
|
|
353
|
+
"adoption_rate": adoption_rate,
|
|
354
|
+
"generation_rate": generation_rate,
|
|
355
|
+
"file_count": len(file_groups),
|
|
356
|
+
"session_count": len(set(s["session_id"] for s in all_summaries)),
|
|
357
|
+
"summaries": all_summaries,
|
|
358
|
+
"diff_lines": all_diff_lines,
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
cache.set(cache_key, result)
|
|
362
|
+
return result
|
config.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""配置管理模块,支持从config.json和环境变量加载配置"""
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any, Dict
|
|
6
|
+
import logging
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
# 全局配置缓存
|
|
11
|
+
_config: Dict[str, Any] = None
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_config_path() -> Path:
|
|
15
|
+
"""获取配置文件路径"""
|
|
16
|
+
config_file = Path(__file__).parent / "config.json"
|
|
17
|
+
return config_file
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def load_config() -> Dict[str, Any]:
|
|
21
|
+
"""加载配置文件,支持环境变量覆盖"""
|
|
22
|
+
global _config
|
|
23
|
+
|
|
24
|
+
if _config is not None:
|
|
25
|
+
return _config
|
|
26
|
+
|
|
27
|
+
config_path = get_config_path()
|
|
28
|
+
|
|
29
|
+
# 默认配置
|
|
30
|
+
default_config = {
|
|
31
|
+
"server": {
|
|
32
|
+
"host": "127.0.0.1",
|
|
33
|
+
"port": 54546,
|
|
34
|
+
"log_level": "info",
|
|
35
|
+
"log_file": "~/.local-mcp-server/server.log"
|
|
36
|
+
},
|
|
37
|
+
"database": {
|
|
38
|
+
"path": "~/.local-mcp-server/db.sqlite",
|
|
39
|
+
"backup_path": "~/.local-mcp-server/backup/",
|
|
40
|
+
"clean_cycle": 30
|
|
41
|
+
},
|
|
42
|
+
"cli": {
|
|
43
|
+
"cache_time": 300,
|
|
44
|
+
"default_time_range": 7
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# 从文件加载配置
|
|
49
|
+
if config_path.exists():
|
|
50
|
+
try:
|
|
51
|
+
with open(config_path, 'r', encoding='utf-8') as f:
|
|
52
|
+
file_config = json.load(f)
|
|
53
|
+
default_config.update(file_config)
|
|
54
|
+
except Exception as e:
|
|
55
|
+
logger.warning(f"Failed to load config file: {e}, using defaults")
|
|
56
|
+
else:
|
|
57
|
+
logger.info(f"Config file not found at {config_path}, using defaults")
|
|
58
|
+
|
|
59
|
+
# 环境变量覆盖
|
|
60
|
+
env_mappings = {
|
|
61
|
+
"MCP_SERVER_HOST": ("server", "host"),
|
|
62
|
+
"MCP_SERVER_PORT": ("server", "port"),
|
|
63
|
+
"MCP_SERVER_LOG_LEVEL": ("server", "log_level"),
|
|
64
|
+
"MCP_SERVER_LOG_FILE": ("server", "log_file"),
|
|
65
|
+
"MCP_DB_PATH": ("database", "path"),
|
|
66
|
+
"MCP_DB_BACKUP_PATH": ("database", "backup_path"),
|
|
67
|
+
"MCP_DB_CLEAN_CYCLE": ("database", "clean_cycle"),
|
|
68
|
+
"MCP_CLI_CACHE_TIME": ("cli", "cache_time"),
|
|
69
|
+
"MCP_CLI_DEFAULT_TIME_RANGE": ("cli", "default_time_range"),
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
for env_key, (section, key) in env_mappings.items():
|
|
73
|
+
env_value = os.getenv(env_key)
|
|
74
|
+
if env_value is not None:
|
|
75
|
+
if key in ["port", "clean_cycle", "cache_time", "default_time_range"]:
|
|
76
|
+
try:
|
|
77
|
+
env_value = int(env_value)
|
|
78
|
+
except ValueError:
|
|
79
|
+
logger.warning(f"Invalid integer value for {env_key}: {env_value}")
|
|
80
|
+
continue
|
|
81
|
+
default_config[section][key] = env_value
|
|
82
|
+
|
|
83
|
+
# 展开路径中的 ~
|
|
84
|
+
if "database" in default_config:
|
|
85
|
+
db_path = default_config["database"]["path"]
|
|
86
|
+
if db_path.startswith("~"):
|
|
87
|
+
default_config["database"]["path"] = os.path.expanduser(db_path)
|
|
88
|
+
|
|
89
|
+
backup_path = default_config["database"]["backup_path"]
|
|
90
|
+
if backup_path.startswith("~"):
|
|
91
|
+
default_config["database"]["backup_path"] = os.path.expanduser(backup_path)
|
|
92
|
+
|
|
93
|
+
if "server" in default_config and "log_file" in default_config["server"]:
|
|
94
|
+
log_file = default_config["server"]["log_file"]
|
|
95
|
+
if log_file and log_file.startswith("~"):
|
|
96
|
+
default_config["server"]["log_file"] = os.path.expanduser(log_file)
|
|
97
|
+
|
|
98
|
+
_config = default_config
|
|
99
|
+
return _config
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def get_config() -> Dict[str, Any]:
|
|
103
|
+
"""获取配置(懒加载)"""
|
|
104
|
+
return load_config()
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def get_server_config() -> Dict[str, Any]:
|
|
108
|
+
"""获取服务器配置"""
|
|
109
|
+
return get_config()["server"]
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def get_database_config() -> Dict[str, Any]:
|
|
113
|
+
"""获取数据库配置"""
|
|
114
|
+
return get_config()["database"]
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def get_cli_config() -> Dict[str, Any]:
|
|
118
|
+
"""获取CLI配置"""
|
|
119
|
+
return get_config()["cli"]
|
|
120
|
+
|