# make-adb-bundle.ps1 — собирает offline-бандл (Windows-хост, без WSL). # # powershell -ExecutionPolicy Bypass -File make-adb-bundle.ps1 -Version 2.0 # # По умолчанию берёт софт из .\software (бинарник ButtonTask + webconfig\), # пакеты из .\debs. Все shell-скрипты/юниты нормализуются в LF (CRLF-фикс). param( [string]$SoftwareDir = '.\software', [Parameter(Mandatory = $true)][string]$Version, [string]$BinPath, [string]$DebsDir ) $ErrorActionPreference = 'Stop' $Here = Split-Path -Parent $MyInvocation.MyCommand.Path function Log($m) { Write-Host "[bundle] $m" -ForegroundColor Green } function Warn($m) { Write-Host "[warn] $m" -ForegroundColor Yellow } function Die($m) { Write-Host "[error] $m" -ForegroundColor Red; exit 1 } function Write-Bytes($path, [string]$text) { [System.IO.File]::WriteAllText($path, $text, (New-Object System.Text.UTF8Encoding($false))) } function ConvertTo-Lf($file) { $t = [System.IO.File]::ReadAllText($file) $t = ($t -replace "`r`n", "`n") -replace "`r", "`n" Write-Bytes $file $t } if (-not (Test-Path $SoftwareDir)) { Die "нет каталога: $SoftwareDir" } $SoftwareDir = (Resolve-Path $SoftwareDir).Path if (-not $BinPath) { $BinPath = Join-Path $SoftwareDir 'ButtonTask' } if (-not $DebsDir) { $DebsDir = Join-Path $Here 'debs' } $web = Join-Path $SoftwareDir 'webconfig' if (-not (Test-Path $BinPath)) { Die "нет бинарника: $BinPath" } if (-not (Test-Path $web)) { Die "нет webconfig: $web" } if (-not (Get-Command tar.exe -ErrorAction SilentlyContinue)) { Die "не найден tar.exe (есть в Windows 10 1803+)" } # юниты systemd — все *.service из webconfig $svc = @(Get-ChildItem $web -Filter '*.service' -File) if ($svc.Count -eq 0) { Die "в webconfig нет ни одного *.service" } # хелперы $scriptsSrc = Join-Path $web 'scripts' $needScripts = 'bt-netconfig', 'bt-update', 'bt-service', 'buttontask.sudoers' foreach ($s in $needScripts) { if (-not (Test-Path (Join-Path $scriptsSrc $s))) { Die "нет webconfig\scripts\$s" } } $stage = Join-Path $Here "stage-$Version" if (Test-Path $stage) { Remove-Item -Recurse -Force $stage } foreach ($d in 'app', 'debs', 'scripts', 'config', 'systemd') { New-Item -ItemType Directory -Force -Path (Join-Path $stage $d) | Out-Null } Log "копирую бинарник" Copy-Item $BinPath (Join-Path $stage 'app\ButtonTask') Log "копирую webconfig" Copy-Item $web (Join-Path $stage 'webconfig') -Recurse Log "копирую хелперы и sudoers" foreach ($s in $needScripts) { Copy-Item (Join-Path $scriptsSrc $s) (Join-Path $stage "scripts\$s") } Log "копирую юниты: $($svc.Name -join ', ')" foreach ($u in $svc) { Copy-Item $u.FullName (Join-Path $stage "systemd\$($u.Name)") } $ovr = Join-Path $web 'buttontask.service.d\override.conf.example' if (Test-Path $ovr) { Copy-Item $ovr (Join-Path $stage 'systemd\override.conf.example') } else { Warn "override.conf.example не найден — авто-настройка тача будет пропущена" } # config.json — ищем; если нигде нет, кладём дефолтный $cfg = @( (Join-Path $SoftwareDir 'config\config.json'), (Join-Path $web 'config\config.json'), (Join-Path $Here 'config\config.json') ) | Where-Object { Test-Path $_ } | Select-Object -First 1 if ($cfg) { Copy-Item $cfg (Join-Path $stage 'config\config.json') Log "config.json: $cfg" } else { Warn "config.json нигде не найден — кладу дефолтный" $default = @' { "version": 2, "layout": { "mode": "grid", "columns": 2, "spacing": 10, "showLabels": true }, "background": { "type": "gradient", "color1": "#00007b", "color2": "#7b007b", "animated": true, "imagePath": "" }, "feedback": { "okColor": "#00cc44", "errorColor": "#cc2200", "okWidth": 6, "errorWidth": 6, "glowRadius": 20 }, "settings": { "darkMode": true, "password": "admin", "kioskMode": false, "iconsDir": "/opt/buttontask/icons", "webPort": 8080 }, "buttons": [] } '@ Write-Bytes (Join-Path $stage 'config\config.json') ($default -replace "`r`n", "`n") } # .deb if ((Test-Path $DebsDir) -and (Get-ChildItem $DebsDir -Filter *.deb -ErrorAction SilentlyContinue)) { Copy-Item (Join-Path $DebsDir '*.deb') (Join-Path $stage 'debs') Log "пакетов в бандле: $((Get-ChildItem (Join-Path $stage 'debs') -Filter *.deb).Count)" } else { Warn "каталог debs пуст ($DebsDir) — сначала прогоните collect-debs.ps1" } Log "кладу device-install.sh и VERSION" Copy-Item (Join-Path $Here 'device-install.sh') (Join-Path $stage 'device-install.sh') Write-Bytes (Join-Path $stage 'VERSION') ($Version + "`n") Log "нормализую переводы строк в LF (CRLF-фикс)" $fix = @() $fix += Get-ChildItem (Join-Path $stage 'scripts') -File $fix += Get-ChildItem (Join-Path $stage 'systemd') -File $fix += Get-Item (Join-Path $stage 'device-install.sh') $fix += @(Get-ChildItem (Join-Path $stage 'webconfig') -Recurse -File -Include 'bt-*', '*.sh', '*.service', '*.sudoers', 'override.conf*') $fix | Sort-Object FullName -Unique | ForEach-Object { ConvertTo-Lf $_.FullName } Log "пакую архив" $tgz = Join-Path $Here "buttontask-deploy-$Version.tgz" if (Test-Path $tgz) { Remove-Item $tgz } & tar.exe -C $stage -czf $tgz . if ($LASTEXITCODE -ne 0) { Die "tar завершился с ошибкой" } Remove-Item -Recurse -Force $stage Log "готово: $tgz"