Auto-build: codeassistant (powershell) from 6188749

This commit is contained in:
github-actions[bot]
2026-09-29 18:37:55 +00:00
commit 11b38478d7
350 changed files with 208187 additions and 0 deletions
@@ -0,0 +1,199 @@
# v8-xsd-fetch v1.0 — Download 1C platform XSD schemas (dump format) into .v8-xsd
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
<#
.SYNOPSIS
Загрузка XSD-схем формата выгрузки 1С по версиям формата
.DESCRIPTION
Скачивает schemas/designer/<версия>/*.xsd из репозитория yellow-hammer/namespace-forest
в каталог схем проекта: -OutPath, иначе xsdPath из .v8-project.json, иначе .v8-xsd
рядом с .v8-project.json (нет его — в текущем каталоге).
.EXAMPLE
.\v8-xsd-fetch.ps1 -Versions "2.20,2.21"
.EXAMPLE
.\v8-xsd-fetch.ps1 -List
#>
[CmdletBinding(PositionalBinding=$false)]
param(
# Списком одной строкой: powershell -File не связывает массивы
[Parameter(Mandatory=$false)]
[string]$Versions,
[Parameter(Mandatory=$false)]
[string]$OutPath,
[Parameter(Mandatory=$false)]
[string]$Ref = "main",
[Parameter(Mandatory=$false)]
[switch]$Force,
[Parameter(Mandatory=$false)]
[switch]$List
)
$ErrorActionPreference = "Stop"
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$repo = "yellow-hammer/namespace-forest"
$repoUrl = "https://github.com/$repo"
# Текст README — в templates/ навыка, одна копия на оба порта
$readmeTemplate = Join-Path $PSScriptRoot "../templates/README.md"
function Find-V8Project([string]$startDir) {
$d = $startDir
for ($i = 0; $i -lt 20 -and $d; $i++) {
$pj = Join-Path $d ".v8-project.json"
if (Test-Path $pj) { return $pj }
$parent = [System.IO.Path]::GetDirectoryName($d)
if ($parent -eq $d) { break }
$d = $parent
}
return $null
}
function Fail([string]$msg) {
Write-Host "Error: $msg" -ForegroundColor Red
exit 1
}
# --- Версии: проверяем до сети ---
$wanted = @()
if ($Versions) {
foreach ($v in ($Versions -split '[,;\s]+')) {
if (-not $v) { continue }
if ($v -notmatch '^\d+\.\d+$') { Fail "неверная версия формата '$v' (ожидается вида 2.20)" }
if ($wanted -notcontains $v) { $wanted += $v }
}
}
# --- Каталог схем ---
$cwd = (Get-Location).Path
$pj = Find-V8Project $cwd
$target = $null
if ($OutPath) {
$target = if ([System.IO.Path]::IsPathRooted($OutPath)) { $OutPath } else { Join-Path $cwd $OutPath }
} elseif ($pj) {
$pjDir = [System.IO.Path]::GetDirectoryName($pj)
try { $cfg = Get-Content -LiteralPath $pj -Raw -Encoding UTF8 | ConvertFrom-Json } catch { $cfg = $null }
if ($cfg -and $cfg.xsdPath) {
$target = if ([System.IO.Path]::IsPathRooted($cfg.xsdPath)) { $cfg.xsdPath } else { Join-Path $pjDir $cfg.xsdPath }
} else {
$target = Join-Path $pjDir ".v8-xsd"
}
} else {
$target = Join-Path $cwd ".v8-xsd"
}
$target = [System.IO.Path]::GetFullPath($target)
if (Test-Path -LiteralPath $target -PathType Leaf) { Fail "каталог схем '$target' — это файл" }
# --- Состав репозитория ---
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$wc = New-Object System.Net.WebClient
$wc.Headers.Add("User-Agent", "v8-xsd-fetch")
$wc.Encoding = [System.Text.Encoding]::UTF8
try {
$tree = $wc.DownloadString("https://api.github.com/repos/$repo/git/trees/$([uri]::EscapeDataString($Ref))?recursive=1") | ConvertFrom-Json
} catch {
Fail "не удалось получить состав $repo@${Ref}: $($_.Exception.Message)`nСкачайте вручную каталоги schemas/designer/<версия> из $repoUrl в '$target'"
}
$commit = $tree.sha
$byVersion = @{}
foreach ($node in $tree.tree) {
if ($node.type -ne 'blob') { continue }
$m = [regex]::Match($node.path, '^schemas/designer/(\d+\.\d+)/([^/]+\.xsd)$')
if (-not $m.Success) { continue }
$v = $m.Groups[1].Value
if (-not $byVersion.ContainsKey($v)) { $byVersion[$v] = New-Object System.Collections.ArrayList }
[void]$byVersion[$v].Add(@{ path = $node.path; name = $m.Groups[2].Value })
}
$available = @($byVersion.Keys | Sort-Object { [version]$_ })
if ($available.Count -eq 0) { Fail "в $repo@$Ref нет каталогов schemas/designer/<версия>" }
if ($List) {
Write-Host "Версии формата в $repo@${Ref}:"
foreach ($v in $available) {
$mark = if (Test-Path -LiteralPath (Join-Path $target $v) -PathType Container) { " (есть локально)" } else { "" }
Write-Host " $v — $($byVersion[$v].Count) схем$mark"
}
Write-Host "Каталог схем: $target"
exit 0
}
if ($wanted.Count -eq 0) { $wanted = $available }
$missing = @($wanted | Where-Object { $available -notcontains $_ })
if ($missing.Count -gt 0) {
Fail "версии $($missing -join ', ') нет в $repo@$Ref (есть: $($available -join ', '))"
}
# --- Загрузка ---
if (-not (Test-Path -LiteralPath $target)) { New-Item -ItemType Directory -Path $target -Force | Out-Null }
$fetched = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
# Происхождение — по версиям: уже лежащие файлы без -Force не перекачиваются, поэтому коммит
# версии обновляем, только когда её файлы действительно скачаны в этом запуске
$srcPath = Join-Path $target "source.json"
$srcVers = @{}
if (Test-Path -LiteralPath $srcPath) {
try {
$old = Get-Content -LiteralPath $srcPath -Raw -Encoding UTF8 | ConvertFrom-Json
if ($old.versions -is [PSCustomObject]) {
foreach ($pr in $old.versions.PSObject.Properties) {
$srcVers[$pr.Name] = @{ ref = "$($pr.Value.ref)"; commit = "$($pr.Value.commit)"; fetched = "$($pr.Value.fetched)" }
}
}
} catch { }
}
$totalNew = 0
foreach ($v in ($wanted | Sort-Object { [version]$_ })) {
$dir = Join-Path $target $v
if (-not (Test-Path -LiteralPath $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
$got = 0; $kept = 0
foreach ($f in $byVersion[$v]) {
$dest = Join-Path $dir $f.name
if ((Test-Path -LiteralPath $dest) -and -not $Force) { $kept++; continue }
# Файлы берём по коммиту, а не по ветке: весь набор — из одного состояния репозитория
$url = "https://raw.githubusercontent.com/$repo/$commit/$($f.path)"
try {
$bytes = $wc.DownloadData($url)
} catch {
Fail "не удалось скачать $($f.path): $($_.Exception.Message)"
}
[System.IO.File]::WriteAllBytes($dest, $bytes)
$got++
}
$totalNew += $got
if ($got -gt 0) { $srcVers[$v] = @{ ref = $Ref; commit = $commit; fetched = $fetched } }
$line = " ${v}: скачано $got"
if ($kept -gt 0) { $line += ", уже было $kept" }
Write-Host $line
}
# --- README и source.json ---
$readmePath = Join-Path $target "README.md"
if (-not (Test-Path -LiteralPath $readmePath) -and (Test-Path -LiteralPath $readmeTemplate)) {
Copy-Item -LiteralPath $readmeTemplate -Destination $readmePath
}
$localVersions = @(Get-ChildItem -LiteralPath $target -Directory |
Where-Object { $_.Name -match '^\d+\.\d+$' } |
ForEach-Object { $_.Name } | Sort-Object { [version]$_ })
# Руками, а не ConvertTo-Json: форматирование PS 5.1 не совпало бы с py-портом.
# Версия без записи о происхождении (скопирована вручную) — с пустыми полями.
function Esc-Json([string]$s) { return ($s -replace '\\', '\\' -replace '"', '\"') }
$verLines = @()
foreach ($v in $localVersions) {
$e = if ($srcVers.ContainsKey($v)) { $srcVers[$v] } else { @{ ref = ''; commit = ''; fetched = '' } }
$verLines += " `"$v`": { `"ref`": `"$(Esc-Json $e.ref)`", `"commit`": `"$(Esc-Json $e.commit)`", `"fetched`": `"$(Esc-Json $e.fetched)`" }"
}
$verBlock = if ($verLines.Count -gt 0) { "{`n" + ($verLines -join ",`n") + "`n }" } else { "{}" }
$srcJson = "{`n `"repository`": `"$repoUrl`",`n `"versions`": $verBlock`n}`n"
$enc = New-Object System.Text.UTF8Encoding($false)
[System.IO.File]::WriteAllText($srcPath, $srcJson, $enc)
Write-Host "Схемы: $target (скачано файлов: $totalNew)"
@@ -0,0 +1,233 @@
#!/usr/bin/env python3
# v8-xsd-fetch v1.0 — Download 1C platform XSD schemas (dump format) into .v8-xsd
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
"""Загрузка XSD-схем формата выгрузки 1С по версиям формата.
Скачивает schemas/designer/<версия>/*.xsd из репозитория yellow-hammer/namespace-forest
в каталог схем проекта: -OutPath, иначе xsdPath из .v8-project.json, иначе .v8-xsd
рядом с .v8-project.json (нет его — в текущем каталоге).
"""
import argparse
import json
import os
import re
import shutil
import sys
import urllib.parse
import urllib.request
from datetime import datetime, timezone
sys.stdout.reconfigure(encoding="utf-8")
sys.stderr.reconfigure(encoding="utf-8")
REPO = "yellow-hammer/namespace-forest"
REPO_URL = "https://github.com/" + REPO
TIMEOUT = 60
# Текст README — в templates/ навыка, одна копия на оба порта
README_TEMPLATE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "templates", "README.md")
def ci_parse_args(parser, argv=None):
"""parse_args по правилам PS: имена параметров и значения choices регистронезависимы."""
argv = list(sys.argv[1:] if argv is None else argv)
names = {s.lower(): s for a in parser._actions for s in a.option_strings}
for i, tok in enumerate(argv):
if tok.startswith('-') and tok.lower() in names:
argv[i] = names[tok.lower()]
# choices — зеркало [ValidateSet]; канонизируем ДО разбора, иначе argparse отвергнет регистр
choice_map = {}
for a in parser._actions:
if a.choices:
for s in a.option_strings:
choice_map[s] = {str(c).lower(): c for c in a.choices}
for i in range(len(argv) - 1):
m = choice_map.get(argv[i])
if m and argv[i + 1].lower() in m:
argv[i + 1] = m[argv[i + 1].lower()]
return parser.parse_args(argv)
def _sg_find_v8project(start_dir):
d = start_dir
for _ in range(20):
if not d:
break
pj = os.path.join(d, ".v8-project.json")
if os.path.isfile(pj):
return pj
parent = os.path.dirname(d)
if parent == d:
break
d = parent
return None
def fail(msg):
print("Error: " + msg)
sys.exit(1)
def version_key(v):
return tuple(int(x) for x in v.split("."))
def http_get(url):
req = urllib.request.Request(url, headers={"User-Agent": "v8-xsd-fetch"})
with urllib.request.urlopen(req, timeout=TIMEOUT) as resp:
return resp.read()
def main():
parser = argparse.ArgumentParser(description="Download 1C platform XSD schemas into .v8-xsd", allow_abbrev=False)
# Списком одной строкой — паритет с PS: powershell -File не связывает массивы
parser.add_argument("-Versions", default="")
parser.add_argument("-OutPath", default="")
parser.add_argument("-Ref", default="main")
parser.add_argument("-Force", action="store_true")
parser.add_argument("-List", action="store_true")
args = ci_parse_args(parser)
ref = args.Ref
# --- Версии: проверяем до сети ---
wanted = []
if args.Versions:
for v in re.split(r"[,;\s]+", args.Versions):
if not v:
continue
if not re.match(r"^\d+\.\d+$", v):
fail("неверная версия формата '%s' (ожидается вида 2.20)" % v)
if v not in wanted:
wanted.append(v)
# --- Каталог схем ---
cwd = os.getcwd()
pj = _sg_find_v8project(cwd)
if args.OutPath:
target = args.OutPath if os.path.isabs(args.OutPath) else os.path.join(cwd, args.OutPath)
elif pj:
pj_dir = os.path.dirname(pj)
try:
with open(pj, encoding="utf-8-sig") as f:
cfg = json.load(f)
except Exception:
cfg = None
xsd_path = cfg.get("xsdPath") if isinstance(cfg, dict) else None
if xsd_path:
target = xsd_path if os.path.isabs(xsd_path) else os.path.join(pj_dir, xsd_path)
else:
target = os.path.join(pj_dir, ".v8-xsd")
else:
target = os.path.join(cwd, ".v8-xsd")
target = os.path.abspath(target)
if os.path.isfile(target):
fail("каталог схем '%s' — это файл" % target)
# --- Состав репозитория ---
try:
tree = json.loads(http_get("https://api.github.com/repos/%s/git/trees/%s?recursive=1"
% (REPO, urllib.parse.quote(ref, safe=""))).decode("utf-8"))
except Exception as e:
fail("не удалось получить состав %s@%s: %s\nСкачайте вручную каталоги schemas/designer/<версия> из %s в '%s'"
% (REPO, ref, e, REPO_URL, target))
commit = tree.get("sha", "")
by_version = {}
for node in tree.get("tree", []):
if node.get("type") != "blob":
continue
m = re.match(r"^schemas/designer/(\d+\.\d+)/([^/]+\.xsd)$", node.get("path", ""))
if not m:
continue
by_version.setdefault(m.group(1), []).append({"path": node["path"], "name": m.group(2)})
available = sorted(by_version.keys(), key=version_key)
if not available:
fail("в %s@%s нет каталогов schemas/designer/<версия>" % (REPO, ref))
if args.List:
print("Версии формата в %s@%s:" % (REPO, ref))
for v in available:
mark = " (есть локально)" if os.path.isdir(os.path.join(target, v)) else ""
print(" %s — %d схем%s" % (v, len(by_version[v]), mark))
print("Каталог схем: " + target)
sys.exit(0)
if not wanted:
wanted = list(available)
missing = [v for v in wanted if v not in available]
if missing:
fail("версии %s нет в %s@%s (есть: %s)" % (", ".join(missing), REPO, ref, ", ".join(available)))
# --- Загрузка ---
os.makedirs(target, exist_ok=True)
fetched = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
# Происхождение — по версиям: уже лежащие файлы без -Force не перекачиваются, поэтому коммит
# версии обновляем, только когда её файлы действительно скачаны в этом запуске
src_path = os.path.join(target, "source.json")
src_vers = {}
if os.path.isfile(src_path):
try:
with open(src_path, encoding="utf-8-sig") as fh:
old = json.load(fh)
if isinstance(old.get("versions"), dict):
for k, e in old["versions"].items():
e = e if isinstance(e, dict) else {}
src_vers[k] = {"ref": str(e.get("ref") or ""), "commit": str(e.get("commit") or ""),
"fetched": str(e.get("fetched") or "")}
except Exception:
pass
total_new = 0
for v in sorted(wanted, key=version_key):
vdir = os.path.join(target, v)
os.makedirs(vdir, exist_ok=True)
got = kept = 0
for f in by_version[v]:
dest = os.path.join(vdir, f["name"])
if os.path.exists(dest) and not args.Force:
kept += 1
continue
# Файлы берём по коммиту, а не по ветке: весь набор — из одного состояния репозитория
url = "https://raw.githubusercontent.com/%s/%s/%s" % (REPO, commit, f["path"])
try:
data = http_get(url)
except Exception as e:
fail("не удалось скачать %s: %s" % (f["path"], e))
with open(dest, "wb") as out:
out.write(data)
got += 1
total_new += got
if got > 0:
src_vers[v] = {"ref": ref, "commit": commit, "fetched": fetched}
line = " %s: скачано %d" % (v, got)
if kept > 0:
line += ", уже было %d" % kept
print(line)
# --- README и source.json ---
readme_path = os.path.join(target, "README.md")
if not os.path.exists(readme_path) and os.path.isfile(README_TEMPLATE):
shutil.copyfile(README_TEMPLATE, readme_path)
local_versions = sorted((d for d in os.listdir(target)
if re.match(r"^\d+\.\d+$", d) and os.path.isdir(os.path.join(target, d))),
key=version_key)
# Руками, а не json.dumps: форматирование совпадает с PS-мастером.
# Версия без записи о происхождении (скопирована вручную) — с пустыми полями.
def esc_json(s):
return s.replace("\\", "\\\\").replace('"', '\\"')
ver_lines = []
for v in local_versions:
e = src_vers.get(v) or {"ref": "", "commit": "", "fetched": ""}
ver_lines.append(' "%s": { "ref": "%s", "commit": "%s", "fetched": "%s" }'
% (v, esc_json(e["ref"]), esc_json(e["commit"]), esc_json(e["fetched"])))
ver_block = "{\n" + ",\n".join(ver_lines) + "\n }" if ver_lines else "{}"
src_json = '{\n "repository": "%s",\n "versions": %s\n}\n' % (REPO_URL, ver_block)
with open(src_path, "w", encoding="utf-8", newline="\n") as out:
out.write(src_json)
print("Схемы: %s (скачано файлов: %d)" % (target, total_new))
if __name__ == "__main__":
main()