mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-07-11 13:33:41 +03:00
de04a8dc7a
Замыкает петлю issue #23: после отказа support-guard модель может легитимно включить редактирование. support-edit правит правила поддержки в Ext/ParentConfigurations.bin выгрузки (только XML; в ИБ — полной загрузкой): -Path <путь> -Set editable|off-support|locked (пообъектно или корень) -Path <путь> -Capability on|off (возможность изменения) Path-based, симметрично гарду — модель берёт путь прямо из отказа. Реализация: regex-замена in-place по разобранному формату bin (round-trip байт-в-байт; парсер подтверждён consumed=100% на корпусе acc/erp/K=7). При выключенной возможности (G=1) пообъектный -Set отказывает с подсказкой «сначала -Capability on» (явные шаги). Включение возможности ставит всё на замок (вендорские флаги «не редактировать» в выгрузке недоступны — массовой разблокировки нет; non-goal). Оба порта дают байт-в-байт идентичный bin. Диагностика support-guard (32 файла, 16 мутаторов × 2 порта) теперь печатает готовую команду support-edit под конкретный отказ. Тесты: фикстуры g0/g1 + кейсы set-editable/off-support/предусловие/capability со снапшотами bin; зелёные на PowerShell и Python. Все 16 мутаторов + support-edit зелёные на обоих рантаймах. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
135 lines
5.7 KiB
Python
135 lines
5.7 KiB
Python
#!/usr/bin/env python3
|
|
# support-edit v1.0 — Toggle 1C configuration support state (Ext/ParentConfigurations.bin)
|
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
|
|
|
import argparse
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
from lxml import etree
|
|
|
|
sys.stdout.reconfigure(encoding="utf-8")
|
|
sys.stderr.reconfigure(encoding="utf-8")
|
|
|
|
parser = argparse.ArgumentParser(description="Toggle 1C support state", allow_abbrev=False)
|
|
parser.add_argument("-Path", "-TargetPath", dest="Path", required=True, help="Путь к объекту/форме/макету или каталогу дампа")
|
|
parser.add_argument("-Set", choices=["editable", "off-support", "locked"], default=None)
|
|
parser.add_argument("-Capability", choices=["on", "off"], default=None)
|
|
args = parser.parse_args()
|
|
|
|
if (not args.Set and not args.Capability) or (args.Set and args.Capability):
|
|
sys.stderr.write("Укажите ровно одно: -Set editable|off-support|locked ЛИБО -Capability on|off\n")
|
|
sys.exit(1)
|
|
|
|
|
|
def root_uuid(xml_path):
|
|
if not os.path.isfile(xml_path):
|
|
return None
|
|
try:
|
|
mx = etree.parse(xml_path).getroot()
|
|
for child in mx:
|
|
if isinstance(child.tag, str) and child.get("uuid"):
|
|
return child.get("uuid")
|
|
except Exception:
|
|
return None
|
|
return None
|
|
|
|
|
|
target_path = args.Path
|
|
if not os.path.exists(target_path):
|
|
sys.stderr.write(f"Путь не найден: {target_path}\n")
|
|
sys.exit(1)
|
|
rp = os.path.abspath(target_path)
|
|
elem_uuid = root_uuid(rp)
|
|
cfg_dir = None
|
|
bin_path = None
|
|
d = rp if os.path.isdir(rp) else os.path.dirname(rp)
|
|
for _ in range(12):
|
|
if not d:
|
|
break
|
|
if not elem_uuid:
|
|
elem_uuid = root_uuid(d + ".xml")
|
|
if not cfg_dir:
|
|
cand = os.path.join(d, "Ext", "ParentConfigurations.bin")
|
|
if os.path.exists(cand) or os.path.exists(os.path.join(d, "Configuration.xml")):
|
|
cfg_dir = d
|
|
bin_path = cand
|
|
if elem_uuid and cfg_dir:
|
|
break
|
|
parent = os.path.dirname(d)
|
|
if parent == d:
|
|
break
|
|
d = parent
|
|
if not elem_uuid and cfg_dir:
|
|
elem_uuid = root_uuid(os.path.join(cfg_dir, "Configuration.xml"))
|
|
|
|
if not cfg_dir:
|
|
sys.stderr.write(f"Не найден корень конфигурации (Configuration.xml) над путём: {rp}\n")
|
|
sys.exit(1)
|
|
if not os.path.exists(bin_path):
|
|
print("Конфигурация не на поддержке (Ext/ParentConfigurations.bin отсутствует) — переключать нечего.")
|
|
sys.exit(0)
|
|
|
|
raw = open(bin_path, "rb").read()
|
|
if len(raw) <= 32:
|
|
print("Поддержка снята полностью (пустой ParentConfigurations.bin) — переключать нечего.")
|
|
sys.exit(0)
|
|
text = raw[3:].decode("utf-8") if raw[:3] == b"\xef\xbb\xbf" else raw.decode("utf-8")
|
|
hm = re.match(r"\{6,(\d+),(\d+),", text)
|
|
if not hm:
|
|
sys.stderr.write("Неизвестный формат ParentConfigurations.bin\n")
|
|
sys.exit(1)
|
|
g = int(hm.group(1))
|
|
k = int(hm.group(2))
|
|
|
|
|
|
def save_bin(txt):
|
|
open(bin_path, "wb").write(b"\xef\xbb\xbf" + txt.encode("utf-8"))
|
|
|
|
|
|
# === Capability (global G) ===
|
|
if args.Capability:
|
|
target = "0" if args.Capability == "on" else "1"
|
|
if g == int(target):
|
|
word = "включена" if args.Capability == "on" else "выключена"
|
|
print(f"Возможность изменения конфигурации уже {word} — изменений нет.")
|
|
sys.exit(0)
|
|
text = re.sub(r"^(\{6,)\d+(,)", r"\g<1>" + target + r"\g<2>", text)
|
|
text = re.sub(r"([0-9a-f-]{36}),\d+,([0-9a-f-]{36})", r"\1," + target + r",\2", text)
|
|
text = re.sub(r"[0-2],0,([0-9a-f-]{36})", target + r",0,\1", text)
|
|
save_bin(text)
|
|
if args.Capability == "on":
|
|
print("Возможность изменения конфигурации ВКЛЮЧЕНА. Все объекты поставщика — на замке.")
|
|
print("Включайте редактирование точечно: support-edit -Path <объект> -Set editable")
|
|
else:
|
|
print("Возможность изменения конфигурации ВЫКЛЮЧЕНА. Вся конфигурация стала read-only; пообъектные правила сброшены.")
|
|
sys.exit(0)
|
|
|
|
# === Per-object -Set ===
|
|
if g == 1:
|
|
sys.stderr.write(
|
|
"Возможность изменения конфигурации выключена — пообъектное переключение недоступно.\n"
|
|
f" Сначала: support-edit -Path {target_path} -Capability on\n"
|
|
)
|
|
sys.exit(1)
|
|
if not elem_uuid:
|
|
sys.stderr.write(f"Не удалось определить объект по пути: {rp}\n")
|
|
sys.exit(1)
|
|
u = re.escape(elem_uuid.lower())
|
|
n = len(re.findall(r"[0-2],0," + u, text))
|
|
if n == 0:
|
|
print(f"Объект (uuid {elem_uuid}) не на поддержке (своё добавление или не найден в bin) — переключать нечего.")
|
|
sys.exit(0)
|
|
new_f1 = {"editable": "1", "off-support": "2", "locked": "0"}[args.Set]
|
|
text = re.sub(r"[0-2],0," + u, new_f1 + ",0," + elem_uuid.lower(), text)
|
|
save_bin(text)
|
|
state = {
|
|
"editable": "редактируется с сохранением поддержки (объект продолжит получать обновления вендора — возможны конфликты при обновлении)",
|
|
"off-support": "снят с поддержки (обновления вендора по этому объекту прекращаются)",
|
|
"locked": "на замке (правка запрещена)",
|
|
}[args.Set]
|
|
print(f"Объект uuid {elem_uuid} → {state}.")
|
|
print(f"Записей в bin изменено: {n}. Цель: {rp}")
|
|
sys.exit(0)
|