mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-09-08 03:00:52 +03:00
feat(meta-edit,meta-remove): точечная правка и удаление внешних источников
meta-edit добавляет поля в таблицу внешнего источника: тот же парсер реквизита, свой тег <Field>, свой контекст (без индексов и полнотекстового поиска — чужой таблицей 1С не владеет) и три своих свойства в хвосте. Сам источник точечно не правится: и таблица (отдельный файл), и функция (узел с полным набором свойств) требуют эмиттера, который живёт в meta-compile, — дублировать его здесь значило бы завести вторую реализацию одного и того же. Заодно закрыт тихий отказ, существовавший независимо от внешних источников: проверка допустимых детей смотрела на истинность списка, а не на наличие ключа, поэтому для вида с пустым списком трактовалась как «ограничений нет» и чужой ребёнок молча записывался в объект. Теперь add-attribute на таблице внешнего источника отвергается с предупреждением, а не пишет <Attribute> вместо <Field>. meta-remove понимает две формы: ExternalDataSource.PG — источник целиком, и четырёхчастную ExternalDataSource.PG.Table.products — одну таблицу. Таблица числится в ChildObjects файла источника, а не конфигурации, поэтому дерегистрация разведена переменной реестра; поиск ссылок дополнен путями вида ExternalDataSource.И.Table.Т и ExternalDataSourceTableRef.И.Т. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NBsZA5cr2WFThtgp7i5WVi
This commit is contained in:
co-authored by
Claude Opus 5
parent
bb56a7e898
commit
ed766154fe
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# meta-remove v1.11 — Remove metadata object from 1C configuration dump
|
||||
# meta-remove v1.12 — Remove metadata object from 1C configuration dump
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
|
||||
import argparse
|
||||
@@ -250,6 +250,7 @@ TYPE_PLURAL_MAP = {
|
||||
"WSReference": "WSReferences",
|
||||
"StyleItem": "StyleItems",
|
||||
"Language": "Languages",
|
||||
"ExternalDataSource": "ExternalDataSources",
|
||||
}
|
||||
|
||||
# Type -> reference type names (used in XML <v8:Type> elements)
|
||||
@@ -388,19 +389,42 @@ def main():
|
||||
sys.exit(1)
|
||||
|
||||
# --- Parse object spec ---
|
||||
parts = args.Object.split(".", 1)
|
||||
if len(parts) != 2 or not parts[0] or not parts[1]:
|
||||
print(f"[ERROR] Invalid object format '{args.Object}'. Expected: Type.Name (e.g. Catalog.\u0422\u043e\u0432\u0430\u0440\u044b)")
|
||||
sys.exit(1)
|
||||
# Таблица внешнего источника — единственный объект с четырёхчастным именем: она лежит не в
|
||||
# каталоге вида, а внутри источника, и числится в ChildObjects файла источника, не конфигурации.
|
||||
eds_source = ""
|
||||
m_eds = re.match(r'^ExternalDataSource\.([^.]+)\.Table\.(.+)$', args.Object)
|
||||
if m_eds:
|
||||
eds_source = m_eds.group(1)
|
||||
obj_type = "Table"
|
||||
obj_name = m_eds.group(2)
|
||||
else:
|
||||
parts = args.Object.split(".", 1)
|
||||
if len(parts) != 2 or not parts[0] or not parts[1]:
|
||||
print(f"[ERROR] Invalid object format '{args.Object}'. Expected: Type.Name (e.g. Catalog.\u0422\u043e\u0432\u0430\u0440\u044b) or ExternalDataSource.\u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a.Table.\u0422\u0430\u0431\u043b\u0438\u0446\u0430")
|
||||
sys.exit(1)
|
||||
obj_type = parts[0]
|
||||
obj_name = parts[1]
|
||||
|
||||
obj_type = parts[0]
|
||||
obj_name = parts[1]
|
||||
if eds_source:
|
||||
type_plural = os.path.join("ExternalDataSources", eds_source, "Tables")
|
||||
else:
|
||||
if obj_type not in TYPE_PLURAL_MAP:
|
||||
print(f"[ERROR] Unknown type '{obj_type}'. Supported: {', '.join(TYPE_PLURAL_MAP.keys())}")
|
||||
sys.exit(1)
|
||||
type_plural = TYPE_PLURAL_MAP[obj_type]
|
||||
|
||||
if obj_type not in TYPE_PLURAL_MAP:
|
||||
print(f"[ERROR] Unknown type '{obj_type}'. Supported: {', '.join(TYPE_PLURAL_MAP.keys())}")
|
||||
sys.exit(1)
|
||||
|
||||
type_plural = TYPE_PLURAL_MAP[obj_type]
|
||||
# Реестр, где объект числится: обычно ChildObjects конфигурации, а для таблицы — файл источника.
|
||||
if eds_source:
|
||||
registry_xml = os.path.join(config_dir, "ExternalDataSources", f"{eds_source}.xml")
|
||||
registry_root = "ExternalDataSource"
|
||||
registry_label = f"ExternalDataSources/{eds_source}.xml"
|
||||
if not os.path.isfile(registry_xml):
|
||||
print(f"[ERROR] \u0412\u043d\u0435\u0448\u043d\u0438\u0439 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a '{eds_source}' \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d: {registry_label}")
|
||||
sys.exit(1)
|
||||
else:
|
||||
registry_xml = config_xml
|
||||
registry_root = "Configuration"
|
||||
registry_label = "Configuration.xml"
|
||||
|
||||
print(f"=== meta-remove: {obj_type}.{obj_name} ===")
|
||||
print()
|
||||
@@ -425,7 +449,7 @@ def main():
|
||||
|
||||
if not has_xml and not has_dir:
|
||||
# Check if registered in Configuration.xml before proceeding
|
||||
cfg_check_tree = etree.parse(config_xml, etree.XMLParser(remove_blank_text=False))
|
||||
cfg_check_tree = etree.parse(registry_xml, etree.XMLParser(remove_blank_text=False))
|
||||
cfg_check_root = cfg_check_tree.getroot()
|
||||
child_objects = cfg_check_root.find(f"{{{MD_NS}}}Configuration/{{{MD_NS}}}ChildObjects")
|
||||
registered_in_cfg = False
|
||||
@@ -463,6 +487,16 @@ def main():
|
||||
search_patterns.append(f"{ru_mgr}.{obj_name}")
|
||||
search_patterns.append(f"{type_plural}.{obj_name}")
|
||||
|
||||
# 2а) Внешний источник данных: ссылки на сам источник и на его таблицы
|
||||
if obj_type == "ExternalDataSource":
|
||||
search_patterns.append(f"ExternalDataSource.{obj_name}.")
|
||||
search_patterns.append(f"\u0412\u043d\u0435\u0448\u043d\u0438\u0435\u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438\u0414\u0430\u043d\u043d\u044b\u0445.{obj_name}")
|
||||
search_patterns.append(f"ExternalDataSources.{obj_name}")
|
||||
if eds_source:
|
||||
search_patterns.append(f"ExternalDataSource.{eds_source}.Table.{obj_name}")
|
||||
search_patterns.append(f"ExternalDataSourceTableRef.{eds_source}.{obj_name}")
|
||||
search_patterns.append(f"\u0412\u043d\u0435\u0448\u043d\u0438\u0435\u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438\u0414\u0430\u043d\u043d\u044b\u0445.{eds_source}.\u0422\u0430\u0431\u043b\u0438\u0446\u044b.{obj_name}")
|
||||
|
||||
# 3) CommonModule: method calls
|
||||
if obj_type == "CommonModule":
|
||||
search_patterns.append(f"{obj_name}.")
|
||||
@@ -578,17 +612,17 @@ def main():
|
||||
else:
|
||||
print("[OK] No references found")
|
||||
|
||||
# --- 3. Remove from Configuration.xml ChildObjects ---
|
||||
# --- 3. Remove from registry ChildObjects (Configuration.xml или файл внешнего источника) ---
|
||||
print()
|
||||
print("--- Configuration.xml ---")
|
||||
print(f"--- {registry_label} ---")
|
||||
|
||||
xml_parser = etree.XMLParser(remove_blank_text=False)
|
||||
tree = etree.parse(config_xml, xml_parser)
|
||||
tree = etree.parse(registry_xml, xml_parser)
|
||||
xml_root = tree.getroot()
|
||||
|
||||
cfg_node = xml_root.find(f"{{{MD_NS}}}Configuration")
|
||||
cfg_node = xml_root.find(f"{{{MD_NS}}}{registry_root}")
|
||||
if cfg_node is None:
|
||||
print("[ERROR] Configuration element not found in Configuration.xml")
|
||||
print(f"[ERROR] {registry_root} element not found in {registry_label}")
|
||||
errors += 1
|
||||
else:
|
||||
child_objects = cfg_node.find(f"{{{MD_NS}}}ChildObjects")
|
||||
@@ -611,8 +645,8 @@ def main():
|
||||
|
||||
# Save Configuration.xml
|
||||
if actions > 0 and not args.DryRun:
|
||||
save_xml_bom(tree, config_xml)
|
||||
print("[OK] Configuration.xml saved")
|
||||
save_xml_bom(tree, registry_xml)
|
||||
print(f"[OK] {registry_label} saved")
|
||||
|
||||
# --- 4. Remove from subsystem Content ---
|
||||
print()
|
||||
|
||||
Reference in New Issue
Block a user