# TeamAAS PostBuild: move all DLL/PDB/XML/Plugins/native libs/resource cultures from root to Runtime subdir. # Duplicate files are skipped (delete source if dest already exists) to keep rebuild idempotent. # Root keeps: EXE + .config + config-class folders (Config/Logs/Products/Recipe). # Runtime gets: all DLL/PDB/XML + Plugins/ + dll/ + satellite culture folders (zh-CN, en-US, ...). # Uses .NET File/Directory APIs directly to avoid PowerShell path-inference quirks. param( [Parameter(Mandatory=$true)] [string]$OutDir ) $ErrorActionPreference = 'Stop' if (-not $OutDir.EndsWith('\')) { $OutDir = $OutDir + '\' } $root = $OutDir $runtime = Join-Path $root 'Runtime' # Config-class folders that must stay in root (whitelist). Runtime itself is also excluded. $configFolders = @('Config', 'Logs', 'Products', 'Recipe', 'Runtime','Calibration') if (-not [System.IO.Directory]::Exists($runtime)) { [System.IO.Directory]::CreateDirectory($runtime) | Out-Null } $pluginsDest = Join-Path $runtime 'Plugins' $dllDest = Join-Path $runtime 'dll\x64' if (-not [System.IO.Directory]::Exists($pluginsDest)) { [System.IO.Directory]::CreateDirectory($pluginsDest) | Out-Null } if (-not [System.IO.Directory]::Exists($dllDest)) { [System.IO.Directory]::CreateDirectory($dllDest) | Out-Null } function Move-FileNoConflict { # Move single file $Source -> $Target. If Target exists, **overwrite with new Source** # (critical: keep Target always up-to-date; the old "delete source" behavior left # stale Target DLLs after rebuild → MissingMethodException at runtime). param([string]$Source, [string]$Target) if (-not [System.IO.File]::Exists($Source)) { return } $targetParent = [System.IO.Path]::GetDirectoryName($Target) if (-not [System.IO.Directory]::Exists($targetParent)) { [System.IO.Directory]::CreateDirectory($targetParent) | Out-Null } try { # Copy with overwrite, then delete source. Works whether Target exists or not. [System.IO.File]::Copy($Source, $Target, $true) [System.IO.File]::Delete($Source) } catch { try { # If copy failed (e.g. file locked), try plain move as fallback. if (-not [System.IO.File]::Exists($Target)) { [System.IO.File]::Move($Source, $Target) } else { # Target exists and copy failed → leave Source in place (do not fail build). Write-Warning "[PostBuild] could not update $Target with $Source : $($_.Exception.Message)" } } catch { Write-Warning "[PostBuild] could not move $Source -> $Target : $($_.Exception.Message)" } } } function Move-DirectoryTree { # Move entire subdir tree from $SourceDir to $TargetDir (preserving relative structure). param([string]$SourceDir, [string]$TargetDir) if (-not [System.IO.Directory]::Exists($SourceDir)) { return } if (-not [System.IO.Directory]::Exists($TargetDir)) { [System.IO.Directory]::CreateDirectory($TargetDir) | Out-Null } $files = [System.IO.Directory]::EnumerateFiles($SourceDir, '*', [System.IO.SearchOption]::AllDirectories) foreach ($srcFile in $files) { $rel = $srcFile.Substring($SourceDir.Length + 1) $tgt = [System.IO.Path]::Combine($TargetDir, $rel) Move-FileNoConflict -Source $srcFile -Target $tgt } # Cleanup empty source dir try { [System.IO.Directory]::Delete($SourceDir, $true) } catch {} } $exts = @('.dll', '.pdb', '.xml') # 1) Root *.dll / *.pdb / *.xml -> Runtime root $rootFiles = [System.IO.Directory]::EnumerateFiles($root) foreach ($file in $rootFiles) { $ext = [System.IO.Path]::GetExtension($file) if ($exts -contains $ext) { $tgt = [System.IO.Path]::Combine($runtime, [System.IO.Path]::GetFileName($file)) Move-FileNoConflict -Source $file -Target $tgt } } # 2) Plugins\* -> Runtime\Plugins (preserve tree) $pluginsSrc = Join-Path $root 'Plugins' if ([System.IO.Directory]::Exists($pluginsSrc)) { Move-DirectoryTree -SourceDir $pluginsSrc -TargetDir $pluginsDest } # 3) dll\* -> Runtime\dll (preserve tree) $dllSrc = Join-Path $root 'dll' if ([System.IO.Directory]::Exists($dllSrc)) { Move-DirectoryTree -SourceDir $dllSrc -TargetDir (Join-Path $runtime 'dll') } # 4) createdump.exe -> Runtime $createdump = Join-Path $root 'createdump.exe' if ([System.IO.File]::Exists($createdump)) { $tgt = Join-Path $runtime 'createdump.exe' Move-FileNoConflict -Source $createdump -Target $tgt } # 5) All other subfolders in root (not in config-class whitelist, not Runtime itself) -> Runtime\ # Covers satellite culture folders (zh-CN, en-US, ...) and any future non-config folders. $subDirs = [System.IO.Directory]::GetDirectories($root) foreach ($d in $subDirs) { $name = [System.IO.Path]::GetFileName($d) if ($configFolders -notcontains $name) { Move-DirectoryTree -SourceDir $d -TargetDir (Join-Path $runtime $name) } } Write-Host "[PostBuild] OK: root keeps EXE + config folders, others in $runtime"