Regalamiunsorriso/scripts/trim-dump-via-temp-mysql.ps1
MaddoScientisto dd7d4c865b
All checks were successful
Publish FaceAI Container / publish (push) Successful in 6m52s
Enhance Docker and PowerShell scripts for improved functionality and maintainability
- Updated Dockerfile to include default MySQL client for better database interaction.
- Modified entrypoint.sh to support additional workspace for legacy applications and added MySQL readiness check before startup.
- Enhanced PowerShell script for trimming MySQL dumps to include overlay dumps and improved error handling for missing race and user IDs.
- Added new image files and face encoding pickles for various projects, ensuring comprehensive data availability.
- Removed outdated face encoding pickle from PISA directory to maintain data relevance.

Co-authored-by: Copilot <copilot@github.com>
2026-04-22 22:45:44 +02:00

408 lines
No EOL
15 KiB
PowerShell

param(
[string]$SourceDump = (Join-Path $PSScriptRoot '..\db\pg-model-seed-trimmed-20260421.sql'),
[string]$OverlayDump = (Join-Path $PSScriptRoot '..\db\pg-local-model-fixtures-overlay-20260422.sql'),
[string]$OutputDump = (Join-Path $PSScriptRoot '..\db\pg-local-purpose-seed-20260422.sql'),
[int[]]$KeepRaceIds = @(1018547, 1018557),
[int[]]$KeepUserIds = @(2),
[string]$ContainerName = 'regalami-dump-trim-mysql-temp',
[string]$VolumeName = 'regalami-dump-trim-mysql-temp-data',
[string]$DatabaseName = 'pgtrim',
[string]$RootPassword = 'root'
)
$ErrorActionPreference = 'Stop'
function Invoke-DockerCapture {
param(
[Parameter(Mandatory = $true)]
[string[]]$DockerArgs
)
$output = & docker @DockerArgs 2>&1
if ($LASTEXITCODE -ne 0) {
throw (("docker " + ($DockerArgs -join ' ')) + " failed:`n" + ($output -join "`n"))
}
return $output
}
function Invoke-DockerQuiet {
param(
[Parameter(Mandatory = $true)]
[string[]]$DockerArgs
)
& docker @DockerArgs | Out-Null
if ($LASTEXITCODE -ne 0) {
throw "docker $($DockerArgs -join ' ') failed"
}
}
function Wait-ForMysqlReady {
param(
[Parameter(Mandatory = $true)]
[string]$Name,
[Parameter(Mandatory = $true)]
[string]$Password
)
for ($attempt = 0; $attempt -lt 180; $attempt++) {
$logs = & docker logs $Name 2>&1
if ($LASTEXITCODE -eq 0 -and ($logs -join "`n") -match 'ready for connections.*port: 3306') {
return
}
Start-Sleep -Seconds 2
}
throw "MySQL in container $Name did not become ready in time."
}
function Invoke-MysqlQuery {
param(
[Parameter(Mandatory = $true)]
[string]$Query,
[switch]$SkipDatabase
)
$dockerArgs = @('exec', '-e', "MYSQL_PWD=$RootPassword", $ContainerName, 'mysql', '-N', '-B', '-uroot')
if (-not $SkipDatabase) {
$dockerArgs += @('-D', $DatabaseName)
}
$dockerArgs += @('-e', $Query)
return Invoke-DockerCapture -DockerArgs $dockerArgs
}
function Get-SqlScalar {
param(
[Parameter(Mandatory = $true)]
[string]$Query,
[switch]$SkipDatabase
)
$result = Invoke-MysqlQuery -Query $Query -SkipDatabase:$SkipDatabase
if (-not $result) {
return ''
}
return ($result | Select-Object -First 1).Trim()
}
function Quote-Identifier {
param([string]$Name)
return '`' + $Name.Replace('`', '``') + '`'
}
function ConvertTo-SqlIntList {
param(
[Parameter(Mandatory = $true)]
[int[]]$Values
)
$dedupedValues = $Values | Sort-Object -Unique
if (-not $dedupedValues -or $dedupedValues.Count -eq 0) {
throw 'At least one numeric keep id is required.'
}
return ($dedupedValues | ForEach-Object { [string]$_ }) -join ','
}
if (-not (Test-Path $SourceDump)) {
throw "Source dump not found: $SourceDump"
}
$dbDirectory = Split-Path -Parent (Resolve-Path $SourceDump).Path
$sourceFileName = Split-Path -Leaf $SourceDump
$outputFileName = Split-Path -Leaf $OutputDump
$overlayResolvedPath = $null
$overlayFileName = ''
$overlayDirectory = $dbDirectory
$overlayMount = @()
if ($OverlayDump -and (Test-Path $OverlayDump)) {
$overlayResolvedPath = (Resolve-Path $OverlayDump).Path
$overlayFileName = Split-Path -Leaf $overlayResolvedPath
$overlayDirectory = Split-Path -Parent $overlayResolvedPath
if ($overlayDirectory -ne $dbDirectory) {
$overlayMount = @('-v', "${overlayDirectory}:/workspace/overlay")
}
}
$importErrorLogFileName = [System.IO.Path]::GetFileNameWithoutExtension($sourceFileName) + '.import-errors.log'
$importErrorLogPath = Join-Path $dbDirectory $importErrorLogFileName
$sourceSizeBytes = (Get-Item $SourceDump).Length
$keepRaceListSql = ConvertTo-SqlIntList -Values $KeepRaceIds
$keepUserListSql = ConvertTo-SqlIntList -Values $KeepUserIds
Write-Host "Using source dump: $SourceDump"
Write-Host "Source size: $sourceSizeBytes bytes"
Write-Host "Import error log: $importErrorLogPath"
if ($overlayResolvedPath) {
Write-Host "Using overlay dump: $overlayResolvedPath"
}
Write-Host "KeepRaceIdsRequested=$keepRaceListSql"
Write-Host "KeepUserIdsRequested=$keepUserListSql"
try {
& docker rm -f $ContainerName 1>$null 2>$null
& docker volume rm $VolumeName 1>$null 2>$null
$dockerRunArgs = @(
'run', '-d', '--name', $ContainerName,
'-e', "MYSQL_ROOT_PASSWORD=$RootPassword",
'-e', 'MYSQL_ROOT_HOST=%',
'-v', "${dbDirectory}:/workspace/db",
'-v', "${VolumeName}:/var/lib/mysql"
)
if ($overlayMount.Count -gt 0) {
$dockerRunArgs += $overlayMount
}
$dockerRunArgs += @(
'mysql:8.4',
'--max_allowed_packet=1G',
'--net_read_timeout=600',
'--net_write_timeout=600'
)
Invoke-DockerCapture -DockerArgs $dockerRunArgs | Out-Null
Write-Host 'Temporary MySQL container started.'
Wait-ForMysqlReady -Name $ContainerName -Password $RootPassword
Write-Host 'Temporary MySQL is ready.'
Invoke-MysqlQuery -SkipDatabase -Query "DROP DATABASE IF EXISTS $DatabaseName; CREATE DATABASE $DatabaseName CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;" | Out-Null
Write-Host 'Temporary database created.'
Write-Host "Importing source dump into temporary MySQL database..."
if (Test-Path $importErrorLogPath) {
Remove-Item $importErrorLogPath -Force
}
Invoke-DockerQuiet -DockerArgs @(
'exec', $ContainerName, 'sh', '-lc',
"mysql --force -uroot -p$RootPassword $DatabaseName < /workspace/db/$sourceFileName 2> /workspace/db/$importErrorLogFileName"
)
if ($overlayResolvedPath) {
$overlayContainerPath = if ($overlayDirectory -eq $dbDirectory) {
"/workspace/db/$overlayFileName"
}
else {
"/workspace/overlay/$overlayFileName"
}
Write-Host "Importing overlay dump into temporary MySQL database..."
Invoke-DockerQuiet -DockerArgs @(
'exec', $ContainerName, 'sh', '-lc',
"mysql --force -uroot -p$RootPassword $DatabaseName < $overlayContainerPath"
)
}
$beforeGara = [int64](Get-SqlScalar -Query 'SELECT COUNT(*) FROM gara;')
$beforePuntoFoto = [int64](Get-SqlScalar -Query 'SELECT COUNT(*) FROM punto_foto;')
$beforeFoto = [int64](Get-SqlScalar -Query 'SELECT COUNT(*) FROM foto;')
$beforeLogFoto = [int64](Get-SqlScalar -Query 'SELECT COUNT(*) FROM log_foto;')
$usersExists = (Get-SqlScalar -SkipDatabase -Query "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = '$DatabaseName' AND table_name = 'users';") -eq '1'
$beforeUsers = 0
if ($usersExists) {
$beforeUsers = [int64](Get-SqlScalar -Query 'SELECT COUNT(*) FROM users;')
}
Invoke-MysqlQuery -Query @"
DROP TABLE IF EXISTS keep_gara_ids;
CREATE TABLE keep_gara_ids AS
SELECT id_gara
FROM gara
WHERE id_gara IN ($keepRaceListSql)
ORDER BY FIELD(id_gara, $keepRaceListSql);
DROP TABLE IF EXISTS keep_punto_foto_ids;
CREATE TABLE keep_punto_foto_ids AS
SELECT id_puntoFoto
FROM punto_foto
WHERE id_gara IN (SELECT id_gara FROM keep_gara_ids);
DROP TABLE IF EXISTS keep_foto_ids;
CREATE TABLE keep_foto_ids AS
SELECT id_foto
FROM foto
WHERE id_gara IN (SELECT id_gara FROM keep_gara_ids);
"@ | Out-Null
$keptGaraIds = Invoke-MysqlQuery -Query 'SELECT id_gara FROM keep_gara_ids ORDER BY id_gara;'
$missingRaceIds = @()
foreach ($requestedRaceId in ($KeepRaceIds | Sort-Object -Unique)) {
if (-not (($keptGaraIds | ForEach-Object { $_.Trim() }) -contains [string]$requestedRaceId)) {
$missingRaceIds += $requestedRaceId
}
}
if ($missingRaceIds.Count -gt 0) {
throw "One or more requested race ids are missing from the imported data: $($missingRaceIds -join ',')"
}
$cleanupStats = [System.Collections.Generic.List[string]]::new()
Invoke-MysqlQuery -Query 'DELETE FROM log_foto;' | Out-Null
$cleanupStats.Add('log_foto:deleted-all')
$garaDependentTables = Invoke-MysqlQuery -SkipDatabase -Query @"
SELECT table_name
FROM information_schema.columns
WHERE table_schema = '$DatabaseName'
AND column_name = 'id_gara'
AND table_name NOT IN ('gara', 'foto', 'punto_foto', 'keep_gara_ids', 'keep_punto_foto_ids', 'keep_foto_ids', 'keep_user_ids')
ORDER BY table_name;
"@
foreach ($tableName in $garaDependentTables) {
if (-not $tableName) {
continue
}
$trimmedTableName = $tableName.Trim()
$quotedTable = Quote-Identifier $trimmedTableName
$deletedRows = [int64](Get-SqlScalar -Query "SELECT COUNT(*) FROM $quotedTable WHERE id_gara IS NOT NULL AND id_gara NOT IN (SELECT id_gara FROM keep_gara_ids);")
if ($deletedRows -gt 0) {
Invoke-MysqlQuery -Query "DELETE FROM $quotedTable WHERE id_gara IS NOT NULL AND id_gara NOT IN (SELECT id_gara FROM keep_gara_ids);" | Out-Null
$cleanupStats.Add("$($trimmedTableName):$deletedRows")
}
}
$fotoDependentTables = Invoke-MysqlQuery -SkipDatabase -Query @"
SELECT table_name
FROM information_schema.columns
WHERE table_schema = '$DatabaseName'
AND column_name = 'id_foto'
AND table_name NOT IN ('foto', 'log_foto', 'keep_foto_ids', 'keep_gara_ids', 'keep_punto_foto_ids', 'keep_user_ids')
ORDER BY table_name;
"@
foreach ($tableName in $fotoDependentTables) {
if (-not $tableName) {
continue
}
$trimmedTableName = $tableName.Trim()
$quotedTable = Quote-Identifier $trimmedTableName
$deletedRows = [int64](Get-SqlScalar -Query "SELECT COUNT(*) FROM $quotedTable WHERE id_foto IS NOT NULL AND id_foto NOT IN (SELECT id_foto FROM keep_foto_ids);")
if ($deletedRows -gt 0) {
Invoke-MysqlQuery -Query "DELETE FROM $quotedTable WHERE id_foto IS NOT NULL AND id_foto NOT IN (SELECT id_foto FROM keep_foto_ids);" | Out-Null
$cleanupStats.Add("$($trimmedTableName):$deletedRows")
}
}
$deletedFotoRows = [int64](Get-SqlScalar -Query 'SELECT COUNT(*) FROM foto WHERE id_foto NOT IN (SELECT id_foto FROM keep_foto_ids);')
if ($deletedFotoRows -gt 0) {
Invoke-MysqlQuery -Query 'DELETE FROM foto WHERE id_foto NOT IN (SELECT id_foto FROM keep_foto_ids);' | Out-Null
$cleanupStats.Add("foto:$deletedFotoRows")
}
$deletedPuntoFotoRows = [int64](Get-SqlScalar -Query 'SELECT COUNT(*) FROM punto_foto WHERE id_gara NOT IN (SELECT id_gara FROM keep_gara_ids);')
if ($deletedPuntoFotoRows -gt 0) {
Invoke-MysqlQuery -Query 'DELETE FROM punto_foto WHERE id_gara NOT IN (SELECT id_gara FROM keep_gara_ids);' | Out-Null
$cleanupStats.Add("punto_foto:$deletedPuntoFotoRows")
}
$deletedGaraRows = [int64](Get-SqlScalar -Query 'SELECT COUNT(*) FROM gara WHERE id_gara NOT IN (SELECT id_gara FROM keep_gara_ids);')
if ($deletedGaraRows -gt 0) {
Invoke-MysqlQuery -Query 'DELETE FROM gara WHERE id_gara NOT IN (SELECT id_gara FROM keep_gara_ids);' | Out-Null
$cleanupStats.Add("gara:$deletedGaraRows")
}
$keptUserIds = @()
if ($usersExists) {
Invoke-MysqlQuery -Query @"
DROP TABLE IF EXISTS keep_user_ids;
CREATE TABLE keep_user_ids AS
SELECT id_users
FROM users
WHERE id_users IN ($keepUserListSql)
ORDER BY FIELD(id_users, $keepUserListSql);
"@ | Out-Null
$keptUserIds = Invoke-MysqlQuery -Query 'SELECT id_users FROM keep_user_ids ORDER BY id_users;'
$missingUserIds = @()
foreach ($requestedUserId in ($KeepUserIds | Sort-Object -Unique)) {
if (-not (($keptUserIds | ForEach-Object { $_.Trim() }) -contains [string]$requestedUserId)) {
$missingUserIds += $requestedUserId
}
}
if ($missingUserIds.Count -gt 0) {
throw "One or more requested user ids are missing from the imported data: $($missingUserIds -join ',')"
}
$usersDependentTables = Invoke-MysqlQuery -SkipDatabase -Query @"
SELECT table_name
FROM information_schema.columns
WHERE table_schema = '$DatabaseName'
AND column_name = 'id_users'
AND table_name NOT IN ('users', 'keep_user_ids', 'keep_gara_ids', 'keep_punto_foto_ids', 'keep_foto_ids')
ORDER BY table_name;
"@
foreach ($tableName in $usersDependentTables) {
if (-not $tableName) {
continue
}
$trimmedTableName = $tableName.Trim()
$quotedTable = Quote-Identifier $trimmedTableName
$deletedRows = [int64](Get-SqlScalar -Query "SELECT COUNT(*) FROM $quotedTable WHERE id_users IS NOT NULL AND id_users NOT IN (SELECT id_users FROM keep_user_ids);")
if ($deletedRows -gt 0) {
Invoke-MysqlQuery -Query "DELETE FROM $quotedTable WHERE id_users IS NOT NULL AND id_users NOT IN (SELECT id_users FROM keep_user_ids);" | Out-Null
$cleanupStats.Add("$($trimmedTableName):$deletedRows")
}
}
$deletedUsers = [int64](Get-SqlScalar -Query 'SELECT COUNT(*) FROM users WHERE id_users NOT IN (SELECT id_users FROM keep_user_ids);')
if ($deletedUsers -gt 0) {
Invoke-MysqlQuery -Query 'DELETE FROM users WHERE id_users NOT IN (SELECT id_users FROM keep_user_ids);' | Out-Null
$cleanupStats.Add("users:$deletedUsers")
}
}
$afterGara = [int64](Get-SqlScalar -Query 'SELECT COUNT(*) FROM gara;')
$afterPuntoFoto = [int64](Get-SqlScalar -Query 'SELECT COUNT(*) FROM punto_foto;')
$afterFoto = [int64](Get-SqlScalar -Query 'SELECT COUNT(*) FROM foto;')
$afterLogFoto = [int64](Get-SqlScalar -Query 'SELECT COUNT(*) FROM log_foto;')
$afterUsers = 0
if ($usersExists) {
$afterUsers = [int64](Get-SqlScalar -Query 'SELECT COUNT(*) FROM users;')
}
if (Test-Path $OutputDump) {
Remove-Item $OutputDump -Force
}
Write-Host "Exporting curated dump..."
Invoke-DockerQuiet -DockerArgs @(
'exec', $ContainerName, 'sh', '-lc',
"mysqldump -uroot -p$RootPassword --default-character-set=utf8mb4 --single-transaction --routines --triggers --set-gtid-purged=OFF $DatabaseName > /workspace/db/$outputFileName"
)
if (-not (Test-Path $OutputDump)) {
throw "Curated dump was not created: $OutputDump"
}
$outputSizeBytes = (Get-Item $OutputDump).Length
Write-Host "OriginalSizeBytes=$sourceSizeBytes"
Write-Host "CuratedSizeBytes=$outputSizeBytes"
Write-Host "BeforeGara=$beforeGara"
Write-Host "AfterGara=$afterGara"
Write-Host "BeforePuntoFoto=$beforePuntoFoto"
Write-Host "AfterPuntoFoto=$afterPuntoFoto"
Write-Host "BeforeFoto=$beforeFoto"
Write-Host "AfterFoto=$afterFoto"
Write-Host "BeforeLogFoto=$beforeLogFoto"
Write-Host "AfterLogFoto=$afterLogFoto"
Write-Host "BeforeUsers=$beforeUsers"
Write-Host "AfterUsers=$afterUsers"
Write-Host ("KeptGaraIds=" + (($keptGaraIds | ForEach-Object { $_.Trim() }) -join ','))
if ($usersExists) {
Write-Host ("KeptUserIds=" + (($keptUserIds | ForEach-Object { $_.Trim() }) -join ','))
}
Write-Host ("DependencyCleanup=" + (($cleanupStats | Sort-Object) -join ';'))
if (Test-Path $importErrorLogPath) {
$importErrorCount = (Get-Item $importErrorLogPath).Length
Write-Host "ImportErrorLogBytes=$importErrorCount"
}
}
finally {
& docker rm -f $ContainerName 1>$null 2>$null
& docker volume rm $VolumeName 1>$null 2>$null
}