check_project.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. """
  4. AI驱动软件著作权申请材料生成系统 - 项目完整性检查脚本
  5. 版本: 1.0
  6. 描述: 全面检查项目文件完整性、配置正确性和功能可用性
  7. """
  8. import os
  9. import sys
  10. import json
  11. import subprocess
  12. import argparse
  13. from pathlib import Path
  14. from typing import List, Dict, Tuple, Optional
  15. import tempfile
  16. import shutil
  17. class Colors:
  18. """终端颜色定义"""
  19. RED = '\033[0;31m'
  20. GREEN = '\033[0;32m'
  21. YELLOW = '\033[1;33m'
  22. BLUE = '\033[0;34m'
  23. PURPLE = '\033[0;35m'
  24. CYAN = '\033[0;36m'
  25. NC = '\033[0m' # No Color
  26. class ProjectChecker:
  27. """项目检查器"""
  28. def __init__(self, project_dir: Path):
  29. self.project_dir = project_dir
  30. self.errors = []
  31. self.warnings = []
  32. self.successes = []
  33. def print_colored(self, color: str, message: str):
  34. """打印带颜色的消息"""
  35. print(f"{color}{message}{Colors.NC}")
  36. def print_header(self, title: str):
  37. """打印章节标题"""
  38. self.print_colored(Colors.CYAN, f"\n{'='*60}")
  39. self.print_colored(Colors.CYAN, f"🔍 {title}")
  40. self.print_colored(Colors.CYAN, f"{'='*60}")
  41. def print_success(self, message: str):
  42. """打印成功消息"""
  43. self.print_colored(Colors.GREEN, f"✅ {message}")
  44. self.successes.append(message)
  45. def print_warning(self, message: str):
  46. """打印警告消息"""
  47. self.print_colored(Colors.YELLOW, f"⚠️ {message}")
  48. self.warnings.append(message)
  49. def print_error(self, message: str):
  50. """打印错误消息"""
  51. self.print_colored(Colors.RED, f"❌ {message}")
  52. self.errors.append(message)
  53. def print_info(self, message: str):
  54. """打印信息消息"""
  55. self.print_colored(Colors.BLUE, f"ℹ️ {message}")
  56. def check_file_exists(self, file_path: str, required: bool = True) -> bool:
  57. """检查文件是否存在"""
  58. full_path = self.project_dir / file_path
  59. if full_path.exists():
  60. self.print_success(f"文件存在: {file_path}")
  61. return True
  62. else:
  63. if required:
  64. self.print_error(f"必需文件缺失: {file_path}")
  65. else:
  66. self.print_warning(f"可选文件缺失: {file_path}")
  67. return False
  68. def check_directory_exists(self, dir_path: str, required: bool = True) -> bool:
  69. """检查目录是否存在"""
  70. full_path = self.project_dir / dir_path
  71. if full_path.exists() and full_path.is_dir():
  72. self.print_success(f"目录存在: {dir_path}")
  73. return True
  74. else:
  75. if required:
  76. self.print_error(f"必需目录缺失: {dir_path}")
  77. else:
  78. self.print_warning(f"可选目录缺失: {dir_path}")
  79. return False
  80. def check_core_files(self):
  81. """检查核心文件完整性"""
  82. self.print_header("核心文件完整性检查")
  83. # 核心配置文件
  84. self.check_file_exists("ai-copyright-config.json")
  85. # 统一入口脚本
  86. self.check_file_exists("ai-copyright.py")
  87. self.check_file_exists("ai-copyright.sh")
  88. self.check_file_exists("create-copyright-project")
  89. # 初始化脚本(新目录)
  90. self.check_file_exists("scripts/init/init_project.py")
  91. self.check_file_exists("scripts/init/init_project.sh")
  92. # 生成脚本(新目录)
  93. generation_scripts = [
  94. "scripts/generators/generate_all_sourcecode.py",
  95. "scripts/generators/generate_frontend_sourcecode.py",
  96. "scripts/generators/generate_backend_sourcecode.py",
  97. "scripts/generators/generate_all_sourcecode.sh",
  98. "scripts/generators/generate_frontend_sourcecode.sh",
  99. "scripts/generators/generate_backend_sourcecode.sh"
  100. ]
  101. for script in generation_scripts:
  102. self.check_file_exists(script)
  103. # 验证脚本(新目录)
  104. validation_scripts = [
  105. "scripts/validators/check_project.py",
  106. "scripts/validators/check_project.sh",
  107. "scripts/validators/run_tests.py",
  108. "scripts/validators/validate_frontend_pages.py"
  109. ]
  110. for script in validation_scripts:
  111. self.check_file_exists(script)
  112. # 文档文件
  113. docs = [
  114. "README.md",
  115. "01-快速开始.md",
  116. "02-安装指南.md",
  117. "03-使用说明.md",
  118. "04-故障排除.md",
  119. "05-FAQ.md",
  120. "00-文档导航.md",
  121. "CLAUDE.md",
  122. "CLAUDE_zh.md",
  123. "ROADMAP.md",
  124. "FEATURE_LIST.md",
  125. "BUG_FIXES_LOG.md",
  126. "工作流程.md",
  127. "执行计划.md",
  128. "06-项目检查指南.md"
  129. ]
  130. for doc in docs:
  131. self.check_file_exists(doc)
  132. def check_directory_structure(self):
  133. """检查目录结构完整性"""
  134. self.print_header("目录结构完整性检查")
  135. # 核心目录
  136. core_dirs = [
  137. "specs_docs",
  138. "specs_docs/ui_design_specs",
  139. "specs_docs/tech_stack_specs",
  140. "system_prompts",
  141. "requires_docs",
  142. "process_docs",
  143. "output_docs",
  144. "output_sourcecode",
  145. "output_sourcecode/front",
  146. "output_sourcecode/backend"
  147. ]
  148. for dir_path in core_dirs:
  149. self.check_directory_exists(dir_path)
  150. def check_ui_design_specs(self):
  151. """检查UI设计规范文件"""
  152. self.print_header("UI设计规范文件检查")
  153. ui_specs = [
  154. "specs_docs/ui_design_specs/01-UI设计规范_默认_Corporate.md",
  155. "specs_docs/ui_design_specs/02-UI设计规范_暗黑科技风格_Cyberpunk.md",
  156. "specs_docs/ui_design_specs/03-UI设计规范_极简主义风格_Minimal.md"
  157. ]
  158. for spec in ui_specs:
  159. self.check_file_exists(spec)
  160. def check_system_prompts(self):
  161. """检查AI系统提示词完整性"""
  162. self.print_header("AI系统提示词完整性检查")
  163. prompts = [
  164. "system_prompts/01-软著框架系统提示词.md",
  165. "system_prompts/02-页面规划系统提示词.md",
  166. "system_prompts/03-界面设计系统提示词.md",
  167. "system_prompts/04-网页代码生成系统提示词.md",
  168. "system_prompts/05-数据库代码生成系统提示词.md",
  169. "system_prompts/06-后端代码生成系统提示词.md",
  170. "system_prompts/07-用户手册系统提示词.md",
  171. "system_prompts/08-软件著作权登记信息表系统提示词.md"
  172. ]
  173. for prompt in prompts:
  174. self.check_file_exists(prompt)
  175. def check_config_file(self):
  176. """检查配置文件内容"""
  177. self.print_header("配置文件内容检查")
  178. config_path = self.project_dir / "ai-copyright-config.json"
  179. if not config_path.exists():
  180. self.print_error("配置文件不存在")
  181. return
  182. try:
  183. with open(config_path, 'r', encoding='utf-8') as f:
  184. config = json.load(f)
  185. # 检查必需字段
  186. required_fields = [
  187. "front", "backend", "title", "short_title",
  188. "requirements_description", "dev_tech_stack", "ui_design_spec",
  189. "ui_design_style", "system_prompt_dir", "ui_design_spec_default"
  190. ]
  191. for field in required_fields:
  192. if field in config:
  193. self.print_success(f"配置字段存在: {field}")
  194. else:
  195. self.print_error(f"配置字段缺失: {field}")
  196. # 检查UI设计风格值
  197. if "ui_design_style" in config:
  198. valid_styles = ["corporate", "cyberpunk", "minimal", "bauhaus", "japanese", "scandinavian", "futuristic", "elegant", "bold", "artdeco", "memphis", "popart"]
  199. if config["ui_design_style"] in valid_styles:
  200. self.print_success(f"UI设计风格有效: {config['ui_design_style']}")
  201. else:
  202. self.print_warning(f"UI设计风格可能无效: {config['ui_design_style']}")
  203. except json.JSONDecodeError as e:
  204. self.print_error(f"配置文件JSON格式错误: {e}")
  205. except Exception as e:
  206. self.print_error(f"配置文件读取错误: {e}")
  207. def check_script_syntax(self):
  208. """检查脚本语法"""
  209. self.print_header("脚本语法检查")
  210. # 检查Python脚本
  211. python_scripts = [
  212. "init_project.py",
  213. "generate_all_sourcecode.py",
  214. "generate_frontend_sourcecode.py",
  215. "generate_backend_sourcecode.py"
  216. ]
  217. for script in python_scripts:
  218. script_path = self.project_dir / script
  219. if script_path.exists():
  220. try:
  221. result = subprocess.run(
  222. [sys.executable, "-m", "py_compile", str(script_path)],
  223. capture_output=True,
  224. text=True,
  225. cwd=self.project_dir
  226. )
  227. if result.returncode == 0:
  228. self.print_success(f"Python脚本语法正确: {script}")
  229. else:
  230. self.print_error(f"Python脚本语法错误: {script}\n{result.stderr}")
  231. except Exception as e:
  232. self.print_error(f"Python脚本检查失败: {script} - {e}")
  233. # 检查Shell脚本
  234. shell_scripts = [
  235. "init_project.sh",
  236. "generate_all_sourcecode.sh",
  237. "generate_frontend_sourcecode.sh",
  238. "generate_backend_sourcecode.sh",
  239. "create-copyright-project"
  240. ]
  241. for script in shell_scripts:
  242. script_path = self.project_dir / script
  243. if script_path.exists():
  244. try:
  245. result = subprocess.run(
  246. ["bash", "-n", str(script_path)],
  247. capture_output=True,
  248. text=True
  249. )
  250. if result.returncode == 0:
  251. self.print_success(f"Shell脚本语法正确: {script}")
  252. else:
  253. self.print_error(f"Shell脚本语法错误: {script}\n{result.stderr}")
  254. except Exception as e:
  255. self.print_error(f"Shell脚本检查失败: {script} - {e}")
  256. def check_document_references(self):
  257. """检查文档中的配置文件引用一致性"""
  258. self.print_header("文档引用一致性检查")
  259. docs_to_check = [
  260. "README.md", "01-快速开始.md", "03-使用说明.md",
  261. "工作流程.md", "04-故障排除.md", "05-FAQ.md",
  262. "CLAUDE.md", "CLAUDE_zh.md"
  263. ]
  264. old_config_refs = 0
  265. new_config_refs = 0
  266. problematic_refs = []
  267. # 定义说明性文本模式,这些不算作问题引用
  268. explanatory_patterns = [
  269. "从.*config\.json.*更名",
  270. "已从.*config\.json.*更名",
  271. "config\.json.*更名为",
  272. "配置文件.*从.*config\.json",
  273. "原.*config\.json",
  274. "旧.*config\.json",
  275. "之前.*config\.json"
  276. ]
  277. import re
  278. for doc in docs_to_check:
  279. doc_path = self.project_dir / doc
  280. if doc_path.exists():
  281. try:
  282. with open(doc_path, 'r', encoding='utf-8') as f:
  283. content = f.read()
  284. # 检查旧配置文件引用(但不包括 ai-copyright-config.json)
  285. # 计算独立的 config.json 引用,排除 ai-copyright-config.json
  286. total_config_count = content.count("config.json")
  287. ai_config_count = content.count("ai-copyright-config.json")
  288. independent_config_count = total_config_count - ai_config_count
  289. if independent_config_count > 0:
  290. # 检查是否是说明性文本
  291. is_explanatory = False
  292. for pattern in explanatory_patterns:
  293. if re.search(pattern, content, re.IGNORECASE):
  294. is_explanatory = True
  295. break
  296. if is_explanatory:
  297. self.print_success(f"文档包含配置文件更名说明: {doc}")
  298. else:
  299. old_config_refs += independent_config_count
  300. problematic_refs.append(doc)
  301. self.print_warning(f"文档包含旧配置文件引用: {doc}")
  302. # 检查新配置文件引用
  303. if "ai-copyright-config.json" in content:
  304. new_config_refs += content.count("ai-copyright-config.json")
  305. self.print_success(f"文档使用新配置文件名: {doc}")
  306. except Exception as e:
  307. self.print_error(f"文档读取失败: {doc} - {e}")
  308. if old_config_refs == 0:
  309. self.print_success("所有文档已更新为新配置文件名")
  310. else:
  311. self.print_error(f"发现 {old_config_refs} 处旧配置文件引用需要更新(在 {len(problematic_refs)} 个文档中)")
  312. def test_project_initialization(self):
  313. """测试项目初始化功能"""
  314. self.print_header("项目初始化功能测试")
  315. # 创建临时测试目录
  316. with tempfile.TemporaryDirectory() as temp_dir:
  317. test_project_name = "test-ai-copyright-project"
  318. test_project_path = Path(temp_dir) / test_project_name
  319. try:
  320. # 测试Python初始化脚本
  321. init_script = self.project_dir / "init_project.py"
  322. if init_script.exists():
  323. # 模拟非交互式运行
  324. env = os.environ.copy()
  325. env['PYTHONPATH'] = str(self.project_dir)
  326. # 这里我们只测试脚本是否能正常导入和基础语法
  327. result = subprocess.run(
  328. [sys.executable, "-c",
  329. f"import sys; sys.path.insert(0, '{self.project_dir}'); "
  330. f"exec(open('{init_script}').read().split('if __name__')[0])"],
  331. capture_output=True,
  332. text=True,
  333. cwd=temp_dir
  334. )
  335. if result.returncode == 0:
  336. self.print_success("初始化脚本语法和导入测试通过")
  337. else:
  338. self.print_error(f"初始化脚本测试失败: {result.stderr}")
  339. else:
  340. self.print_error("初始化脚本不存在")
  341. except Exception as e:
  342. self.print_error(f"项目初始化测试失败: {e}")
  343. def check_git_configuration(self):
  344. """检查Git配置"""
  345. self.print_header("Git配置检查")
  346. # 检查.gitignore
  347. gitignore_path = self.project_dir / ".gitignore"
  348. if gitignore_path.exists():
  349. self.print_success(".gitignore文件存在")
  350. try:
  351. with open(gitignore_path, 'r', encoding='utf-8') as f:
  352. content = f.read()
  353. # 检查关键忽略项
  354. key_ignores = [
  355. "ai-copyright-config_local.json",
  356. ".DS_Store",
  357. "__pycache__",
  358. "node_modules",
  359. "*.log"
  360. ]
  361. for ignore_item in key_ignores:
  362. if ignore_item in content:
  363. self.print_success(f"包含忽略项: {ignore_item}")
  364. else:
  365. self.print_warning(f"缺少忽略项: {ignore_item}")
  366. except Exception as e:
  367. self.print_error(f".gitignore读取失败: {e}")
  368. else:
  369. self.print_warning(".gitignore文件不存在")
  370. # 检查是否为Git仓库
  371. git_dir = self.project_dir / ".git"
  372. if git_dir.exists():
  373. self.print_success("Git仓库已初始化")
  374. else:
  375. self.print_warning("未初始化Git仓库")
  376. def generate_report(self):
  377. """生成检查报告"""
  378. self.print_header("检查报告汇总")
  379. total_checks = len(self.successes) + len(self.warnings) + len(self.errors)
  380. self.print_colored(Colors.CYAN, f"📊 检查统计:")
  381. self.print_colored(Colors.GREEN, f" ✅ 成功: {len(self.successes)}")
  382. self.print_colored(Colors.YELLOW, f" ⚠️ 警告: {len(self.warnings)}")
  383. self.print_colored(Colors.RED, f" ❌ 错误: {len(self.errors)}")
  384. self.print_colored(Colors.BLUE, f" 📋 总计: {total_checks}")
  385. # 计算健康度分数
  386. if total_checks > 0:
  387. health_score = (len(self.successes) / total_checks) * 100
  388. self.print_colored(Colors.PURPLE, f" 💯 健康度: {health_score:.1f}%")
  389. print("\n" + "="*60)
  390. if len(self.errors) == 0:
  391. if len(self.warnings) == 0:
  392. self.print_colored(Colors.GREEN, "🎉 项目检查完全通过!系统可以正常使用。")
  393. return 0
  394. else:
  395. self.print_colored(Colors.YELLOW, "✅ 项目检查基本通过,有一些警告需要注意。")
  396. return 1
  397. else:
  398. self.print_colored(Colors.RED, "❌ 项目检查发现错误,需要修复后才能正常使用。")
  399. self.print_colored(Colors.RED, "\n🔧 需要修复的错误:")
  400. for i, error in enumerate(self.errors[:5], 1): # 只显示前5个错误
  401. self.print_colored(Colors.RED, f" {i}. {error}")
  402. if len(self.errors) > 5:
  403. self.print_colored(Colors.RED, f" ... 还有 {len(self.errors) - 5} 个错误")
  404. return 2
  405. def run_all_checks(self):
  406. """运行所有检查"""
  407. self.print_colored(Colors.PURPLE, "🚀 开始AI软著申请材料生成系统完整性检查")
  408. self.print_colored(Colors.BLUE, f"📁 检查目录: {self.project_dir}")
  409. # 执行各项检查
  410. self.check_core_files()
  411. self.check_directory_structure()
  412. self.check_ui_design_specs()
  413. self.check_system_prompts()
  414. self.check_config_file()
  415. self.check_script_syntax()
  416. self.check_document_references()
  417. self.test_project_initialization()
  418. self.check_git_configuration()
  419. # 生成报告
  420. return self.generate_report()
  421. def main():
  422. """主函数"""
  423. parser = argparse.ArgumentParser(
  424. description='AI驱动软件著作权申请材料生成系统 - 项目完整性检查工具',
  425. formatter_class=argparse.RawDescriptionHelpFormatter,
  426. epilog="""
  427. 使用示例:
  428. python3 check_project.py # 检查当前目录
  429. python3 check_project.py /path/to/project # 检查指定目录
  430. python3 check_project.py --quick # 快速检查(跳过某些耗时检查)
  431. """
  432. )
  433. parser.add_argument(
  434. 'project_dir',
  435. nargs='?',
  436. default='.',
  437. help='项目目录路径(默认为当前目录)'
  438. )
  439. parser.add_argument(
  440. '--quick', '-q',
  441. action='store_true',
  442. help='快速检查模式(跳过语法检查和初始化测试)'
  443. )
  444. args = parser.parse_args()
  445. # 解析项目目录
  446. project_dir = Path(args.project_dir).resolve()
  447. if not project_dir.exists():
  448. print(f"{Colors.RED}❌ 项目目录不存在: {project_dir}{Colors.NC}")
  449. sys.exit(1)
  450. if not project_dir.is_dir():
  451. print(f"{Colors.RED}❌ 指定路径不是目录: {project_dir}{Colors.NC}")
  452. sys.exit(1)
  453. # 创建检查器并运行
  454. checker = ProjectChecker(project_dir)
  455. if args.quick:
  456. checker.print_colored(Colors.YELLOW, "⚡ 快速检查模式(跳过语法检查和初始化测试)")
  457. # 在快速模式下跳过某些检查
  458. checker.check_core_files()
  459. checker.check_directory_structure()
  460. checker.check_ui_design_specs()
  461. checker.check_system_prompts()
  462. checker.check_config_file()
  463. checker.check_document_references()
  464. checker.check_git_configuration()
  465. return checker.generate_report()
  466. else:
  467. return checker.run_all_checks()
  468. if __name__ == "__main__":
  469. sys.exit(main())