jarvis-ai-assistant 0.3.30__py3-none-any.whl → 0.7.6__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.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +458 -152
- jarvis/jarvis_agent/agent_manager.py +17 -13
- jarvis/jarvis_agent/builtin_input_handler.py +2 -6
- jarvis/jarvis_agent/config_editor.py +2 -7
- jarvis/jarvis_agent/event_bus.py +82 -12
- jarvis/jarvis_agent/file_context_handler.py +329 -0
- jarvis/jarvis_agent/file_methodology_manager.py +3 -4
- jarvis/jarvis_agent/jarvis.py +628 -55
- jarvis/jarvis_agent/language_extractors/__init__.py +57 -0
- jarvis/jarvis_agent/language_extractors/c_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/cpp_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/go_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/java_extractor.py +84 -0
- jarvis/jarvis_agent/language_extractors/javascript_extractor.py +79 -0
- jarvis/jarvis_agent/language_extractors/python_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/rust_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/typescript_extractor.py +84 -0
- jarvis/jarvis_agent/language_support_info.py +486 -0
- jarvis/jarvis_agent/main.py +34 -10
- jarvis/jarvis_agent/memory_manager.py +7 -16
- jarvis/jarvis_agent/methodology_share_manager.py +10 -16
- jarvis/jarvis_agent/prompt_manager.py +1 -1
- jarvis/jarvis_agent/prompts.py +193 -171
- jarvis/jarvis_agent/protocols.py +8 -12
- jarvis/jarvis_agent/run_loop.py +105 -9
- jarvis/jarvis_agent/session_manager.py +2 -3
- jarvis/jarvis_agent/share_manager.py +20 -22
- jarvis/jarvis_agent/shell_input_handler.py +1 -2
- jarvis/jarvis_agent/stdio_redirect.py +295 -0
- jarvis/jarvis_agent/task_analyzer.py +31 -6
- jarvis/jarvis_agent/task_manager.py +11 -27
- jarvis/jarvis_agent/tool_executor.py +2 -3
- jarvis/jarvis_agent/tool_share_manager.py +12 -24
- jarvis/jarvis_agent/utils.py +5 -1
- jarvis/jarvis_agent/web_bridge.py +189 -0
- jarvis/jarvis_agent/web_output_sink.py +53 -0
- jarvis/jarvis_agent/web_server.py +786 -0
- jarvis/jarvis_c2rust/__init__.py +26 -0
- jarvis/jarvis_c2rust/cli.py +575 -0
- jarvis/jarvis_c2rust/collector.py +250 -0
- jarvis/jarvis_c2rust/constants.py +26 -0
- jarvis/jarvis_c2rust/library_replacer.py +1254 -0
- jarvis/jarvis_c2rust/llm_module_agent.py +1272 -0
- jarvis/jarvis_c2rust/loaders.py +207 -0
- jarvis/jarvis_c2rust/models.py +28 -0
- jarvis/jarvis_c2rust/optimizer.py +2157 -0
- jarvis/jarvis_c2rust/scanner.py +1681 -0
- jarvis/jarvis_c2rust/transpiler.py +2983 -0
- jarvis/jarvis_c2rust/utils.py +385 -0
- jarvis/jarvis_code_agent/build_validation_config.py +132 -0
- jarvis/jarvis_code_agent/code_agent.py +1371 -220
- jarvis/jarvis_code_agent/code_analyzer/__init__.py +65 -0
- jarvis/jarvis_code_agent/code_analyzer/base_language.py +74 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +44 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +106 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +74 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +125 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +72 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +70 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +53 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +47 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +61 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +110 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +154 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +110 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +153 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator.py +43 -0
- jarvis/jarvis_code_agent/code_analyzer/context_manager.py +648 -0
- jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +18 -0
- jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +132 -0
- jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +330 -0
- jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +781 -0
- jarvis/jarvis_code_agent/code_analyzer/language_registry.py +185 -0
- jarvis/jarvis_code_agent/code_analyzer/language_support.py +110 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +49 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +299 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +215 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +212 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +254 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +269 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +281 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +280 -0
- jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +605 -0
- jarvis/jarvis_code_agent/code_analyzer/structured_code.py +556 -0
- jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +252 -0
- jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +58 -0
- jarvis/jarvis_code_agent/lint.py +501 -8
- jarvis/jarvis_code_agent/utils.py +141 -0
- jarvis/jarvis_code_analysis/code_review.py +493 -584
- jarvis/jarvis_data/config_schema.json +128 -12
- jarvis/jarvis_git_squash/main.py +4 -5
- jarvis/jarvis_git_utils/git_commiter.py +82 -75
- jarvis/jarvis_mcp/sse_mcp_client.py +22 -29
- jarvis/jarvis_mcp/stdio_mcp_client.py +12 -13
- jarvis/jarvis_mcp/streamable_mcp_client.py +15 -14
- jarvis/jarvis_memory_organizer/memory_organizer.py +55 -74
- jarvis/jarvis_methodology/main.py +32 -48
- jarvis/jarvis_multi_agent/__init__.py +287 -55
- jarvis/jarvis_multi_agent/main.py +36 -4
- jarvis/jarvis_platform/base.py +524 -202
- jarvis/jarvis_platform/human.py +7 -8
- jarvis/jarvis_platform/kimi.py +30 -36
- jarvis/jarvis_platform/openai.py +88 -25
- jarvis/jarvis_platform/registry.py +26 -10
- jarvis/jarvis_platform/tongyi.py +24 -25
- jarvis/jarvis_platform/yuanbao.py +32 -43
- jarvis/jarvis_platform_manager/main.py +66 -77
- jarvis/jarvis_platform_manager/service.py +8 -13
- jarvis/jarvis_rag/cli.py +53 -55
- jarvis/jarvis_rag/embedding_manager.py +13 -18
- jarvis/jarvis_rag/llm_interface.py +8 -9
- jarvis/jarvis_rag/query_rewriter.py +10 -21
- jarvis/jarvis_rag/rag_pipeline.py +24 -27
- jarvis/jarvis_rag/reranker.py +4 -5
- jarvis/jarvis_rag/retriever.py +28 -30
- jarvis/jarvis_sec/__init__.py +305 -0
- jarvis/jarvis_sec/agents.py +143 -0
- jarvis/jarvis_sec/analysis.py +276 -0
- jarvis/jarvis_sec/checkers/__init__.py +32 -0
- jarvis/jarvis_sec/checkers/c_checker.py +2680 -0
- jarvis/jarvis_sec/checkers/rust_checker.py +1108 -0
- jarvis/jarvis_sec/cli.py +139 -0
- jarvis/jarvis_sec/clustering.py +1439 -0
- jarvis/jarvis_sec/file_manager.py +427 -0
- jarvis/jarvis_sec/parsers.py +73 -0
- jarvis/jarvis_sec/prompts.py +268 -0
- jarvis/jarvis_sec/report.py +336 -0
- jarvis/jarvis_sec/review.py +453 -0
- jarvis/jarvis_sec/status.py +264 -0
- jarvis/jarvis_sec/types.py +20 -0
- jarvis/jarvis_sec/utils.py +499 -0
- jarvis/jarvis_sec/verification.py +848 -0
- jarvis/jarvis_sec/workflow.py +226 -0
- jarvis/jarvis_smart_shell/main.py +38 -87
- jarvis/jarvis_stats/cli.py +2 -2
- jarvis/jarvis_stats/stats.py +8 -8
- jarvis/jarvis_stats/storage.py +15 -21
- jarvis/jarvis_stats/visualizer.py +1 -1
- jarvis/jarvis_tools/clear_memory.py +3 -20
- jarvis/jarvis_tools/cli/main.py +21 -23
- jarvis/jarvis_tools/edit_file.py +1019 -132
- jarvis/jarvis_tools/execute_script.py +83 -25
- jarvis/jarvis_tools/file_analyzer.py +6 -9
- jarvis/jarvis_tools/generate_new_tool.py +14 -21
- jarvis/jarvis_tools/lsp_client.py +1552 -0
- jarvis/jarvis_tools/methodology.py +2 -3
- jarvis/jarvis_tools/read_code.py +1736 -35
- jarvis/jarvis_tools/read_symbols.py +140 -0
- jarvis/jarvis_tools/read_webpage.py +12 -13
- jarvis/jarvis_tools/registry.py +427 -200
- jarvis/jarvis_tools/retrieve_memory.py +20 -19
- jarvis/jarvis_tools/rewrite_file.py +72 -158
- jarvis/jarvis_tools/save_memory.py +3 -15
- jarvis/jarvis_tools/search_web.py +18 -18
- jarvis/jarvis_tools/sub_agent.py +36 -43
- jarvis/jarvis_tools/sub_code_agent.py +25 -26
- jarvis/jarvis_tools/virtual_tty.py +55 -33
- jarvis/jarvis_utils/clipboard.py +7 -10
- jarvis/jarvis_utils/config.py +232 -45
- jarvis/jarvis_utils/embedding.py +8 -5
- jarvis/jarvis_utils/fzf.py +8 -8
- jarvis/jarvis_utils/git_utils.py +225 -36
- jarvis/jarvis_utils/globals.py +3 -3
- jarvis/jarvis_utils/http.py +1 -1
- jarvis/jarvis_utils/input.py +99 -48
- jarvis/jarvis_utils/jsonnet_compat.py +465 -0
- jarvis/jarvis_utils/methodology.py +52 -48
- jarvis/jarvis_utils/utils.py +819 -491
- jarvis_ai_assistant-0.7.6.dist-info/METADATA +600 -0
- jarvis_ai_assistant-0.7.6.dist-info/RECORD +218 -0
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/entry_points.txt +4 -0
- jarvis/jarvis_agent/config.py +0 -92
- jarvis/jarvis_agent/edit_file_handler.py +0 -296
- jarvis/jarvis_platform/ai8.py +0 -332
- jarvis/jarvis_tools/ask_user.py +0 -54
- jarvis_ai_assistant-0.3.30.dist-info/METADATA +0 -381
- jarvis_ai_assistant-0.3.30.dist-info/RECORD +0 -137
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Jarvis C2Rust 工具集。
|
|
4
|
+
|
|
5
|
+
核心数据:
|
|
6
|
+
- 统一符号表(JSONL):<project_root>/.jarvis/c2rust/symbols.jsonl(后续流程的主输入)
|
|
7
|
+
- 原始符号表(JSONL):<project_root>/.jarvis/c2rust/symbols_raw.jsonl
|
|
8
|
+
- 其他产物:translation_order.jsonl、library_replacements.jsonl、progress.json、config.json、symbol_map.jsonl 等
|
|
9
|
+
|
|
10
|
+
推荐用法(CLI):
|
|
11
|
+
- 配置管理: jarvis-c2rust config --files <hdrs...> [--root-list-syms ...] [--disabled-libs ...]
|
|
12
|
+
- 扫描: jarvis-c2rust scan
|
|
13
|
+
- 库替代评估: jarvis-c2rust lib-replace [-g <llm-group>]
|
|
14
|
+
- 规划/落盘: jarvis-c2rust prepare [-g <llm-group>]
|
|
15
|
+
- 转译: jarvis-c2rust transpile [-g <llm-group>] [-m <max-retries>](断点续跑默认始终启用)
|
|
16
|
+
- 代码优化: jarvis-c2rust optimize [--crate-dir ...] [--unsafe/--no-unsafe] [--structure/--no-structure] [--visibility/--no-visibility] [--doc/--no-doc] [-m N] [--dry-run]
|
|
17
|
+
- 一键流水线: jarvis-c2rust run [-g <llm-group>] [-m <max-retries>]
|
|
18
|
+
|
|
19
|
+
或(模块方式):
|
|
20
|
+
python -m jarvis.jarvis_c2rust.cli <subcommand>
|
|
21
|
+
|
|
22
|
+
说明:
|
|
23
|
+
- 所有路径均推荐使用 <project_root>/.jarvis/c2rust 下的标准文件名,便于断点续跑与复用。
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
__all__ = ["scanner", "optimizer"]
|
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
C2Rust 独立命令行入口。
|
|
4
|
+
|
|
5
|
+
提供分组式 CLI:
|
|
6
|
+
- jarvis-c2rust run: 执行完整的转译流水线(scan -> lib-replace -> prepare -> transpile -> optimize),支持断点续跑
|
|
7
|
+
- jarvis-c2rust config: 管理转译配置文件(根符号列表、禁用库列表、附加说明等)
|
|
8
|
+
|
|
9
|
+
实现策略:
|
|
10
|
+
- 使用 Typer 分组式结构,便于后续扩展更多子命令(如 analyze/export 等)。
|
|
11
|
+
- run 命令支持断点续跑,根据状态文件自动跳过已完成的阶段。
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Optional, List
|
|
19
|
+
|
|
20
|
+
import typer
|
|
21
|
+
from jarvis.jarvis_c2rust.scanner import run_scan as _run_scan
|
|
22
|
+
from jarvis.jarvis_c2rust.library_replacer import (
|
|
23
|
+
apply_library_replacement as _apply_library_replacement,
|
|
24
|
+
)
|
|
25
|
+
from jarvis.jarvis_utils.utils import init_env
|
|
26
|
+
from jarvis.jarvis_c2rust.llm_module_agent import (
|
|
27
|
+
execute_llm_plan as _execute_llm_plan,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _check_optimize_completed(crate_dir: Path) -> bool:
|
|
32
|
+
"""
|
|
33
|
+
检查优化是否真正完成。
|
|
34
|
+
需要检查 optimize_progress.json 中所有必要的步骤是否都完成了。
|
|
35
|
+
特别是 clippy_elimination:如果有告警,必须完成;如果没有告警,可以跳过。
|
|
36
|
+
"""
|
|
37
|
+
import json
|
|
38
|
+
from jarvis.jarvis_c2rust.constants import C2RUST_DIRNAME
|
|
39
|
+
|
|
40
|
+
progress_path = crate_dir / C2RUST_DIRNAME / "optimize_progress.json"
|
|
41
|
+
if not progress_path.exists():
|
|
42
|
+
# 如果没有进度文件,说明还没开始,不算完成
|
|
43
|
+
return False
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
with progress_path.open("r", encoding="utf-8") as f:
|
|
47
|
+
progress = json.load(f)
|
|
48
|
+
|
|
49
|
+
steps_completed = set(progress.get("steps_completed", []))
|
|
50
|
+
|
|
51
|
+
# 检查是否有 clippy 告警
|
|
52
|
+
# 直接调用 optimizer 模块中的函数(虽然是私有函数,但我们需要它来检查)
|
|
53
|
+
import subprocess
|
|
54
|
+
try:
|
|
55
|
+
res = subprocess.run(
|
|
56
|
+
["cargo", "clippy", "--", "-W", "clippy::all"],
|
|
57
|
+
capture_output=True,
|
|
58
|
+
text=True,
|
|
59
|
+
check=False,
|
|
60
|
+
cwd=str(crate_dir),
|
|
61
|
+
)
|
|
62
|
+
stderr_output = (res.stderr or "").strip()
|
|
63
|
+
stdout_output = (res.stdout or "").strip()
|
|
64
|
+
output = (stderr_output + "\n" + stdout_output).strip() if (stderr_output and stdout_output) else (stderr_output or stdout_output or "").strip()
|
|
65
|
+
output_lower = output.lower()
|
|
66
|
+
has_warnings = "warning:" in output_lower or "warn(" in output_lower or ("clippy::" in output_lower and res.returncode != 0)
|
|
67
|
+
except Exception:
|
|
68
|
+
# 如果检查失败,保守地认为有告警(需要完成)
|
|
69
|
+
has_warnings = True
|
|
70
|
+
|
|
71
|
+
# 如果有告警,clippy_elimination 必须在 steps_completed 中
|
|
72
|
+
if has_warnings:
|
|
73
|
+
if "clippy_elimination" not in steps_completed:
|
|
74
|
+
return False
|
|
75
|
+
|
|
76
|
+
# 检查其他必要的步骤(根据 enable_* 选项,但这里我们假设都启用了)
|
|
77
|
+
# 注意:这里我们只检查 clippy_elimination,其他步骤(unsafe_cleanup, visibility_opt, doc_opt)
|
|
78
|
+
# 可能因为 enable_* 选项而未执行,所以不强制要求
|
|
79
|
+
|
|
80
|
+
return True
|
|
81
|
+
except Exception:
|
|
82
|
+
# 如果读取失败,保守地认为未完成
|
|
83
|
+
return False
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
app = typer.Typer(help="C2Rust 命令行工具")
|
|
87
|
+
|
|
88
|
+
# 显式定义根回调,确保为命令组而非单函数入口
|
|
89
|
+
@app.callback()
|
|
90
|
+
def _root():
|
|
91
|
+
"""
|
|
92
|
+
C2Rust 命令行工具
|
|
93
|
+
"""
|
|
94
|
+
# 设置环境变量,标识当前运行在 c2rust 环境中
|
|
95
|
+
os.environ["JARVIS_C2RUST_ENABLED"] = "1"
|
|
96
|
+
# 不做任何处理,仅作为命令组的占位,使 'scan' 作为子命令出现
|
|
97
|
+
init_env("")
|
|
98
|
+
pass
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _load_config() -> dict:
|
|
102
|
+
"""
|
|
103
|
+
从配置文件加载配置。
|
|
104
|
+
返回包含 root_symbols、disabled_libraries 和 additional_notes 的字典。
|
|
105
|
+
"""
|
|
106
|
+
import json
|
|
107
|
+
from jarvis.jarvis_c2rust.constants import CONFIG_JSON, C2RUST_DIRNAME
|
|
108
|
+
|
|
109
|
+
data_dir = Path(".") / C2RUST_DIRNAME
|
|
110
|
+
config_path = data_dir / CONFIG_JSON
|
|
111
|
+
default_config = {"root_symbols": [], "disabled_libraries": [], "additional_notes": ""}
|
|
112
|
+
|
|
113
|
+
if not config_path.exists():
|
|
114
|
+
return default_config
|
|
115
|
+
|
|
116
|
+
try:
|
|
117
|
+
with config_path.open("r", encoding="utf-8") as f:
|
|
118
|
+
config = json.load(f)
|
|
119
|
+
if not isinstance(config, dict):
|
|
120
|
+
return default_config
|
|
121
|
+
# 确保包含所有必需的键
|
|
122
|
+
return {
|
|
123
|
+
"root_symbols": config.get("root_symbols", []),
|
|
124
|
+
"disabled_libraries": config.get("disabled_libraries", []),
|
|
125
|
+
"additional_notes": config.get("additional_notes", ""),
|
|
126
|
+
}
|
|
127
|
+
except Exception:
|
|
128
|
+
return default_config
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
RUN_STATE_JSON = "run_state.json"
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _get_run_state_path() -> Path:
|
|
135
|
+
"""获取 run 状态文件路径"""
|
|
136
|
+
from jarvis.jarvis_c2rust.constants import C2RUST_DIRNAME
|
|
137
|
+
data_dir = Path(".") / C2RUST_DIRNAME
|
|
138
|
+
return data_dir / RUN_STATE_JSON
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _load_run_state() -> dict:
|
|
142
|
+
"""加载 run 状态文件"""
|
|
143
|
+
import json
|
|
144
|
+
|
|
145
|
+
state_path = _get_run_state_path()
|
|
146
|
+
default_state = {
|
|
147
|
+
"scan": {"completed": False, "timestamp": None},
|
|
148
|
+
"lib_replace": {"completed": False, "timestamp": None},
|
|
149
|
+
"prepare": {"completed": False, "timestamp": None},
|
|
150
|
+
"transpile": {"completed": False, "timestamp": None},
|
|
151
|
+
"optimize": {"completed": False, "timestamp": None},
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if not state_path.exists():
|
|
155
|
+
return default_state
|
|
156
|
+
|
|
157
|
+
try:
|
|
158
|
+
with state_path.open("r", encoding="utf-8") as f:
|
|
159
|
+
state = json.load(f)
|
|
160
|
+
if not isinstance(state, dict):
|
|
161
|
+
return default_state
|
|
162
|
+
# 确保包含所有必需的阶段
|
|
163
|
+
for stage in ["scan", "lib_replace", "prepare", "transpile", "optimize"]:
|
|
164
|
+
if stage not in state:
|
|
165
|
+
state[stage] = {"completed": False, "timestamp": None}
|
|
166
|
+
return state
|
|
167
|
+
except Exception:
|
|
168
|
+
return default_state
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _save_run_state(stage: str, completed: bool = True) -> None:
|
|
172
|
+
"""保存 run 状态文件"""
|
|
173
|
+
import json
|
|
174
|
+
import time
|
|
175
|
+
|
|
176
|
+
state_path = _get_run_state_path()
|
|
177
|
+
state = _load_run_state()
|
|
178
|
+
|
|
179
|
+
state[stage] = {
|
|
180
|
+
"completed": completed,
|
|
181
|
+
"timestamp": time.strftime("%Y-%m-%dT%H:%M:%S", time.localtime()) if completed else None,
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
try:
|
|
185
|
+
state_path.parent.mkdir(parents=True, exist_ok=True)
|
|
186
|
+
with state_path.open("w", encoding="utf-8") as f:
|
|
187
|
+
json.dump(state, f, ensure_ascii=False, indent=2)
|
|
188
|
+
except Exception as e:
|
|
189
|
+
typer.secho(f"[c2rust-run] 保存状态文件失败: {e}", fg=typer.colors.YELLOW, err=True)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
@app.command("config")
|
|
193
|
+
def config(
|
|
194
|
+
files: Optional[List[Path]] = typer.Option(
|
|
195
|
+
None, "--files", help="头文件(.h/.hh/.hpp/.hxx)或函数名列表文件(每行一个函数名,忽略空行与以#开头的注释)"
|
|
196
|
+
),
|
|
197
|
+
root_list_syms: Optional[str] = typer.Option(
|
|
198
|
+
None, "--root-list-syms", help="根符号列表内联(逗号分隔)"
|
|
199
|
+
),
|
|
200
|
+
disabled_libs: Optional[str] = typer.Option(
|
|
201
|
+
None, "--disabled-libs", help="禁用库列表(逗号分隔)"
|
|
202
|
+
),
|
|
203
|
+
additional_notes: Optional[str] = typer.Option(
|
|
204
|
+
None, "--additional-notes", help="附加说明(将在所有 agent 的提示词中追加)"
|
|
205
|
+
),
|
|
206
|
+
show: bool = typer.Option(
|
|
207
|
+
False, "--show", help="显示当前配置内容"
|
|
208
|
+
),
|
|
209
|
+
clear: bool = typer.Option(
|
|
210
|
+
False, "--clear", help="清空配置(重置为默认值)"
|
|
211
|
+
),
|
|
212
|
+
) -> None:
|
|
213
|
+
"""
|
|
214
|
+
管理转译配置文件(.jarvis/c2rust/config.json)。
|
|
215
|
+
|
|
216
|
+
可以设置根符号列表(root_symbols)、禁用库列表(disabled_libraries)和附加说明(additional_notes)。
|
|
217
|
+
这些配置会被 transpile 命令自动读取和使用。
|
|
218
|
+
|
|
219
|
+
示例:
|
|
220
|
+
# 从头文件自动提取函数名并设置根符号列表
|
|
221
|
+
jarvis-c2rust config --files bzlib.h
|
|
222
|
+
|
|
223
|
+
# 从多个头文件提取函数名
|
|
224
|
+
jarvis-c2rust config --files a.h b.hpp c.hxx
|
|
225
|
+
|
|
226
|
+
# 从函数名列表文件设置根符号列表
|
|
227
|
+
jarvis-c2rust config --files roots.txt
|
|
228
|
+
|
|
229
|
+
# 从命令行设置根符号列表
|
|
230
|
+
jarvis-c2rust config --root-list-syms "func1,func2,func3"
|
|
231
|
+
|
|
232
|
+
# 设置禁用库列表
|
|
233
|
+
jarvis-c2rust config --disabled-libs "libc,libm"
|
|
234
|
+
|
|
235
|
+
# 设置附加说明(将在所有 agent 的提示词中追加)
|
|
236
|
+
jarvis-c2rust config --additional-notes "注意:所有函数必须处理错误情况,避免 panic"
|
|
237
|
+
|
|
238
|
+
# 同时设置多个参数
|
|
239
|
+
jarvis-c2rust config --files bzlib.h --disabled-libs "libc" --additional-notes "特殊要求说明"
|
|
240
|
+
|
|
241
|
+
# 查看当前配置
|
|
242
|
+
jarvis-c2rust config --show
|
|
243
|
+
|
|
244
|
+
# 清空配置
|
|
245
|
+
jarvis-c2rust config --clear
|
|
246
|
+
"""
|
|
247
|
+
import json
|
|
248
|
+
from jarvis.jarvis_c2rust.constants import CONFIG_JSON, C2RUST_DIRNAME
|
|
249
|
+
|
|
250
|
+
data_dir = Path(".") / C2RUST_DIRNAME
|
|
251
|
+
config_path = data_dir / CONFIG_JSON
|
|
252
|
+
data_dir.mkdir(parents=True, exist_ok=True)
|
|
253
|
+
|
|
254
|
+
# 读取现有配置
|
|
255
|
+
default_config = {"root_symbols": [], "disabled_libraries": [], "additional_notes": ""}
|
|
256
|
+
current_config = default_config.copy()
|
|
257
|
+
|
|
258
|
+
if config_path.exists():
|
|
259
|
+
try:
|
|
260
|
+
with config_path.open("r", encoding="utf-8") as f:
|
|
261
|
+
current_config = json.load(f)
|
|
262
|
+
if not isinstance(current_config, dict):
|
|
263
|
+
current_config = default_config.copy()
|
|
264
|
+
except Exception as e:
|
|
265
|
+
typer.secho(f"[c2rust-config] 读取现有配置失败: {e},将使用默认值", fg=typer.colors.YELLOW)
|
|
266
|
+
current_config = default_config.copy()
|
|
267
|
+
|
|
268
|
+
# 如果只是查看配置
|
|
269
|
+
if show:
|
|
270
|
+
typer.secho(f"[c2rust-config] 当前配置文件: {config_path}", fg=typer.colors.BLUE)
|
|
271
|
+
typer.secho(json.dumps(current_config, ensure_ascii=False, indent=2), fg=typer.colors.CYAN)
|
|
272
|
+
return
|
|
273
|
+
|
|
274
|
+
# 如果清空配置
|
|
275
|
+
if clear:
|
|
276
|
+
current_config = default_config.copy()
|
|
277
|
+
with config_path.open("w", encoding="utf-8") as f:
|
|
278
|
+
json.dump(current_config, f, ensure_ascii=False, indent=2)
|
|
279
|
+
typer.secho(f"[c2rust-config] 配置已清空: {config_path}", fg=typer.colors.GREEN)
|
|
280
|
+
return
|
|
281
|
+
|
|
282
|
+
# 读取根符号列表(从现有配置开始,以便追加而不是替换)
|
|
283
|
+
root_symbols: List[str] = list(current_config.get("root_symbols", []))
|
|
284
|
+
header_exts = {".h", ".hh", ".hpp", ".hxx"}
|
|
285
|
+
|
|
286
|
+
if files:
|
|
287
|
+
for file_path in files:
|
|
288
|
+
try:
|
|
289
|
+
file_path = Path(file_path).resolve()
|
|
290
|
+
if not file_path.exists():
|
|
291
|
+
typer.secho(f"[c2rust-config] 警告: 文件不存在,跳过: {file_path}", fg=typer.colors.YELLOW)
|
|
292
|
+
continue
|
|
293
|
+
|
|
294
|
+
# 检查是否是头文件
|
|
295
|
+
if file_path.suffix.lower() in header_exts:
|
|
296
|
+
# 从头文件提取函数名
|
|
297
|
+
typer.secho(f"[c2rust-config] 从头文件提取函数名: {file_path}", fg=typer.colors.BLUE)
|
|
298
|
+
try:
|
|
299
|
+
from jarvis.jarvis_c2rust.collector import collect_function_names as _collect_fn_names
|
|
300
|
+
# 使用临时文件存储提取的函数名
|
|
301
|
+
import tempfile
|
|
302
|
+
with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False, encoding='utf-8') as tmp:
|
|
303
|
+
tmp_path = Path(tmp.name)
|
|
304
|
+
_collect_fn_names(files=[file_path], out_path=tmp_path, compile_commands_root=None)
|
|
305
|
+
# 读取提取的函数名
|
|
306
|
+
txt = tmp_path.read_text(encoding="utf-8")
|
|
307
|
+
collected = [ln.strip() for ln in txt.splitlines() if ln.strip()]
|
|
308
|
+
root_symbols.extend(collected)
|
|
309
|
+
typer.secho(f"[c2rust-config] 从头文件 {file_path.name} 提取了 {len(collected)} 个函数名", fg=typer.colors.GREEN)
|
|
310
|
+
# 清理临时文件
|
|
311
|
+
try:
|
|
312
|
+
tmp_path.unlink()
|
|
313
|
+
except Exception:
|
|
314
|
+
pass
|
|
315
|
+
except Exception as e:
|
|
316
|
+
typer.secho(f"[c2rust-config] 从头文件提取函数名失败: {file_path}: {e}", fg=typer.colors.RED, err=True)
|
|
317
|
+
raise typer.Exit(code=1)
|
|
318
|
+
else:
|
|
319
|
+
# 读取函数名列表文件(每行一个函数名)
|
|
320
|
+
txt = file_path.read_text(encoding="utf-8")
|
|
321
|
+
collected = [ln.strip() for ln in txt.splitlines() if ln.strip() and not ln.strip().startswith("#")]
|
|
322
|
+
root_symbols.extend(collected)
|
|
323
|
+
typer.secho(f"[c2rust-config] 从文件 {file_path.name} 读取了 {len(collected)} 个根符号", fg=typer.colors.BLUE)
|
|
324
|
+
except typer.Exit:
|
|
325
|
+
raise
|
|
326
|
+
except Exception as e:
|
|
327
|
+
typer.secho(f"[c2rust-config] 处理文件失败: {file_path}: {e}", fg=typer.colors.RED, err=True)
|
|
328
|
+
raise typer.Exit(code=1)
|
|
329
|
+
|
|
330
|
+
# 标记是否处理了 root_list_syms,以便即使结果为空也更新配置
|
|
331
|
+
processed_root_list_syms = False
|
|
332
|
+
if isinstance(root_list_syms, str) and root_list_syms.strip():
|
|
333
|
+
parts = [s.strip() for s in root_list_syms.replace("\n", ",").split(",") if s.strip()]
|
|
334
|
+
root_symbols.extend(parts)
|
|
335
|
+
processed_root_list_syms = True
|
|
336
|
+
typer.secho(f"[c2rust-config] 从命令行读取根符号: {len(parts)} 个", fg=typer.colors.BLUE)
|
|
337
|
+
|
|
338
|
+
# 去重根符号列表(如果处理了 files 或 root_list_syms,或者 root_symbols 非空,则更新配置)
|
|
339
|
+
if files or processed_root_list_syms or root_symbols:
|
|
340
|
+
try:
|
|
341
|
+
root_symbols = list(dict.fromkeys(root_symbols))
|
|
342
|
+
except Exception:
|
|
343
|
+
root_symbols = sorted(list(set(root_symbols)))
|
|
344
|
+
current_config["root_symbols"] = root_symbols
|
|
345
|
+
typer.secho(f"[c2rust-config] 已设置根符号列表: {len(root_symbols)} 个", fg=typer.colors.GREEN)
|
|
346
|
+
|
|
347
|
+
# 读取禁用库列表
|
|
348
|
+
if isinstance(disabled_libs, str) and disabled_libs.strip():
|
|
349
|
+
disabled_list = [s.strip() for s in disabled_libs.replace("\n", ",").split(",") if s.strip()]
|
|
350
|
+
if disabled_list:
|
|
351
|
+
current_config["disabled_libraries"] = disabled_list
|
|
352
|
+
typer.secho(f"[c2rust-config] 已设置禁用库列表: {', '.join(disabled_list)}", fg=typer.colors.GREEN)
|
|
353
|
+
|
|
354
|
+
# 读取附加说明
|
|
355
|
+
if isinstance(additional_notes, str):
|
|
356
|
+
current_config["additional_notes"] = additional_notes.strip()
|
|
357
|
+
if additional_notes.strip():
|
|
358
|
+
typer.secho(f"[c2rust-config] 已设置附加说明: {len(additional_notes.strip())} 字符", fg=typer.colors.GREEN)
|
|
359
|
+
else:
|
|
360
|
+
typer.secho("[c2rust-config] 已清空附加说明", fg=typer.colors.GREEN)
|
|
361
|
+
|
|
362
|
+
# 如果没有提供任何参数,提示用户
|
|
363
|
+
if not files and not root_list_syms and not disabled_libs and additional_notes is None:
|
|
364
|
+
typer.secho("[c2rust-config] 未提供任何参数,使用 --show 查看当前配置,或使用 --help 查看帮助", fg=typer.colors.YELLOW)
|
|
365
|
+
return
|
|
366
|
+
|
|
367
|
+
# 保存配置
|
|
368
|
+
try:
|
|
369
|
+
with config_path.open("w", encoding="utf-8") as f:
|
|
370
|
+
json.dump(current_config, f, ensure_ascii=False, indent=2)
|
|
371
|
+
typer.secho(f"[c2rust-config] 配置已保存: {config_path}", fg=typer.colors.GREEN)
|
|
372
|
+
typer.secho(json.dumps(current_config, ensure_ascii=False, indent=2), fg=typer.colors.CYAN)
|
|
373
|
+
except Exception as e:
|
|
374
|
+
typer.secho(f"[c2rust-config] 保存配置失败: {e}", fg=typer.colors.RED, err=True)
|
|
375
|
+
raise typer.Exit(code=1)
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
@app.command("run")
|
|
379
|
+
def run(
|
|
380
|
+
llm_group: Optional[str] = typer.Option(
|
|
381
|
+
None,
|
|
382
|
+
"-g",
|
|
383
|
+
"--llm-group",
|
|
384
|
+
help="用于 LLM 相关阶段(lib-replace/prepare/transpile/optimize)的模型组",
|
|
385
|
+
),
|
|
386
|
+
max_retries: int = typer.Option(
|
|
387
|
+
0, "-m", "--max-retries", help="transpile 构建/修复与审查的最大重试次数(0 表示不限制)"
|
|
388
|
+
),
|
|
389
|
+
interactive: bool = typer.Option(
|
|
390
|
+
False,
|
|
391
|
+
"--interactive",
|
|
392
|
+
help="启用交互模式(默认非交互模式)",
|
|
393
|
+
),
|
|
394
|
+
reset: bool = typer.Option(
|
|
395
|
+
False,
|
|
396
|
+
"--reset",
|
|
397
|
+
help="重置状态,从头开始执行所有阶段",
|
|
398
|
+
),
|
|
399
|
+
) -> None:
|
|
400
|
+
"""
|
|
401
|
+
依次执行流水线:scan -> lib-replace -> prepare -> transpile -> optimize
|
|
402
|
+
|
|
403
|
+
支持断点续跑:根据状态文件(.jarvis/c2rust/run_state.json)自动跳过已完成的阶段。
|
|
404
|
+
|
|
405
|
+
约束:
|
|
406
|
+
|
|
407
|
+
- 根符号列表和禁用库列表从配置文件(.jarvis/c2rust/config.json)读取
|
|
408
|
+
使用 jarvis-c2rust config 命令设置这些配置(例如:jarvis-c2rust config --files bzlib.h)
|
|
409
|
+
|
|
410
|
+
- 使用 --reset 可以重置状态,从头开始执行所有阶段
|
|
411
|
+
|
|
412
|
+
- prepare/transpile 会使用 --llm-group 指定的模型组
|
|
413
|
+
|
|
414
|
+
- optimize 阶段采用默认优化配置,自动检测 crate 根目录并进行保守优化(unsafe 清理、结构优化、可见性优化、文档补充)
|
|
415
|
+
"""
|
|
416
|
+
|
|
417
|
+
try:
|
|
418
|
+
# 加载状态文件
|
|
419
|
+
if reset:
|
|
420
|
+
# 重置状态
|
|
421
|
+
state_path = _get_run_state_path()
|
|
422
|
+
if state_path.exists():
|
|
423
|
+
state_path.unlink()
|
|
424
|
+
typer.secho("[c2rust-run] 已重置状态,将从头开始执行", fg=typer.colors.YELLOW)
|
|
425
|
+
state = _load_run_state()
|
|
426
|
+
else:
|
|
427
|
+
state = _load_run_state()
|
|
428
|
+
# 显示当前状态
|
|
429
|
+
completed_stages = [s for s, info in state.items() if info.get("completed", False)]
|
|
430
|
+
if completed_stages:
|
|
431
|
+
typer.secho(f"[c2rust-run] 检测到已完成阶段: {', '.join(completed_stages)},将从断点继续", fg=typer.colors.CYAN)
|
|
432
|
+
|
|
433
|
+
# Step 1: scan
|
|
434
|
+
if not state.get("scan", {}).get("completed", False):
|
|
435
|
+
typer.secho("[c2rust-run] scan: 开始", fg=typer.colors.BLUE)
|
|
436
|
+
_run_scan(dot=None, only_dot=False, subgraphs_dir=None, only_subgraphs=False, png=False, non_interactive=True)
|
|
437
|
+
typer.secho("[c2rust-run] scan: 完成", fg=typer.colors.GREEN)
|
|
438
|
+
# 保存状态(因为直接调用 _run_scan 函数,需要手动保存状态)
|
|
439
|
+
_save_run_state("scan", completed=True)
|
|
440
|
+
else:
|
|
441
|
+
typer.secho("[c2rust-run] scan: 已完成,跳过", fg=typer.colors.CYAN)
|
|
442
|
+
|
|
443
|
+
# Step 2: lib-replace(从配置文件读取根列表和禁用库列表)
|
|
444
|
+
if not state.get("lib_replace", {}).get("completed", False):
|
|
445
|
+
# 从配置文件读取基础配置
|
|
446
|
+
config = _load_config()
|
|
447
|
+
root_names: List[str] = list(config.get("root_symbols", []))
|
|
448
|
+
disabled_list: Optional[List[str]] = config.get("disabled_libraries", []) or None
|
|
449
|
+
|
|
450
|
+
# 去重并校验(允许为空时回退为自动根集)
|
|
451
|
+
if root_names:
|
|
452
|
+
try:
|
|
453
|
+
root_names = list(dict.fromkeys(root_names))
|
|
454
|
+
except Exception:
|
|
455
|
+
root_names = sorted(list(set(root_names)))
|
|
456
|
+
|
|
457
|
+
candidates_list: Optional[List[str]] = root_names if root_names else None
|
|
458
|
+
if not candidates_list:
|
|
459
|
+
typer.secho("[c2rust-run] lib-replace: 根列表为空,将回退为自动检测的根集合(基于扫描结果)", fg=typer.colors.YELLOW)
|
|
460
|
+
|
|
461
|
+
if disabled_list:
|
|
462
|
+
typer.secho(f"[c2rust-run] lib-replace: 从配置文件读取禁用库: {', '.join(disabled_list)}", fg=typer.colors.BLUE)
|
|
463
|
+
|
|
464
|
+
# 执行 lib-replace(默认库 std)
|
|
465
|
+
library = "std"
|
|
466
|
+
root_count_str = str(len(candidates_list)) if candidates_list is not None else "auto"
|
|
467
|
+
typer.secho(f"[c2rust-run] lib-replace: 开始(库: {library},根数: {root_count_str})", fg=typer.colors.BLUE)
|
|
468
|
+
ret = _apply_library_replacement(
|
|
469
|
+
db_path=Path("."),
|
|
470
|
+
library_name=library,
|
|
471
|
+
llm_group=llm_group,
|
|
472
|
+
candidates=candidates_list, # None 表示自动检测全部根
|
|
473
|
+
out_symbols_path=None,
|
|
474
|
+
out_mapping_path=None,
|
|
475
|
+
max_funcs=None,
|
|
476
|
+
disabled_libraries=disabled_list,
|
|
477
|
+
non_interactive=not interactive,
|
|
478
|
+
)
|
|
479
|
+
try:
|
|
480
|
+
order_msg = f"\n[c2rust-run] lib-replace: 转译顺序: {ret['order']}" if 'order' in ret else ""
|
|
481
|
+
typer.secho(
|
|
482
|
+
f"[c2rust-run] lib-replace: 替代映射: {ret['mapping']}\n"
|
|
483
|
+
f"[c2rust-run] lib-replace: 新符号表: {ret['symbols']}"
|
|
484
|
+
+ order_msg,
|
|
485
|
+
fg=typer.colors.GREEN,
|
|
486
|
+
)
|
|
487
|
+
except Exception as _e:
|
|
488
|
+
typer.secho(f"[c2rust-run] lib-replace: 结果输出时发生非致命错误: {_e}", fg=typer.colors.YELLOW, err=True)
|
|
489
|
+
# 保存状态(因为直接调用 _apply_library_replacement 函数,需要手动保存状态)
|
|
490
|
+
_save_run_state("lib_replace", completed=True)
|
|
491
|
+
else:
|
|
492
|
+
typer.secho("[c2rust-run] lib-replace: 已完成,跳过", fg=typer.colors.CYAN)
|
|
493
|
+
|
|
494
|
+
# Step 3: prepare
|
|
495
|
+
if not state.get("prepare", {}).get("completed", False):
|
|
496
|
+
typer.secho("[c2rust-run] prepare: 开始", fg=typer.colors.BLUE)
|
|
497
|
+
_execute_llm_plan(apply=True, llm_group=llm_group, non_interactive=not interactive)
|
|
498
|
+
typer.secho("[c2rust-run] prepare: 完成", fg=typer.colors.GREEN)
|
|
499
|
+
# 保存状态(因为直接调用 _execute_llm_plan 函数,需要手动保存状态)
|
|
500
|
+
_save_run_state("prepare", completed=True)
|
|
501
|
+
else:
|
|
502
|
+
typer.secho("[c2rust-run] prepare: 已完成,跳过", fg=typer.colors.CYAN)
|
|
503
|
+
|
|
504
|
+
# Step 4: transpile
|
|
505
|
+
if not state.get("transpile", {}).get("completed", False):
|
|
506
|
+
typer.secho("[c2rust-run] transpile: 开始", fg=typer.colors.BLUE)
|
|
507
|
+
from jarvis.jarvis_c2rust.transpiler import run_transpile as _run_transpile
|
|
508
|
+
# 从配置文件读取配置(transpile 内部会自动读取)
|
|
509
|
+
_run_transpile(
|
|
510
|
+
project_root=Path("."),
|
|
511
|
+
crate_dir=None,
|
|
512
|
+
llm_group=llm_group,
|
|
513
|
+
max_retries=max_retries,
|
|
514
|
+
disabled_libraries=None, # 从配置文件恢复
|
|
515
|
+
root_symbols=None, # 从配置文件恢复
|
|
516
|
+
non_interactive=not interactive,
|
|
517
|
+
)
|
|
518
|
+
typer.secho("[c2rust-run] transpile: 完成", fg=typer.colors.GREEN)
|
|
519
|
+
# 保存状态(因为直接调用 _run_transpile 函数,需要手动保存状态)
|
|
520
|
+
_save_run_state("transpile", completed=True)
|
|
521
|
+
else:
|
|
522
|
+
typer.secho("[c2rust-run] transpile: 已完成,跳过", fg=typer.colors.CYAN)
|
|
523
|
+
|
|
524
|
+
# Step 5: optimize
|
|
525
|
+
if not state.get("optimize", {}).get("completed", False):
|
|
526
|
+
try:
|
|
527
|
+
typer.secho("[c2rust-run] optimize: 开始", fg=typer.colors.BLUE)
|
|
528
|
+
from jarvis.jarvis_c2rust.optimizer import optimize_project as _optimize_project
|
|
529
|
+
from jarvis.jarvis_c2rust.utils import default_crate_dir
|
|
530
|
+
# 使用与 transpile 相同的逻辑确定项目根目录和 crate 目录
|
|
531
|
+
project_root = Path(".")
|
|
532
|
+
crate_dir = default_crate_dir(project_root)
|
|
533
|
+
typer.secho(f"[c2rust-run] optimize: 使用项目根目录: {project_root}, crate 目录: {crate_dir}", fg=typer.colors.CYAN)
|
|
534
|
+
res = _optimize_project(project_root=project_root, crate_dir=crate_dir, llm_group=llm_group, non_interactive=not interactive)
|
|
535
|
+
summary = (
|
|
536
|
+
f"[c2rust-run] optimize: 结果摘要:\n"
|
|
537
|
+
f" files_scanned: {res.get('files_scanned')}\n"
|
|
538
|
+
f" unsafe_removed: {res.get('unsafe_removed')}\n"
|
|
539
|
+
f" unsafe_annotated: {res.get('unsafe_annotated')}\n"
|
|
540
|
+
f" visibility_downgraded: {res.get('visibility_downgraded')}\n"
|
|
541
|
+
f" docs_added: {res.get('docs_added')}\n"
|
|
542
|
+
f" cargo_checks: {res.get('cargo_checks')}\n"
|
|
543
|
+
)
|
|
544
|
+
typer.secho(summary, fg=typer.colors.GREEN)
|
|
545
|
+
|
|
546
|
+
# 检查优化是否真正完成(所有步骤都完成,包括 clippy 告警修复)
|
|
547
|
+
optimize_truly_completed = _check_optimize_completed(crate_dir)
|
|
548
|
+
if optimize_truly_completed:
|
|
549
|
+
typer.secho("[c2rust-run] optimize: 完成", fg=typer.colors.GREEN)
|
|
550
|
+
# 保存状态(因为直接调用 _optimize_project 函数,需要手动保存状态)
|
|
551
|
+
_save_run_state("optimize", completed=True)
|
|
552
|
+
else:
|
|
553
|
+
typer.secho("[c2rust-run] optimize: 部分步骤未完成(如 clippy 告警未完全修复),下次将继续", fg=typer.colors.YELLOW)
|
|
554
|
+
# 不保存状态,下次恢复时会继续执行优化
|
|
555
|
+
except Exception as _e:
|
|
556
|
+
typer.secho(f"[c2rust-run] optimize: 错误: {_e}", fg=typer.colors.RED, err=True)
|
|
557
|
+
raise
|
|
558
|
+
else:
|
|
559
|
+
typer.secho("[c2rust-run] optimize: 已完成,跳过", fg=typer.colors.CYAN)
|
|
560
|
+
|
|
561
|
+
# 所有阶段完成
|
|
562
|
+
typer.secho("[c2rust-run] 所有阶段已完成!", fg=typer.colors.GREEN)
|
|
563
|
+
except Exception as e:
|
|
564
|
+
typer.secho(f"[c2rust-run] 错误: {e}", fg=typer.colors.RED, err=True)
|
|
565
|
+
raise typer.Exit(code=1)
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
def main() -> None:
|
|
570
|
+
"""主入口"""
|
|
571
|
+
app()
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
if __name__ == "__main__":
|
|
575
|
+
main()
|