404659a545
Конфиг утилиты переведён на YAML; default_baseconfs для reindex без -b; автопоиск config.local.yml/.yaml/.json; обобщённая документация. Co-authored-by: Cursor <cursoragent@cursor.com>
253 lines
8.8 KiB
Python
253 lines
8.8 KiB
Python
"""Каталоги конфигураций проекта и типы объектов метаданных 1С."""
|
||
|
||
from __future__ import annotations
|
||
|
||
from dataclasses import dataclass
|
||
from pathlib import Path
|
||
|
||
# Алиасы имён конфигураций 1С для CLI (--baseconf / -b), задаются через --config
|
||
# (поле baseconf_aliases в YAML). См. config.example.yml.
|
||
_RUNTIME_ALIASES: dict[str, str] = {}
|
||
_RUNTIME_DEFAULT_BASECONFS: list[str] = []
|
||
|
||
# Папка EDT → канонический тип (английский идентификатор выгрузки).
|
||
OBJECT_TYPE_FOLDERS: dict[str, str] = {
|
||
"AccumulationRegisters": "AccumulationRegister",
|
||
"BusinessProcesses": "BusinessProcess",
|
||
"Catalogs": "Catalog",
|
||
"ChartsOfAccounts": "ChartOfAccounts",
|
||
"ChartsOfCalculationTypes": "ChartOfCalculationTypes",
|
||
"ChartsOfCharacteristicTypes": "ChartOfCharacteristicTypes",
|
||
"CommandGroups": "CommandGroup",
|
||
"CommonAttributes": "CommonAttribute",
|
||
"CommonCommands": "CommonCommand",
|
||
"CommonForms": "CommonForm",
|
||
"CommonModules": "CommonModule",
|
||
"CommonPictures": "CommonPicture",
|
||
"CommonTemplates": "CommonTemplate",
|
||
"Constants": "Constant",
|
||
"DataProcessors": "DataProcessor",
|
||
"DefinedTypes": "DefinedType",
|
||
"DocumentJournals": "DocumentJournal",
|
||
"DocumentNumerators": "DocumentNumerator",
|
||
"Documents": "Document",
|
||
"Enums": "Enum",
|
||
"EventSubscriptions": "EventSubscription",
|
||
"ExchangePlans": "ExchangePlan",
|
||
"FilterCriteria": "FilterCriterion",
|
||
"FunctionalOptions": "FunctionalOption",
|
||
"FunctionalOptionsParameters": "FunctionalOptionsParameter",
|
||
"HTTPServices": "HTTPService",
|
||
"InformationRegisters": "InformationRegister",
|
||
"IntegrationServices": "IntegrationService",
|
||
"Reports": "Report",
|
||
"Roles": "Role",
|
||
"ScheduledJobs": "ScheduledJob",
|
||
"SessionParameters": "SessionParameter",
|
||
"SettingsStorages": "SettingsStorage",
|
||
"StyleItems": "StyleItem",
|
||
"Subsystems": "Subsystem",
|
||
"Tasks": "Task",
|
||
"WebServices": "WebService",
|
||
"WSReferences": "WSReference",
|
||
"XDTOPackages": "XDTOPackage",
|
||
"Bots": "Bot",
|
||
"ExternalDataSources": "ExternalDataSource",
|
||
"Languages": "Language",
|
||
}
|
||
|
||
# Алиасы типов для --types (русский / короткий / мн.ч.).
|
||
TYPE_ALIASES: dict[str, str] = {
|
||
"catalog": "Catalog",
|
||
"catalogs": "Catalog",
|
||
"справочник": "Catalog",
|
||
"справочники": "Catalog",
|
||
"document": "Document",
|
||
"documents": "Document",
|
||
"документ": "Document",
|
||
"документы": "Document",
|
||
"informationregister": "InformationRegister",
|
||
"informationregisters": "InformationRegister",
|
||
"регистрсведений": "InformationRegister",
|
||
"регистрысведений": "InformationRegister",
|
||
"рс": "InformationRegister",
|
||
"accumulationregister": "AccumulationRegister",
|
||
"accumulationregisters": "AccumulationRegister",
|
||
"регистрнакопления": "AccumulationRegister",
|
||
"регистрынакопления": "AccumulationRegister",
|
||
"рн": "AccumulationRegister",
|
||
"constant": "Constant",
|
||
"constants": "Constant",
|
||
"константа": "Constant",
|
||
"константы": "Constant",
|
||
"enum": "Enum",
|
||
"enums": "Enum",
|
||
"перечисление": "Enum",
|
||
"перечисления": "Enum",
|
||
"commonmodule": "CommonModule",
|
||
"commonmodules": "CommonModule",
|
||
"общиймодуль": "CommonModule",
|
||
"общиемодули": "CommonModule",
|
||
"dataprocessor": "DataProcessor",
|
||
"dataprocessors": "DataProcessor",
|
||
"обработка": "DataProcessor",
|
||
"обработки": "DataProcessor",
|
||
"report": "Report",
|
||
"reports": "Report",
|
||
"отчет": "Report",
|
||
"отчеты": "Report",
|
||
"exchangeplan": "ExchangePlan",
|
||
"exchangeplans": "ExchangePlan",
|
||
"планыобмена": "ExchangePlan",
|
||
"definedtype": "DefinedType",
|
||
"definedtypes": "DefinedType",
|
||
"определяемыетипы": "DefinedType",
|
||
"chartofcharacteristictypes": "ChartOfCharacteristicTypes",
|
||
"пвх": "ChartOfCharacteristicTypes",
|
||
"role": "Role",
|
||
"roles": "Role",
|
||
"роль": "Role",
|
||
"роли": "Role",
|
||
"subsystem": "Subsystem",
|
||
"subsystems": "Subsystem",
|
||
"подсистема": "Subsystem",
|
||
"подсистемы": "Subsystem",
|
||
"httpservice": "HTTPService",
|
||
"httpservices": "HTTPService",
|
||
"documentjournal": "DocumentJournal",
|
||
"documentjournals": "DocumentJournal",
|
||
"журналыдокументов": "DocumentJournal",
|
||
"task": "Task",
|
||
"tasks": "Task",
|
||
"задача": "Task",
|
||
"задачи": "Task",
|
||
"businessprocess": "BusinessProcess",
|
||
"businessprocesses": "BusinessProcess",
|
||
"бизнеспроцесс": "BusinessProcess",
|
||
"бизнеспроцессы": "BusinessProcess",
|
||
"модуль": "CommonModule",
|
||
"модули": "CommonModule",
|
||
"bsl": "CommonModule",
|
||
}
|
||
|
||
# Типы с разбором реквизитов / измерений / ссылок.
|
||
FIELD_RICH_TYPES: frozenset[str] = frozenset(
|
||
{
|
||
"Catalog",
|
||
"Document",
|
||
"InformationRegister",
|
||
"AccumulationRegister",
|
||
"ChartOfCharacteristicTypes",
|
||
"ChartOfAccounts",
|
||
"ChartOfCalculationTypes",
|
||
"ExchangePlan",
|
||
"BusinessProcess",
|
||
"Task",
|
||
"DocumentJournal",
|
||
"Constant",
|
||
"DefinedType",
|
||
"CommonAttribute",
|
||
"Enum",
|
||
}
|
||
)
|
||
|
||
# Типы, которые по умолчанию пропускаем (шум / картинки).
|
||
DEFAULT_SKIP_TYPES: frozenset[str] = frozenset(
|
||
{
|
||
"CommonPicture",
|
||
"StyleItem",
|
||
"XDTOPackage",
|
||
"CommonTemplate",
|
||
"Language",
|
||
"Bot",
|
||
}
|
||
)
|
||
|
||
FOLDER_BY_TYPE: dict[str, str] = {v: k for k, v in OBJECT_TYPE_FOLDERS.items()}
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class ConfigPaths:
|
||
name: str
|
||
root: Path
|
||
src: Path
|
||
|
||
|
||
def project_root_from_here() -> Path:
|
||
"""Корень проекта: каталог с index_1c.py и VERSION."""
|
||
here = Path(__file__).resolve().parent
|
||
for candidate in (here.parent, here.parent.parent, here.parent.parent.parent):
|
||
if (candidate / "index_1c.py").is_file() and (candidate / "VERSION").is_file():
|
||
return candidate
|
||
return here.parent
|
||
|
||
|
||
def set_config_aliases(aliases: dict[str, str] | None) -> None:
|
||
"""Задать алиасы baseconf из файла --config (baseconf_aliases)."""
|
||
global _RUNTIME_ALIASES
|
||
_RUNTIME_ALIASES = {str(k): str(v) for k, v in (aliases or {}).items()}
|
||
|
||
|
||
def get_config_aliases() -> dict[str, str]:
|
||
return dict(_RUNTIME_ALIASES)
|
||
|
||
|
||
def set_default_baseconfs(names: list[str] | None) -> None:
|
||
"""Задать default_baseconfs из файла --config (YAML)."""
|
||
global _RUNTIME_DEFAULT_BASECONFS
|
||
_RUNTIME_DEFAULT_BASECONFS = [str(x) for x in (names or []) if str(x).strip()]
|
||
|
||
|
||
def get_default_baseconfs() -> list[str]:
|
||
"""Список baseconf по умолчанию для reindex без -b."""
|
||
return list(_RUNTIME_DEFAULT_BASECONFS)
|
||
|
||
|
||
def resolve_config_name(name: str) -> str:
|
||
key = name.strip()
|
||
aliases = get_config_aliases()
|
||
return aliases.get(key, aliases.get(key.lower(), key))
|
||
|
||
|
||
def list_config_dirs(project_root: Path) -> list[str]:
|
||
"""Все каталоги с выгрузкой 1С (<name>/src/) в корне проекта."""
|
||
if not project_root.is_dir():
|
||
return []
|
||
found: list[str] = []
|
||
for child in sorted(project_root.iterdir()):
|
||
if not child.is_dir() or child.name.startswith("."):
|
||
continue
|
||
if (child / "src").is_dir():
|
||
found.append(child.name)
|
||
return found
|
||
|
||
|
||
def resolve_object_type(name: str) -> str:
|
||
raw = name.strip()
|
||
if raw in FOLDER_BY_TYPE:
|
||
return raw
|
||
if raw in OBJECT_TYPE_FOLDERS:
|
||
return OBJECT_TYPE_FOLDERS[raw]
|
||
compact = raw.replace(" ", "").replace("_", "").replace("-", "").casefold()
|
||
if compact in TYPE_ALIASES:
|
||
return TYPE_ALIASES[compact]
|
||
for folder, otype in OBJECT_TYPE_FOLDERS.items():
|
||
if folder.casefold() == raw.casefold() or otype.casefold() == raw.casefold():
|
||
return otype
|
||
raise ValueError(f"Неизвестный тип объекта метаданных: {name!r}")
|
||
|
||
|
||
def discover_configs(project_root: Path, names: list[str] | None = None) -> list[ConfigPaths]:
|
||
wanted = [resolve_config_name(n) for n in names] if names else list_config_dirs(project_root)
|
||
found: list[ConfigPaths] = []
|
||
for name in wanted:
|
||
root = project_root / name
|
||
src = root / "src"
|
||
if src.is_dir():
|
||
found.append(ConfigPaths(name=name, root=root, src=src))
|
||
return found
|
||
|
||
|
||
def cache_dir(project_root: Path) -> Path:
|
||
return project_root / "cache" / "1c_meta"
|