ManimCat / scripts /sync-space.ps1
Bin29's picture
Sync from main: c1ef036 chore: document docker persistence volumes
94e1b2f
param(
[string[]]$Remotes = @('space', 'space-show'),
[string]$SourceBranch = 'main',
[string]$TempBranch = '__space-sync-tmp',
[switch]$AutoStash = $true,
[switch]$IncludeUntracked = $true
)
$ErrorActionPreference = 'Stop'
$excludePatterns = @(
'public/readme-images/*.png',
'src/audio/tracks/*.mp3'
)
$hfReadmeFrontmatterPath = Join-Path $PSScriptRoot 'hf-readme-frontmatter.txt'
function Remove-ReadmeFrontmatter {
param(
[Parameter(Mandatory = $true)]
[string]$Content
)
if (-not $Content.StartsWith("---`n") -and -not $Content.StartsWith("---`r`n")) {
return $Content
}
$normalized = $Content -replace "`r`n", "`n"
$lines = $normalized -split "`n"
if ($lines.Count -lt 3 -or $lines[0] -ne '---') {
return $Content
}
for ($i = 1; $i -lt $lines.Count; $i++) {
if ($lines[$i] -eq '---') {
$remaining = if ($i + 1 -lt $lines.Count) {
($lines[($i + 1)..($lines.Count - 1)] -join "`n").TrimStart("`n")
} else {
''
}
if ([string]::IsNullOrEmpty($remaining)) {
return ''
}
return $remaining
}
}
return $Content
}
function Update-SpaceReadme {
$readmePath = Join-Path (Get-Location) 'README.md'
if (-not (Test-Path $readmePath) -or -not (Test-Path $hfReadmeFrontmatterPath)) {
return
}
$frontmatter = [System.IO.File]::ReadAllText($hfReadmeFrontmatterPath).Trim()
$readmeBody = [System.IO.File]::ReadAllText($readmePath)
$strippedBody = (Remove-ReadmeFrontmatter -Content $readmeBody).TrimStart()
$updatedReadme = "$frontmatter`r`n`r`n$strippedBody"
[System.IO.File]::WriteAllText($readmePath, $updatedReadme)
}
function Invoke-Git {
param(
[Parameter(Mandatory = $true)]
[string[]]$Args,
[string]$ErrorMessage = 'Git command failed.'
)
& git @Args
if ($LASTEXITCODE -ne 0) {
throw $ErrorMessage
}
}
function Get-TrimmedGitOutput {
param(
[Parameter(Mandatory = $true)]
[string[]]$Args,
[string]$ErrorMessage = 'Git command failed.'
)
$output = (& git @Args)
if ($LASTEXITCODE -ne 0) {
throw $ErrorMessage
}
return ($output | Out-String).Trim()
}
function Test-GitRemoteExists {
param(
[Parameter(Mandatory = $true)]
[string]$Remote
)
& git remote get-url $Remote *> $null
return $LASTEXITCODE -eq 0
}
$resolvedRemotes = @($Remotes | Where-Object { -not [string]::IsNullOrWhiteSpace($_) })
if ($resolvedRemotes.Count -eq 0) {
throw 'Error: no remotes specified.'
}
$missingRemotes = @($resolvedRemotes | Where-Object { -not (Test-GitRemoteExists $_) })
if ($missingRemotes.Count -gt 0) {
throw "Error: remote not found: $($missingRemotes -join ', ')"
}
$current = Get-TrimmedGitOutput -Args @('branch', '--show-current') -ErrorMessage 'Failed to read current branch.'
if ($current -ne $SourceBranch) {
throw "Error: please checkout $SourceBranch first"
}
$status = Get-TrimmedGitOutput -Args @('status', '--porcelain') -ErrorMessage 'Failed to check working tree status.'
$workingTreeDirty = -not [string]::IsNullOrWhiteSpace($status)
$stashCreated = $false
$createdTempBranch = $false
$pushFailures = New-Object System.Collections.Generic.List[string]
try {
if ($workingTreeDirty) {
if (-not $AutoStash) {
throw 'Error: working tree not clean, please commit or stash first'
}
Write-Host 'Working tree is not clean. Auto-stashing changes...'
$stashArgs = @('stash', 'push', '-m', '__space_sync_auto__')
if ($IncludeUntracked) {
$stashArgs += '--include-untracked'
}
Invoke-Git -Args $stashArgs -ErrorMessage 'Failed to stash working tree.'
$stashCreated = $true
}
Invoke-Git -Args @('checkout', '--orphan', $TempBranch) -ErrorMessage 'Failed to create orphan temp branch.'
$createdTempBranch = $true
Update-SpaceReadme
Invoke-Git -Args @('add', '-A') -ErrorMessage 'Failed to stage files on temp branch.'
foreach ($pattern in $excludePatterns) {
& git rm -rf --cached --ignore-unmatch -- $pattern 2>$null
if ($LASTEXITCODE -ne 0) {
Write-Host "Warning: failed to exclude pattern: $pattern"
}
}
$head = Get-TrimmedGitOutput -Args @('log', $SourceBranch, '-1', "--format=%h %s") -ErrorMessage "Failed to get latest commit from $SourceBranch."
Invoke-Git -Args @('commit', '-m', "Sync from ${SourceBranch}: $head") -ErrorMessage 'Failed to create sync snapshot commit.'
foreach ($remote in $resolvedRemotes) {
Write-Host "Pushing to $remote..."
& git push $remote "${TempBranch}:main" --force
if ($LASTEXITCODE -eq 0) {
Write-Host " ✓ $remote pushed"
} else {
Write-Host " ✗ $remote push failed"
$pushFailures.Add($remote) | Out-Null
}
}
if ($pushFailures.Count -gt 0) {
throw "Push failed for remotes: $($pushFailures -join ', ')"
}
}
finally {
if ($createdTempBranch) {
& git checkout -f $SourceBranch | Out-Null
if ($LASTEXITCODE -ne 0) {
Write-Host "Warning: failed to switch back to $SourceBranch"
}
& git branch -D $TempBranch | Out-Null
if ($LASTEXITCODE -ne 0) {
Write-Host "Warning: failed to delete temp branch $TempBranch"
}
}
if ($stashCreated) {
Write-Host 'Restoring stashed changes...'
& git stash pop --index 'stash@{0}' | Out-Null
if ($LASTEXITCODE -ne 0) {
Write-Host 'Warning: failed to auto-restore stash. Recover it manually with: git stash list'
}
}
}
Write-Host 'Done!'