mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-07-31 00:37:47 +03:00
fix(epf-dump): постусловие выходного каталога + маскировка учётных данных
Пропущенный при разборе #49-52 навык того же класса: epf-dump разбирает EPF/ERF через платформу в каталог XML. Успех определялся только по коду возврата (ложный успех при пустом выходе), а строка Running светила /P<пароль> (1cv8) и --password= (ibcmd). Добавлены postcondition непустого OutputDir и маскировка, обе ветки, оба порта. Покрывает и erf-dump (общий скрипт). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
00cd0f3f5f
commit
06485d216b
@@ -1,4 +1,4 @@
|
|||||||
# epf-dump v1.6 — Dump external data processor or report (EPF/ERF) to XML sources
|
# epf-dump v1.7 — Dump external data processor or report (EPF/ERF) to XML sources
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
# NB: *nix-раскладку платформы (/opt/1cv8/<ver>/1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется.
|
# NB: *nix-раскладку платформы (/opt/1cv8/<ver>/1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется.
|
||||||
<#
|
<#
|
||||||
@@ -155,6 +155,19 @@ function Invoke-IbcmdProcess {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function Test-DirNonEmpty {
|
||||||
|
# Postcondition: the platform must have written files into the output directory.
|
||||||
|
# Exit code 0 with an empty dir (broken/headless env) is a false success — reject it.
|
||||||
|
param([string]$Path)
|
||||||
|
return (Test-Path $Path -PathType Container) -and ([bool](Get-ChildItem -LiteralPath $Path -Force -ErrorAction SilentlyContinue | Select-Object -First 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
function Format-SafeArgs {
|
||||||
|
# Mask credential tokens (/N, /P for 1cv8; --user=, --password= for ibcmd) for display.
|
||||||
|
param([string[]]$A)
|
||||||
|
($A | ForEach-Object { $_ -replace '^(/[NP]).+', '$1***' -replace '^(--(user|password)=).+', '$1***' }) -join ' '
|
||||||
|
}
|
||||||
|
|
||||||
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
||||||
if ($engine -eq "ibcmd") {
|
if ($engine -eq "ibcmd") {
|
||||||
if (-not $InfoBasePath) {
|
if (-not $InfoBasePath) {
|
||||||
@@ -189,12 +202,16 @@ try {
|
|||||||
if ($UserName) { $arguments += "--user=$UserName" }
|
if ($UserName) { $arguments += "--user=$UserName" }
|
||||||
if ($Password) { $arguments += "--password=$Password" }
|
if ($Password) { $arguments += "--password=$Password" }
|
||||||
$arguments += "--data=$tempDir"
|
$arguments += "--data=$tempDir"
|
||||||
Write-Host "Running: ibcmd $($arguments -join ' ')"
|
Write-Host "Running: ibcmd $(Format-SafeArgs $arguments)"
|
||||||
$__ib = Invoke-IbcmdProcess $V8Path $arguments
|
$__ib = Invoke-IbcmdProcess $V8Path $arguments
|
||||||
$output = $__ib.Output
|
$output = $__ib.Output
|
||||||
$exitCode = $__ib.ExitCode
|
$exitCode = $__ib.ExitCode
|
||||||
|
$outMissing = ($exitCode -eq 0) -and -not (Test-DirNonEmpty $OutputDir)
|
||||||
|
if ($outMissing) { $exitCode = 1 }
|
||||||
if ($exitCode -eq 0) {
|
if ($exitCode -eq 0) {
|
||||||
Write-Host "External data processor/report dumped successfully to: $OutputDir" -ForegroundColor Green
|
Write-Host "External data processor/report dumped successfully to: $OutputDir" -ForegroundColor Green
|
||||||
|
} elseif ($outMissing) {
|
||||||
|
Write-Host "Error: exit code 0 but no files under $OutputDir — dump produced no output" -ForegroundColor Red
|
||||||
} else {
|
} else {
|
||||||
Write-Host "Error dumping external data processor/report (code: $exitCode)" -ForegroundColor Red
|
Write-Host "Error dumping external data processor/report (code: $exitCode)" -ForegroundColor Red
|
||||||
}
|
}
|
||||||
@@ -224,13 +241,18 @@ try {
|
|||||||
$arguments += "/DisableStartupDialogs"
|
$arguments += "/DisableStartupDialogs"
|
||||||
|
|
||||||
# --- Execute ---
|
# --- Execute ---
|
||||||
Write-Host "Running: 1cv8.exe $($arguments -join ' ')"
|
Write-Host "Running: 1cv8.exe $(Format-SafeArgs $arguments)"
|
||||||
$process = Start-Process -FilePath $V8Path -ArgumentList $arguments -NoNewWindow -Wait -PassThru
|
$process = Start-Process -FilePath $V8Path -ArgumentList $arguments -NoNewWindow -Wait -PassThru
|
||||||
$exitCode = $process.ExitCode
|
$exitCode = $process.ExitCode
|
||||||
|
|
||||||
# --- Result ---
|
# --- Result ---
|
||||||
|
# Postcondition: exit 0 with an empty output directory is a false success.
|
||||||
|
$outMissing = ($exitCode -eq 0) -and -not (Test-DirNonEmpty $OutputDir)
|
||||||
|
if ($outMissing) { $exitCode = 1 }
|
||||||
if ($exitCode -eq 0) {
|
if ($exitCode -eq 0) {
|
||||||
Write-Host "Dump completed successfully to: $OutputDir" -ForegroundColor Green
|
Write-Host "Dump completed successfully to: $OutputDir" -ForegroundColor Green
|
||||||
|
} elseif ($outMissing) {
|
||||||
|
Write-Host "Error: exit code 0 but no files under $OutputDir — dump produced no output" -ForegroundColor Red
|
||||||
} else {
|
} else {
|
||||||
Write-Host "Error dumping (code: $exitCode)" -ForegroundColor Red
|
Write-Host "Error dumping (code: $exitCode)" -ForegroundColor Red
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# epf-dump v1.6 — Dump external data processor or report (EPF/ERF) to XML sources
|
# epf-dump v1.7 — Dump external data processor or report (EPF/ERF) to XML sources
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -99,6 +99,22 @@ def run_ibcmd(cmd, has_username=False, warn_no_user=True):
|
|||||||
return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace")
|
return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace")
|
||||||
|
|
||||||
|
|
||||||
|
def dir_nonempty(path):
|
||||||
|
"""Postcondition: the platform must have written files into the output directory.
|
||||||
|
Exit code 0 with an empty dir (broken/headless env) is a false success — reject it."""
|
||||||
|
return os.path.isdir(path) and any(os.scandir(path))
|
||||||
|
|
||||||
|
|
||||||
|
def _mask(args):
|
||||||
|
"""Mask credential tokens (/N, /P for 1cv8; --user=, --password= for ibcmd) for display."""
|
||||||
|
out = []
|
||||||
|
for a in args:
|
||||||
|
a = re.sub(r"^(/[NP]).+", r"\1***", a)
|
||||||
|
a = re.sub(r"^(--(?:user|password)=).+", r"\1***", a)
|
||||||
|
out.append(a)
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
sys.stdout.reconfigure(encoding="utf-8")
|
sys.stdout.reconfigure(encoding="utf-8")
|
||||||
sys.stderr.reconfigure(encoding="utf-8")
|
sys.stderr.reconfigure(encoding="utf-8")
|
||||||
@@ -163,17 +179,23 @@ def main():
|
|||||||
if args.Password:
|
if args.Password:
|
||||||
arguments.append(f"--password={args.Password}")
|
arguments.append(f"--password={args.Password}")
|
||||||
arguments.append(f"--data={ib_data}")
|
arguments.append(f"--data={ib_data}")
|
||||||
print(f"Running: ibcmd {' '.join(arguments)}")
|
print(f"Running: ibcmd {' '.join(_mask(arguments))}")
|
||||||
result = run_ibcmd([v8path] + arguments, warn_no_user=False)
|
result = run_ibcmd([v8path] + arguments, warn_no_user=False)
|
||||||
if result.returncode == 0:
|
exit_code = result.returncode
|
||||||
|
out_missing = exit_code == 0 and not dir_nonempty(args.OutputDir)
|
||||||
|
if out_missing:
|
||||||
|
exit_code = 1
|
||||||
|
if exit_code == 0:
|
||||||
print(f"External data processor/report dumped successfully to: {args.OutputDir}")
|
print(f"External data processor/report dumped successfully to: {args.OutputDir}")
|
||||||
|
elif out_missing:
|
||||||
|
print(f"Error: exit code 0 but no files under {args.OutputDir} — dump produced no output", file=sys.stderr)
|
||||||
else:
|
else:
|
||||||
print(f"Error dumping external data processor/report (code: {result.returncode})", file=sys.stderr)
|
print(f"Error dumping external data processor/report (code: {exit_code})", file=sys.stderr)
|
||||||
if result.stdout:
|
if result.stdout:
|
||||||
print(result.stdout)
|
print(result.stdout)
|
||||||
if result.stderr:
|
if result.stderr:
|
||||||
print(result.stderr, file=sys.stderr)
|
print(result.stderr, file=sys.stderr)
|
||||||
sys.exit(result.returncode)
|
sys.exit(exit_code)
|
||||||
|
|
||||||
# --- Build arguments ---
|
# --- Build arguments ---
|
||||||
arguments = ["DESIGNER"]
|
arguments = ["DESIGNER"]
|
||||||
@@ -197,7 +219,7 @@ def main():
|
|||||||
arguments.append("/DisableStartupDialogs")
|
arguments.append("/DisableStartupDialogs")
|
||||||
|
|
||||||
# --- Execute ---
|
# --- Execute ---
|
||||||
print(f"Running: 1cv8.exe {' '.join(arguments)}")
|
print(f"Running: 1cv8.exe {' '.join(_mask(arguments))}")
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
[v8path] + arguments,
|
[v8path] + arguments,
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
@@ -206,8 +228,14 @@ def main():
|
|||||||
exit_code = result.returncode
|
exit_code = result.returncode
|
||||||
|
|
||||||
# --- Result ---
|
# --- Result ---
|
||||||
|
# Postcondition: exit 0 with an empty output directory is a false success.
|
||||||
|
out_missing = exit_code == 0 and not dir_nonempty(args.OutputDir)
|
||||||
|
if out_missing:
|
||||||
|
exit_code = 1
|
||||||
if exit_code == 0:
|
if exit_code == 0:
|
||||||
print(f"Dump completed successfully to: {args.OutputDir}")
|
print(f"Dump completed successfully to: {args.OutputDir}")
|
||||||
|
elif out_missing:
|
||||||
|
print(f"Error: exit code 0 but no files under {args.OutputDir} — dump produced no output", file=sys.stderr)
|
||||||
else:
|
else:
|
||||||
print(f"Error dumping (code: {exit_code})", file=sys.stderr)
|
print(f"Error dumping (code: {exit_code})", file=sys.stderr)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user