| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- """
- 项目扫描器模块
- 负责扫描和分类项目目录
- """
- import os
- import fnmatch
- from pathlib import Path
- from typing import Dict, List, Tuple
- class ProjectScanner:
- def __init__(self, projects_dir: str, categories: Dict):
- self.projects_dir = Path(projects_dir)
- self.categories = categories
- self.category_mapping = {cat: [] for cat in categories.keys()}
- def scan_projects(self) -> Dict[str, List[str]]:
- """扫描项目目录并分类
- - 对于不含路径分隔符的 pattern(如: "Titan_basic_*"),仅在一级目录名上匹配。
- - 对于包含路径分隔符的 pattern(如: "dir/sub"),使用基于根目录的 glob 匹配精确目录。
- 不会把更深层的子目录当作项目条目,严格以匹配到的目录为准。
- """
- if not self.projects_dir.exists():
- raise FileNotFoundError(f"项目目录不存在: {self.projects_dir}")
- print("开始扫描项目...")
- # 先缓存一级目录列表,便于无斜杠模式匹配
- top_level_dirs = [p for p in self.projects_dir.iterdir() if p.is_dir()]
- # 清空旧映射
- self.category_mapping = {cat: [] for cat in self.categories.keys()}
- for category, config in self.categories.items():
- patterns = config.get('patterns', [])
- matched_paths = []
- for pattern in patterns:
- # 标准化分隔符判断
- has_sep = ('/' in pattern) or ('\\' in pattern)
- if not has_sep:
- # 仅在一级目录名上匹配
- for d in top_level_dirs:
- if fnmatch.fnmatch(d.name, pattern):
- matched_paths.append(d)
- else:
- # 使用根目录下的 glob 精确匹配相对路径
- # 注意: Path.glob 接受 POSIX 风格的分隔符
- for p in self.projects_dir.glob(pattern):
- if p.is_dir():
- matched_paths.append(p)
- # 去重并排序,填充分类结果
- seen = set()
- for p in matched_paths:
- rel = p.relative_to(self.projects_dir).as_posix()
- if rel not in seen:
- seen.add(rel)
- self.category_mapping[category].append(rel)
- print(f"分类项目: {rel} -> {category}")
- return self.category_mapping
- def _classify_project(self, project_relative_path: str) -> str:
- """已不使用:分类逻辑已内联在 scan_projects 中。保留以兼容旧接口。"""
- for category, projects in self.category_mapping.items():
- if project_relative_path in projects:
- return category
- return None
- def get_projects_by_category(self, category: str) -> List[str]:
- """获取指定分类的项目列表"""
- return self.category_mapping.get(category, [])
- def get_all_projects(self) -> List[str]:
- """获取所有项目"""
- all_projects = []
- for projects in self.category_mapping.values():
- all_projects.extend(projects)
- return all_projects
- def validate_projects(self) -> bool:
- """验证项目目录结构"""
- for project_name in self.get_all_projects():
- project_path = self.projects_dir / project_name
- if not project_path.exists():
- print(f"警告: 项目目录不存在: {project_path}")
- return False
- return True
|