- проверка gcc перенесена после чтения creds (шаг 1a) - GCC_PATH дописывается в PATH (абсолютный или относительно scripts/); без него — gcc из текущего PATH - комментарии в шапку: GCC_PATH и уточнённый PROJECT_PATH
146 lines
7.7 KiB
PowerShell
146 lines
7.7 KiB
PowerShell
<#
|
||
build-publish-ui.ps1 — локальная сборка Windows-бинаря с UI (Fyne) и публикация в Gitea Packages.
|
||
|
||
Почему локально: Fyne-окно требует cgo + C-компилятор (MinGW/gcc), которых нет в CI.
|
||
CI собирает ТОЛЬКО headless-linux (см. .gitea/workflows/ci.yaml). Windows-бинарь
|
||
с графическим окном собирается на Windows-машине Камиля и публикуется скриптом ниже
|
||
в ту же версию commit-<sha7>, что и CI, с теми же companion-файлами (.version/.sha256),
|
||
чтобы автообновление (U4 checksum, ResolveLatest) работало без изменений.
|
||
|
||
Требования:
|
||
- Go с доступным C-компилятором (CGO_ENABLED=1). WinLibs gcc: см. память
|
||
`mem:binator/cgo-winlibs-gcc`. Каталог с gcc.exe можно задать через
|
||
GCC_PATH (ниже); если не задан — gcc должен быть уже в PATH.
|
||
- Файл scripts/.gitea-creds (git-ignored, см. ниже) с токенами.
|
||
Формат (по одной `ключ=значение` на строку):
|
||
GITEA_TOKEN=write:packages-токен
|
||
UPDATE_TOKEN=read:package-токен
|
||
GIT_MAIN_URL=http://gitea.hal9000.home
|
||
PROJECT_PATH=..\..\foo (опционально) корень проекта (где лежат cmd/
|
||
и go.mod); относительно папки scripts/ или
|
||
абсолютный; без него — папка рядом с
|
||
скриптом
|
||
GCC_PATH=D:\MinGW\bin (опционально) каталог, где лежит gcc.exe;
|
||
дописывается в PATH перед проверкой и
|
||
сборкой; абсолютный или относительно
|
||
scripts/; без него — gcc из текущего PATH
|
||
- Ветка уже запушена в `main` (VERSION = commit-<sha7> от текущего HEAD).
|
||
|
||
Пример:
|
||
powershell -ExecutionPolicy Bypass -File scripts/build-publish-ui.ps1
|
||
#>
|
||
|
||
$ErrorActionPreference = "Stop"
|
||
|
||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||
$CredsFile = Join-Path $ScriptDir ".gitea-creds"
|
||
$Package = "ratatoskr"
|
||
$Owner = "kamelion"
|
||
$Filename = "ratatoskr-windows-amd64.exe"
|
||
|
||
# --- 0. Проверка флага CGO_ENABLED (не зависит от creds) ---
|
||
if ($env:CGO_ENABLED -eq "0") { Write-Error "CGO_ENABLED=0 — нужен C-компилятор (MinGW). Уберите его из env." }
|
||
|
||
# --- 1. Чтение секретов ---
|
||
if (-not (Test-Path $CredsFile)) {
|
||
Write-Error "Нет файла секретов: $CredsFile`nФормат: GITEA_TOKEN=... / UPDATE_TOKEN=... / GIT_MAIN_URL=..."
|
||
}
|
||
$creds = @{}
|
||
Get-Content $CredsFile | ForEach-Object {
|
||
$line = $_.Trim()
|
||
if ($line -and -not $line.StartsWith("#")) {
|
||
$kv = $line.Split("=", 2)
|
||
if ($kv.Count -eq 2) { $creds[$kv[0].Trim()] = $kv[1].Trim() }
|
||
}
|
||
}
|
||
$giteaToken = $creds["GITEA_TOKEN"]
|
||
$updateToken = $creds["UPDATE_TOKEN"]
|
||
$giteaUrl = $creds["GIT_MAIN_URL"]
|
||
if (-not $giteaToken) { Write-Error "В $CredsFile нет GITEA_TOKEN (нужен write:packages)." }
|
||
if (-not $giteaUrl) { Write-Error "В $CredsFile нет GIT_MAIN_URL." }
|
||
|
||
# --- 1a. C-тулчейн (gcc): GCC_PATH из creds дописывается в PATH ---
|
||
# Путь абсолютный либо относительно папки scripts/; без GCC_PATH — gcc
|
||
# берётся из уже установленного PATH.
|
||
$gccPath = $creds["GCC_PATH"]
|
||
if ($gccPath -ne "" -and $gccPath) {
|
||
$gccAbs = Join-Path $ScriptDir $gccPath
|
||
$gccBin = (Resolve-Path -LiteralPath $gccAbs -ErrorAction SilentlyContinue).Path
|
||
if (-not $gccBin) {
|
||
$gccAbs = $gccPath # не нашлось относительно scripts/ — пробуем как абсолютный
|
||
$gccBin = (Resolve-Path -LiteralPath $gccAbs -ErrorAction SilentlyContinue).Path
|
||
}
|
||
if (-not $gccBin) { Write-Error "GCC_PATH не найден: $gccPath (или относительно $ScriptDir)" }
|
||
$env:Path = "$gccBin;$env:Path"
|
||
Write-Host "[gcc] PATH += $gccBin"
|
||
}
|
||
if (-not (Get-Command gcc -ErrorAction SilentlyContinue)) {
|
||
Write-Host "gcc не найден в PATH. Пример (WinLibs):"
|
||
Write-Host ' D:\MinGW\bin, затем:
|
||
GCC_PATH=D:\MinGW\bin — в scripts/.gitea-creds'
|
||
Write-Error "C-компилятор gcc не найден."
|
||
}
|
||
Write-Host "[ok] gcc: $((gcc --version | Select-Object -First 1))"
|
||
|
||
# --- 1b. Корень целевого проекта ---
|
||
# PROJECT_PATH из .gitea-creds (относительно папки scripts/) либо, если не задан,
|
||
# папка рядом со скриптом (прежнее поведение).
|
||
$projPath = $creds["PROJECT_PATH"]
|
||
if ($projPath -ne "" -and $projPath) {
|
||
$RepoRoot = (Resolve-Path -LiteralPath (Join-Path $ScriptDir $projPath)).Path
|
||
if (-not $RepoRoot) { Write-Error "PROJECT_PATH не найден: $projPath (относительно $ScriptDir)" }
|
||
} else {
|
||
$RepoRoot = Split-Path -Parent $ScriptDir
|
||
}
|
||
Set-Location $RepoRoot
|
||
Write-Host "[root] $RepoRoot"
|
||
|
||
# --- 2. Версия = commit-<sha7> текущего HEAD (совпадает с именованием CI) ---
|
||
$sha = (git rev-parse --short HEAD).Trim()
|
||
if (-not $sha) { Write-Error "git rev-parse --short HEAD не дал хэш." }
|
||
$Version = "commit-$sha"
|
||
Write-Host "[build] VERSION=$Version FILENAME=$Filename"
|
||
|
||
# --- 3. Сборка (cgo + UI) ---
|
||
$env:CGO_ENABLED = "1"
|
||
$out = Join-Path $RepoRoot $Filename
|
||
$ldflags = "-s -w -X main.version=${Version} -X main.updateToken=${updateToken}"
|
||
Write-Host "[build] go build -ldflags=... -o $Filename"
|
||
$goArgs = @("build", "-ldflags=$ldflags", "-o", $out, "./cmd/ratatoskr/")
|
||
go $goArgs
|
||
if ($LASTEXITCODE -ne 0) { Write-Error "go build завершился с кодом $LASTEXITCODE" }
|
||
|
||
# --- 4. Companion-файлы (.version, .sha256) ---
|
||
$sha256Hex = (Get-FileHash -Algorithm SHA256 $out).Hash.ToLower()
|
||
$verFile = "$out.version"
|
||
$sumFile = "$out.sha256"
|
||
Set-Content -Path $verFile -Value $Version -NoNewline -Encoding ascii
|
||
Set-Content -Path $sumFile -Value $sha256Hex -NoNewline -Encoding ascii
|
||
Write-Host "[ok] bin: $out ($([math]::Round((Get-Item $out).Length/1MB,1)) MB)"
|
||
Write-Host "[ok] sha256: $sha256Hex"
|
||
|
||
# --- 5. Публикация в Gitea Packages ---
|
||
$api = "$giteaUrl/api/packages/$Owner/generic/$Package/$Version"
|
||
$files = @($Filename, "$Filename.version", "$Filename.sha256")
|
||
foreach ($f in $files) {
|
||
Write-Host "[put] $api/$f"
|
||
curl.exe -sS -X PUT `
|
||
-H "Authorization: token $giteaToken" `
|
||
-H "Content-Type: application/octet-stream" `
|
||
"$api/$f" `
|
||
--data-binary "@$f"
|
||
if ($LASTEXITCODE -ne 0) { Write-Error "curl PUT $f завершился с кодом $LASTEXITCODE" }
|
||
}
|
||
|
||
# --- 6. Самопроверка: читаем .sha256 обратно и сверяем (контракт U4) ---
|
||
Write-Host "[verify] перечитываю $Filename.sha256 из Gitea..."
|
||
$remoteSum = (curl.exe -sS -H "Authorization: token $giteaToken" "$api/$Filename.sha256").Trim()
|
||
if ($remoteSum -ne $sha256Hex) {
|
||
Write-Error "Проверка не сошлась: remote=$remoteSum local=$sha256Hex"
|
||
}
|
||
$remoteVer = (curl.exe -sS -H "Authorization: token $giteaToken" "$api/$Filename.version").Trim()
|
||
if ($remoteVer -ne $Version) {
|
||
Write-Error "Версия не сошлась: remote=$remoteVer local=$Version"
|
||
}
|
||
Write-Host "[ok] опубликовано и проверено: $Version/$Filename (+.version, +.sha256)"
|