mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-09-06 02:00:54 +03:00
feat(db-*): после загрузки расширения проверяется его применимость
Платформа отчитывается успехом и о расширении, которое не применит: отказ всплывает лениво, при первом вызове метода, записью в журнал регистрации. Теперь db-load-xml, db-load-git, db-load-cf и db-update после успешной операции с расширением спрашивают платформу явно и печатают предупреждение; код возврата операции не меняется — применение неприменимого расширения не разрушительно, платформа просто работает по оригиналу. Поднять код возврата может -StrictLog, он для регрессов и в инструкциях не значится. Проверка обязана быть ОТДЕЛЬНЫМ запуском платформы: в одной командной строке DESIGNER выполняет только последнюю пакетную команду, и дописанная проверка отменила бы саму загрузку (замер: /LoadConfigFromFiles + /CheckCanApply… → код 0, пустой лог, расширение в базе не изменилось). Об этом сказано в теле функции, чтобы «оптимизация» не вернула команды в одну строку. Выключатель: ключ -NoApplyCheck и настройка проекта extensionApplyCheck (ключ команды сильнее). В ветке ibcmd проверка идёт соседним 1cv8; если его рядом нет — одна строка [note], а не тишина. Общий блок (Invoke-ApplyCheck / Invoke-ApplyCheckReport / Get-ApplyCheckEnabled и их py-двойники) объявлен семьёй в check-inline-drift.mjs: разъехавшиеся копии означали бы, что один навык предупреждает, а соседний по той же операции молчит. db-load-cf получил недостающие копии Find-V8Project и ключ -StrictLog. Раннер: у фейковой платформы появился отдельный ответ на проверку (spec.check), выбираемый по составу аргументов, — иначе сценарий «загрузка прошла, проверка провалилась» невыразим. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QoAJmoNbgWKobA7JGgN5S3
This commit is contained in:
co-authored by
Claude Opus 5
parent
5943828216
commit
a3ea0b7be6
@@ -517,6 +517,76 @@ def find_silent_rejections(log_text):
|
||||
return found
|
||||
|
||||
|
||||
def run_apply_check(exe, conn_args, extension, extra_args):
|
||||
"""Постусловие применимости расширения: платформа отчитывается успехом и о расширении,
|
||||
которое не применит — отказ всплывает лениво, при первом вызове метода, записью в журнал
|
||||
регистрации.
|
||||
|
||||
Запуск ОБЯЗАТЕЛЬНО отдельный. Дописать эту команду в строку операции нельзя: в одной
|
||||
командной строке DESIGNER выполняет только ПОСЛЕДНЮЮ пакетную команду, остальные молча
|
||||
отбрасывает — проверено на 8.3.24, /LoadConfigFromFiles вместе с
|
||||
/CheckCanApplyConfigurationExtensions завершились кодом 0 с пустым логом, и загрузка не
|
||||
состоялась.
|
||||
|
||||
Проверку умеет только 1cv8; если навык работал через ibcmd, берём соседний файл.
|
||||
"""
|
||||
exe_dir = os.path.dirname(exe)
|
||||
leaf = os.path.basename(exe)
|
||||
if leaf.lower().startswith("ibcmd"):
|
||||
v8 = os.path.join(exe_dir, "1cv8" + os.path.splitext(leaf)[1])
|
||||
else:
|
||||
v8 = exe
|
||||
if not os.path.isfile(v8):
|
||||
return {"skipped": True, "reason": f"1cv8 not found at {v8}", "exit": 0, "lines": []}
|
||||
temp_dir = tempfile.mkdtemp(prefix="apply_check_")
|
||||
try:
|
||||
a = ["DESIGNER"] + list(conn_args) + ["/CheckCanApplyConfigurationExtensions"]
|
||||
if extension:
|
||||
a += ["-Extension", f'"{extension}"']
|
||||
out_file = os.path.join(temp_dir, "check_log.txt")
|
||||
a += ["/Out", f'"{out_file}"', "/DisableStartupDialogs"]
|
||||
a += list(extra_args)
|
||||
r = run_v8(v8, a)
|
||||
lines = []
|
||||
if os.path.isfile(out_file):
|
||||
with open(out_file, encoding="utf-8-sig", errors="replace") as f:
|
||||
lines = [x.strip() for x in f.read().splitlines() if x.strip()]
|
||||
return {"skipped": False, "reason": "", "exit": r.returncode, "lines": lines}
|
||||
finally:
|
||||
shutil.rmtree(temp_dir, ignore_errors=True)
|
||||
|
||||
|
||||
def apply_check_report(exe, conn_args, extension, extra_args):
|
||||
"""Проверить и напечатать. True, если платформа расширение не применит — вызывающий решает,
|
||||
поднимать ли код возврата (строгий режим)."""
|
||||
ac = run_apply_check(exe, conn_args, extension, extra_args)
|
||||
if ac["skipped"]:
|
||||
print(f"[note] applicability check skipped: {ac['reason']}")
|
||||
return False
|
||||
if ac["exit"] != 0 or ac["lines"]:
|
||||
print("[warning] the extension is loaded, but the platform will not apply it:")
|
||||
for line in ac["lines"]:
|
||||
print(f" {line}")
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def apply_check_enabled(disabled):
|
||||
"""Проверять ли применимость: -NoApplyCheck сильнее настройки проекта."""
|
||||
if disabled:
|
||||
return False
|
||||
pf = _sg_find_v8project(os.getcwd())
|
||||
if pf:
|
||||
try:
|
||||
with open(pf, encoding="utf-8-sig") as f:
|
||||
proj = json.load(f)
|
||||
if proj.get("extensionApplyCheck") is not None:
|
||||
return bool(proj.get("extensionApplyCheck"))
|
||||
except Exception:
|
||||
pass
|
||||
return True
|
||||
|
||||
|
||||
def run_ibcmd(cmd, has_username=False, warn_no_user=True):
|
||||
"""Run an ibcmd command non-interactively.
|
||||
|
||||
@@ -626,6 +696,8 @@ def main():
|
||||
# намеренно не выносится. Поднимает код возврата, если платформа отчиталась об успехе,
|
||||
# но в логе есть отбраковка.
|
||||
parser.add_argument("-StrictLog", action="store_true")
|
||||
# Пропустить проверку применимости расширения после загрузки.
|
||||
parser.add_argument("-NoApplyCheck", action="store_true")
|
||||
parser.add_argument("-AdditionalV8Arguments", nargs="*", default=[],
|
||||
help="Extra 1cv8 arguments, e.g. /UseHwLicenses+")
|
||||
parser.add_argument("-AdditionalIbcmdArguments", nargs="*", default=[],
|
||||
@@ -828,6 +900,17 @@ def main():
|
||||
else:
|
||||
print(f"Error updating database configuration (code: {exit_code}){describe_exit(exit_code)}")
|
||||
print_platform_output(ar)
|
||||
# Проверку применимости умеет только 1cv8 — соединение для неё собираем в его форме.
|
||||
if (exit_code == 0 and (args.Extension or args.AllExtensions)
|
||||
and apply_check_enabled(args.NoApplyCheck)):
|
||||
ac_conn = ["/F", f'"{args.InfoBasePath}"']
|
||||
if args.UserName:
|
||||
ac_conn.append(f'/N"{args.UserName}"')
|
||||
if args.Password:
|
||||
ac_conn.append(f'/P"{args.Password}"')
|
||||
if apply_check_report(v8path, ac_conn, args.Extension, []) and args.StrictLog:
|
||||
exit_code = 1
|
||||
|
||||
sys.exit(exit_code)
|
||||
|
||||
# --- Write list file (UTF-8 with BOM) ---
|
||||
@@ -836,22 +919,25 @@ def main():
|
||||
f.write("\n".join(config_files))
|
||||
|
||||
# --- Build arguments ---
|
||||
arguments = ["DESIGNER"]
|
||||
# Аргументы соединения собираем отдельно: тем же набором пойдёт проверка применимости.
|
||||
conn_args = []
|
||||
|
||||
if args.InfoBaseServer and args.InfoBaseRef:
|
||||
arguments += ["/S", f'"{args.InfoBaseServer}/{args.InfoBaseRef}"']
|
||||
conn_args += ["/S", f'"{args.InfoBaseServer}/{args.InfoBaseRef}"']
|
||||
else:
|
||||
arguments += ["/F", f'"{args.InfoBasePath}"']
|
||||
conn_args += ["/F", f'"{args.InfoBasePath}"']
|
||||
|
||||
if args.UserName:
|
||||
arguments.append(f'/N"{args.UserName}"')
|
||||
conn_args.append(f'/N"{args.UserName}"')
|
||||
if args.Password:
|
||||
arguments.append(f'/P"{args.Password}"')
|
||||
conn_args.append(f'/P"{args.Password}"')
|
||||
|
||||
# База под хранилищем не примет НИ ОДНОЙ операции конфигуратора без этих реквизитов, а для
|
||||
# базы вне хранилища они безвредны — поэтому подставляем всегда, когда они известны.
|
||||
repo = resolve_repository_settings(args)
|
||||
arguments.extend(repository_args(repo))
|
||||
conn_args.extend(repository_args(repo))
|
||||
|
||||
arguments = ["DESIGNER"] + conn_args
|
||||
|
||||
arguments += ["/LoadConfigFromFiles", f'"{args.ConfigDir}"']
|
||||
arguments += ["-listFile", f'"{list_file}"']
|
||||
@@ -919,6 +1005,12 @@ def main():
|
||||
if args.StrictLog and exit_code == 0:
|
||||
exit_code = 1
|
||||
|
||||
# Расширение могло загрузиться «успешно» и остаться неприменимым — спрашиваем платформу.
|
||||
if (exit_code == 0 and (args.Extension or args.AllExtensions)
|
||||
and apply_check_enabled(args.NoApplyCheck)):
|
||||
if apply_check_report(v8path, conn_args, args.Extension, extra_args) and args.StrictLog:
|
||||
exit_code = 1
|
||||
|
||||
sys.exit(exit_code)
|
||||
|
||||
finally:
|
||||
|
||||
Reference in New Issue
Block a user