152 lines
7.8 KiB
PowerShell
152 lines
7.8 KiB
PowerShell
# collect-debs-ssh.ps1 — как collect-debs.ps1, но по SSH (для устройства БЕЗ adbd).
|
||
# Windows-хост, без WSL: SSH/SCP делаются через plink.exe / pscp.exe (PuTTY tools).
|
||
#
|
||
# Шаг 1 — снять список установленных пакетов с устройства:
|
||
# powershell -ExecutionPolicy Bypass -File collect-debs-ssh.ps1 -Step target
|
||
# -> new-installed.txt
|
||
#
|
||
# Шаг 2 — сравнить с тем, что вам давали (файл target-installed.txt из старого workflow):
|
||
# powershell -ExecutionPolicy Bypass -File collect-debs-ssh.ps1 -Step diff
|
||
#
|
||
# Шаг 3 (опционально, как -Step fetch у adb-версии) — добрать недостающие .deb:
|
||
# powershell -ExecutionPolicy Bypass -File collect-debs-ssh.ps1 -Step fetch
|
||
# нужен рядом packages.list и collect-on-device.sh (тот же файл, без изменений).
|
||
#
|
||
# Параметры подключения (по умолчанию — как вы просили):
|
||
# -HostAddr 192.168.1.52 -User linaro -Pass linaro
|
||
#
|
||
# plink.exe / pscp.exe берутся из .\bin\ рядом со скриптом (как у вас adb.exe),
|
||
# иначе — из PATH. Если ни там ни там нет — скачайте с https://www.putty.org
|
||
#
|
||
# ВАЖНО про первое подключение: plink на первый коннект спросит про host key
|
||
# ("host key is not cached... store key?"). В batch-режиме он на это ответит
|
||
# отказом и упадёт. Поэтому один раз ПЕРЕД первым запуском примите ключ вручную:
|
||
# .\bin\plink.exe -ssh linaro@192.168.1.52
|
||
# (введите "y" на вопрос про ключ, затем можно Ctrl+C — ключ сохранится в реестр)
|
||
|
||
param(
|
||
[Parameter(Mandatory = $true)][ValidateSet('target', 'diff', 'fetch')][string]$Step,
|
||
[string]$HostAddr = '192.168.1.52',
|
||
[string]$User = 'linaro',
|
||
[string]$Pass = 'linaro',
|
||
[string]$SudoPass,
|
||
[string]$OldFile, # для -Step diff, по умолчанию target-installed.txt
|
||
[string]$NewFile, # для -Step diff, по умолчанию new-installed.txt
|
||
[string]$Plink,
|
||
[string]$Pscp
|
||
)
|
||
$ErrorActionPreference = 'Continue'
|
||
$Here = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||
if (-not $SudoPass) { $SudoPass = $Pass }
|
||
|
||
function Log($m) { Write-Host "[collect] $m" -ForegroundColor Green }
|
||
function Warn($m) { Write-Host "[warn] $m" -ForegroundColor Yellow }
|
||
function Die($m) { Write-Host "[error] $m" -ForegroundColor Red; exit 1 }
|
||
|
||
# plink/pscp по умолчанию берём из .\bin\ рядом со скриптом, иначе из PATH
|
||
if (-not $Plink) {
|
||
$cand = Join-Path $Here 'bin\plink.exe'
|
||
$Plink = if (Test-Path $cand) { $cand } else { 'plink' }
|
||
}
|
||
if (-not $Pscp) {
|
||
$cand = Join-Path $Here 'bin\pscp.exe'
|
||
$Pscp = if (Test-Path $cand) { $cand } else { 'pscp' }
|
||
}
|
||
foreach ($exe in @($Plink, $Pscp)) {
|
||
if (-not (Get-Command $exe -ErrorAction SilentlyContinue)) {
|
||
Die "не найден '$exe'. Положите plink.exe/pscp.exe в .\bin\ или в PATH (https://www.putty.org)"
|
||
}
|
||
}
|
||
|
||
function Write-Lf($path, [string[]]$lines) {
|
||
$text = ($lines -join "`n") + "`n"
|
||
[System.IO.File]::WriteAllText($path, $text, (New-Object System.Text.UTF8Encoding($false)))
|
||
}
|
||
|
||
function Invoke-Remote([string]$cmd) {
|
||
# plink в batch-режиме: без интерактивных вопросов (host key должен быть уже принят заранее)
|
||
$out = & $Plink -ssh -batch -pw $Pass "$User@$HostAddr" $cmd 2>&1 | Out-String
|
||
return $out
|
||
}
|
||
function Push-File([string]$local, [string]$remote) {
|
||
& $Pscp -batch -pw $Pass $local "$User@${HostAddr}:$remote" 2>&1 | Out-Null
|
||
}
|
||
function Pull-Path([string]$remote, [string]$localDir) {
|
||
& $Pscp -batch -pw $Pass -r "$User@${HostAddr}:$remote" $localDir 2>&1 | Out-Null
|
||
}
|
||
|
||
# ---------------------------------------------------------------------------
|
||
if ($Step -eq 'target') {
|
||
Log "подключаюсь к $User@$HostAddr, снимаю список установленных пакетов..."
|
||
$raw = Invoke-Remote 'dpkg-query -W | cut -f1'
|
||
$pkgs = $raw -replace "`r", '' -split "`n" | Where-Object { $_ -ne '' } | Sort-Object -Unique
|
||
if ($pkgs.Count -eq 0) { Die "не получил список пакетов (проверьте SSH-доступ / что это Debian-rootfs). Вывод:`n$raw" }
|
||
$out = Join-Path $Here 'new-installed.txt'
|
||
Write-Lf $out $pkgs
|
||
Log "сохранено $($pkgs.Count) пакетов -> $out"
|
||
Log "теперь сравните: -Step diff"
|
||
exit 0
|
||
}
|
||
|
||
# ---------------------------------------------------------------------------
|
||
if ($Step -eq 'diff') {
|
||
$old = if ($OldFile) { $OldFile } else { Join-Path $Here 'target-installed.txt' }
|
||
$new = if ($NewFile) { $NewFile } else { Join-Path $Here 'new-installed.txt' }
|
||
foreach ($f in @($old, $new)) { if (-not (Test-Path $f)) { Die "нет файла: $f" } }
|
||
|
||
$oldSet = Get-Content $old | Where-Object { $_ -ne '' } | Sort-Object -Unique
|
||
$newSet = Get-Content $new | Where-Object { $_ -ne '' } | Sort-Object -Unique
|
||
|
||
$onlyOld = $oldSet | Where-Object { $newSet -notcontains $_ }
|
||
$onlyNew = $newSet | Where-Object { $oldSet -notcontains $_ }
|
||
|
||
Write-Host "=== Есть только на СТАРОМ устройстве (в новом отсутствует), $($onlyOld.Count) шт ===" -ForegroundColor Cyan
|
||
$onlyOld | ForEach-Object { Write-Host $_ }
|
||
Write-Host ""
|
||
Write-Host "=== Есть только на НОВОМ устройстве (на старом не было), $($onlyNew.Count) шт ===" -ForegroundColor Cyan
|
||
$onlyNew | ForEach-Object { Write-Host $_ }
|
||
|
||
if ($onlyOld.Count -eq 0 -and $onlyNew.Count -eq 0) { Log "списки пакетов идентичны." }
|
||
else { Warn "списки различаются (см. выше)." }
|
||
exit 0
|
||
}
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Step 'fetch'
|
||
$pkgsList = Join-Path $Here 'packages.list'
|
||
$helper = Join-Path $Here 'collect-on-device.sh'
|
||
$tgt = Join-Path $Here 'target-installed.txt'
|
||
foreach ($f in @($pkgsList, $helper)) { if (-not (Test-Path $f)) { Die "нет файла: $f" } }
|
||
|
||
Log "проверяю доступ по SSH..."
|
||
$idOut = (Invoke-Remote 'id -u').Trim()
|
||
if (-not $idOut) { Die "не удалось подключиться к $User@$HostAddr (проверьте host key: см. комментарий в начале файла)" }
|
||
$sudo = if ($idOut -eq '0') { '' } else { Warn "$User не root — иду через sudo"; 'sudo -S' }
|
||
|
||
Log "заливаю списки и хелпер на устройство..."
|
||
Invoke-Remote 'rm -rf /tmp/btcollect && mkdir -p /tmp/btcollect' | Out-Null
|
||
Push-File $pkgsList '/tmp/btcollect/packages.list'
|
||
Push-File $helper '/tmp/btcollect/collect-on-device.sh'
|
||
if (Test-Path $tgt) { Push-File $tgt '/tmp/btcollect/target-installed.txt' }
|
||
else { Warn "нет target-installed.txt — сначала лучше прогнать -Step target" }
|
||
# на случай CRLF после Windows
|
||
Invoke-Remote "sed -i 's/\r`$//' /tmp/btcollect/* 2>/dev/null; true" | Out-Null
|
||
|
||
Log "качаю зависимости на устройстве (нужен интернет на нём)..."
|
||
$cmd = if ($sudo -ne '') {
|
||
"echo '$SudoPass' | $sudo bash /tmp/btcollect/collect-on-device.sh"
|
||
} else {
|
||
"bash /tmp/btcollect/collect-on-device.sh"
|
||
}
|
||
$output = Invoke-Remote $cmd
|
||
Write-Host $output
|
||
if ($output -notmatch 'COLLECT-OK') { Die "сбор пакетов не дошёл до COLLECT-OK" }
|
||
|
||
Log "забираю .deb на хост..."
|
||
$debs = Join-Path $Here 'debs'
|
||
if (Test-Path $debs) { Remove-Item -Recurse -Force $debs }
|
||
Pull-Path '/tmp/btdebs' $Here
|
||
Rename-Item (Join-Path $Here 'btdebs') $debs
|
||
$n = (Get-ChildItem $debs -Filter *.deb).Count
|
||
Log "готово: $n .deb в $debs"
|