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,243 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from sapcli.exceptions import InvalidNameError
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ObjectTypeConfig:
|
||||
key: str
|
||||
label: str
|
||||
obj_uri_template: str
|
||||
src_uri_template: str | None
|
||||
collection_uri: str
|
||||
create_content_type: str
|
||||
has_source: bool = True
|
||||
|
||||
def format_obj_uri(self, name: str, **kwargs: str) -> str:
|
||||
return self.obj_uri_template.format(name=name, **kwargs)
|
||||
|
||||
def format_src_uri(self, name: str, **kwargs: str) -> str | None:
|
||||
if self.src_uri_template is None:
|
||||
return None
|
||||
return self.src_uri_template.format(name=name, **kwargs)
|
||||
|
||||
def format_collection_uri(self, **kwargs: str) -> str:
|
||||
return self.collection_uri.format(**kwargs)
|
||||
|
||||
|
||||
_OBJECT_TYPE_REGISTRY: dict[str, ObjectTypeConfig] = {}
|
||||
|
||||
|
||||
def _register(cfg: ObjectTypeConfig) -> ObjectTypeConfig:
|
||||
_OBJECT_TYPE_REGISTRY[cfg.key] = cfg
|
||||
return cfg
|
||||
|
||||
|
||||
REPORT = _register(ObjectTypeConfig(
|
||||
key="report",
|
||||
label="程序(REPORT)",
|
||||
obj_uri_template="/sap/bc/adt/programs/programs/{name}",
|
||||
src_uri_template="/sap/bc/adt/programs/programs/{name}/source/main",
|
||||
collection_uri="/sap/bc/adt/programs/programs",
|
||||
create_content_type="application/vnd.sap.adt.programs.programs.v2+xml",
|
||||
))
|
||||
|
||||
CLASS = _register(ObjectTypeConfig(
|
||||
key="class",
|
||||
label="类(CLASS)",
|
||||
obj_uri_template="/sap/bc/adt/oo/classes/{name}",
|
||||
src_uri_template="/sap/bc/adt/oo/classes/{name}/source/main",
|
||||
collection_uri="/sap/bc/adt/oo/classes",
|
||||
create_content_type="application/vnd.sap.adt.oo.classes.v1+xml",
|
||||
))
|
||||
|
||||
FUNCTION = _register(ObjectTypeConfig(
|
||||
key="function",
|
||||
label="函数模块(FUNCTION)",
|
||||
obj_uri_template="/sap/bc/adt/functions/groups/{group}/fmodules/{name}",
|
||||
src_uri_template="/sap/bc/adt/functions/groups/{group}/fmodules/{name}/source/main",
|
||||
collection_uri="/sap/bc/adt/functions/groups/{group}/fmodules",
|
||||
create_content_type="application/vnd.sap.adt.functions.fmodules.v1+xml",
|
||||
))
|
||||
|
||||
FUNCTIONGROUP = _register(ObjectTypeConfig(
|
||||
key="functiongroup",
|
||||
label="函数组(FUNCTION GROUP)",
|
||||
obj_uri_template="/sap/bc/adt/functions/groups/{name}",
|
||||
src_uri_template=None,
|
||||
collection_uri="/sap/bc/adt/functions/groups",
|
||||
create_content_type="application/vnd.sap.adt.functions.groups.v2+xml",
|
||||
has_source=False,
|
||||
))
|
||||
|
||||
INTERFACE = _register(ObjectTypeConfig(
|
||||
key="interface",
|
||||
label="接口(INTERFACE)",
|
||||
obj_uri_template="/sap/bc/adt/oo/interfaces/{name}",
|
||||
src_uri_template="/sap/bc/adt/oo/interfaces/{name}/source/main",
|
||||
collection_uri="/sap/bc/adt/oo/interfaces",
|
||||
create_content_type="application/vnd.sap.adt.oo.interfaces.v1+xml",
|
||||
))
|
||||
|
||||
DOMAIN = _register(ObjectTypeConfig(
|
||||
key="domain",
|
||||
label="域(DOMAIN)",
|
||||
obj_uri_template="/sap/bc/adt/ddic/domains/{name}",
|
||||
src_uri_template="/sap/bc/adt/ddic/domains/{name}/source/main",
|
||||
collection_uri="/sap/bc/adt/ddic/domains",
|
||||
create_content_type="application/vnd.sap.adt.domains.v2+xml",
|
||||
))
|
||||
|
||||
DATAELEMENT = _register(ObjectTypeConfig(
|
||||
key="dataelement",
|
||||
label="数据元素(DATA ELEMENT)",
|
||||
obj_uri_template="/sap/bc/adt/ddic/dataelements/{name}",
|
||||
src_uri_template="/sap/bc/adt/ddic/dataelements/{name}/source/main",
|
||||
collection_uri="/sap/bc/adt/ddic/dataelements",
|
||||
create_content_type="application/vnd.sap.adt.dataelements.v2+xml",
|
||||
))
|
||||
|
||||
TABLE = _register(ObjectTypeConfig(
|
||||
key="table",
|
||||
label="透明表(TABLE)",
|
||||
obj_uri_template="/sap/bc/adt/ddic/tables/{name}",
|
||||
src_uri_template="/sap/bc/adt/ddic/tables/{name}/source/main",
|
||||
collection_uri="/sap/bc/adt/ddic/tables",
|
||||
create_content_type="application/vnd.sap.adt.ddic.tables.v1+xml",
|
||||
))
|
||||
|
||||
STRUCTURE = _register(ObjectTypeConfig(
|
||||
key="structure",
|
||||
label="结构(STRUCTURE)",
|
||||
obj_uri_template="/sap/bc/adt/ddic/structures/{name}",
|
||||
src_uri_template="/sap/bc/adt/ddic/structures/{name}/source/main",
|
||||
collection_uri="/sap/bc/adt/ddic/structures",
|
||||
create_content_type="application/vnd.sap.adt.ddic.structures.v1+xml",
|
||||
))
|
||||
|
||||
TABLETYPE = _register(ObjectTypeConfig(
|
||||
key="tabletype",
|
||||
label="表类型(TABLE TYPE)",
|
||||
obj_uri_template="/sap/bc/adt/vit/wb/object_type/ttypda/object_name/{name}",
|
||||
src_uri_template=None,
|
||||
collection_uri="/sap/bc/adt/ddic/tabletypes",
|
||||
create_content_type="application/vnd.sap.adt.ddic.tabletypes.v1+xml",
|
||||
has_source=False,
|
||||
))
|
||||
|
||||
INCLUDE = _register(ObjectTypeConfig(
|
||||
key="include",
|
||||
label="Include程序(INCLUDE)",
|
||||
obj_uri_template="/sap/bc/adt/programs/includes/{name}",
|
||||
src_uri_template="/sap/bc/adt/programs/includes/{name}/source/main",
|
||||
collection_uri="/sap/bc/adt/programs/includes",
|
||||
create_content_type="application/vnd.sap.adt.programs.includes.v2+xml",
|
||||
))
|
||||
|
||||
CDSVIEW = _register(ObjectTypeConfig(
|
||||
key="cdsview",
|
||||
label="CDS视图(CDS VIEW)",
|
||||
obj_uri_template="/sap/bc/adt/dds/ddl/sources/{name}",
|
||||
src_uri_template="/sap/bc/adt/dds/ddl/sources/{name}/content",
|
||||
collection_uri="/sap/bc/adt/dds/ddl/sources",
|
||||
create_content_type="text/plain",
|
||||
))
|
||||
|
||||
MESSAGECLASS = _register(ObjectTypeConfig(
|
||||
key="messageclass",
|
||||
label="消息类(MESSAGE CLASS)",
|
||||
obj_uri_template="/sap/bc/adt/oo/t100/messages/classes/{name}",
|
||||
src_uri_template=None,
|
||||
collection_uri="/sap/bc/adt/oo/t100/messages/classes",
|
||||
create_content_type="application/vnd.sap.adt.t100.message.classes.v1+xml",
|
||||
has_source=False,
|
||||
))
|
||||
|
||||
VIEW = _register(ObjectTypeConfig(
|
||||
key="view",
|
||||
label="数据库视图(VIEW)",
|
||||
obj_uri_template="/sap/bc/adt/ddic/views/{name}",
|
||||
src_uri_template="/sap/bc/adt/ddic/views/{name}/source/main",
|
||||
collection_uri="/sap/bc/adt/ddic/views",
|
||||
create_content_type="application/vnd.sap.adt.ddic.views.v1+xml",
|
||||
))
|
||||
|
||||
SEARCHHELP = _register(ObjectTypeConfig(
|
||||
key="searchhelp",
|
||||
label="搜索帮助(SEARCH HELP)",
|
||||
obj_uri_template="/sap/bc/adt/ddic/searchhelps/{name}",
|
||||
src_uri_template=None,
|
||||
collection_uri="/sap/bc/adt/ddic/searchhelps",
|
||||
create_content_type="application/vnd.sap.adt.ddic.searchhelps.v1+xml",
|
||||
has_source=False,
|
||||
))
|
||||
|
||||
LOCKOBJECT = _register(ObjectTypeConfig(
|
||||
key="lockobject",
|
||||
label="锁对象(LOCK OBJECT)",
|
||||
obj_uri_template="/sap/bc/adt/ddic/lockobjects/{name}",
|
||||
src_uri_template=None,
|
||||
collection_uri="/sap/bc/adt/ddic/lockobjects",
|
||||
create_content_type="application/vnd.sap.adt.ddic.lockobjects.v1+xml",
|
||||
has_source=False,
|
||||
))
|
||||
|
||||
|
||||
def get_type_config(key: str) -> ObjectTypeConfig:
|
||||
if key not in _OBJECT_TYPE_REGISTRY:
|
||||
raise ValueError(f"不支持的对象类型: {key}")
|
||||
return _OBJECT_TYPE_REGISTRY[key]
|
||||
|
||||
|
||||
def all_type_keys() -> list[str]:
|
||||
return list(_OBJECT_TYPE_REGISTRY.keys())
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ParsedName:
|
||||
obj_uri: str
|
||||
src_uri: str | None
|
||||
display_name: str
|
||||
file_base: str
|
||||
|
||||
|
||||
def parse_object_name(name: str, obj_type: str) -> ParsedName:
|
||||
cfg = get_type_config(obj_type)
|
||||
|
||||
if obj_type == "function":
|
||||
if "/" not in name:
|
||||
raise InvalidNameError(
|
||||
"function 类型需要'函数组名/函数模块名' 格式,例如: ZGROUP/Z_MY_FUNC"
|
||||
)
|
||||
group, fm = name.split("/", 1)
|
||||
group = group.strip()
|
||||
fm = fm.strip()
|
||||
if not group or not fm:
|
||||
raise InvalidNameError("函数组名和函数模块名不能为空")
|
||||
return ParsedName(
|
||||
obj_uri=cfg.format_obj_uri(fm.lower(), group=group.lower()),
|
||||
src_uri=cfg.format_src_uri(fm.lower(), group=group.lower()),
|
||||
display_name=name,
|
||||
file_base=fm.lower(),
|
||||
)
|
||||
|
||||
# VIT 端点需要大写名称以返回完整元数据;去掉前导 /
|
||||
if obj_type == "tabletype":
|
||||
clean = name.lstrip("/")
|
||||
name_upper = clean.upper()
|
||||
return ParsedName(
|
||||
obj_uri=cfg.format_obj_uri(name_upper),
|
||||
src_uri=cfg.format_src_uri(name_upper),
|
||||
display_name=clean,
|
||||
file_base=clean.lower(),
|
||||
)
|
||||
|
||||
name_lower = name.lower()
|
||||
return ParsedName(
|
||||
obj_uri=cfg.format_obj_uri(name_lower),
|
||||
src_uri=cfg.format_src_uri(name_lower),
|
||||
display_name=name,
|
||||
file_base=name_lower,
|
||||
)
|
||||
Reference in New Issue
Block a user