feat: sap-cli skill v2.1.0 — self-contained distributable package
- assets/: sap-cli source (v2.1.0, 26 commands, 16 object types) - references/: tool constraints + error handling (self-contained) - scripts/setup.py: one-click install/config/verify - SKILL.md: full command reference + dual-platform install guide - VERSION: 2.1.0 Built from D:/Codespace/sap-cli via scripts/pack_skill.py
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
"""目录扫描模块。
|
||||
|
||||
扫描项目根目录下按约定的子目录结构,识别 ABAP 开发对象。
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
|
||||
logger = logging.getLogger("sapcli.scanner")
|
||||
|
||||
DIRECTORY_TYPE_MAP: dict[str, str] = {
|
||||
"reports": "report",
|
||||
"classes": "class",
|
||||
"interfaces": "interface",
|
||||
"functions": "function",
|
||||
"domains": "domain",
|
||||
"dataelements": "dataelement",
|
||||
"tables": "table",
|
||||
"structures": "structure",
|
||||
"tabletypes": "tabletype",
|
||||
"includes": "include",
|
||||
"cdsviews": "cdsview",
|
||||
"messageclasses": "messageclass",
|
||||
"views": "view",
|
||||
"searchhelps": "searchhelp",
|
||||
"lockobjects": "lockobject",
|
||||
}
|
||||
|
||||
FUNCTIONS_DIR = "functions"
|
||||
|
||||
|
||||
@dataclass
|
||||
class ScannedObject:
|
||||
"""扫描到的对象。"""
|
||||
|
||||
name: str # 大写对象名,function 类型含 / (GROUP/FUNC)
|
||||
type: str # 对象类型
|
||||
file: str # 相对于项目根目录的路径
|
||||
|
||||
|
||||
def scan_project(project_path: str) -> list[ScannedObject]:
|
||||
"""扫描项目目录,返回识别到的所有对象列表。
|
||||
|
||||
遍历已知目录名,每个目录下找 .abap 文件。
|
||||
functions/ 特殊处理:子目录 = 函数组名。
|
||||
"""
|
||||
results: list[ScannedObject] = []
|
||||
|
||||
for dir_name, obj_type in DIRECTORY_TYPE_MAP.items():
|
||||
dir_path = os.path.join(project_path, dir_name)
|
||||
if not os.path.isdir(dir_path):
|
||||
logger.debug("目录不存在,跳过: %s", dir_path)
|
||||
continue
|
||||
|
||||
if dir_name == FUNCTIONS_DIR:
|
||||
_scan_functions(dir_path, results)
|
||||
else:
|
||||
_scan_flat_directory(dir_path, dir_name, obj_type, results)
|
||||
|
||||
logger.info("扫描完成: %d 个对象", len(results))
|
||||
return results
|
||||
|
||||
|
||||
def _scan_flat_directory(
|
||||
dir_path: str,
|
||||
dir_name: str,
|
||||
obj_type: str,
|
||||
results: list[ScannedObject],
|
||||
) -> None:
|
||||
"""扫描普通目录(一对一:文件名 = 对象名)。"""
|
||||
for filename in sorted(os.listdir(dir_path)):
|
||||
if not filename.endswith(".abap"):
|
||||
continue
|
||||
# 隐藏文件跳过
|
||||
if filename.startswith("."):
|
||||
continue
|
||||
|
||||
obj_name = filename[:-5].upper() # 去掉 .abap,转大写
|
||||
rel_path = f"{dir_name}/{filename}"
|
||||
|
||||
results.append(ScannedObject(
|
||||
name=obj_name,
|
||||
type=obj_type,
|
||||
file=rel_path,
|
||||
))
|
||||
logger.debug("扫描到: %s (%s) → %s", obj_name, obj_type, rel_path)
|
||||
|
||||
|
||||
def _scan_functions(dir_path: str, results: list[ScannedObject]) -> None:
|
||||
"""扫描 functions/ 目录(特殊处理:子目录 = 函数组名)。
|
||||
|
||||
目录结构: functions/{组名小写}/{模块名小写}.abap
|
||||
对象名: {组名大写}/{模块名大写}
|
||||
"""
|
||||
for group_dir_name in sorted(os.listdir(dir_path)):
|
||||
group_dir = os.path.join(dir_path, group_dir_name)
|
||||
if not os.path.isdir(group_dir):
|
||||
continue
|
||||
if group_dir_name.startswith("."):
|
||||
continue
|
||||
|
||||
group_name = group_dir_name.upper()
|
||||
|
||||
for filename in sorted(os.listdir(group_dir)):
|
||||
if not filename.endswith(".abap"):
|
||||
continue
|
||||
if filename.startswith("."):
|
||||
continue
|
||||
|
||||
func_name = filename[:-5].upper()
|
||||
obj_name = f"{group_name}/{func_name}"
|
||||
rel_path = f"{FUNCTIONS_DIR}/{group_dir_name}/{filename}"
|
||||
|
||||
results.append(ScannedObject(
|
||||
name=obj_name,
|
||||
type="function",
|
||||
file=rel_path,
|
||||
))
|
||||
logger.debug("扫描到: %s (function) → %s", obj_name, rel_path)
|
||||
Reference in New Issue
Block a user