PowerShell_Scripts/base/Move-WithRsync.ps1

144 lines
4.2 KiB
PowerShell

[CmdletBinding(SupportsShouldProcess,ConfirmImpact='Medium')]param(
[Parameter(Mandatory,ParameterSetName="RemoteSrc")]
[string]$RemoteSrc,
[Parameter(Mandatory,ParameterSetName="Local",Position=1)]
[Parameter(Mandatory,ParameterSetName="RemoteSrc",Position=1)]
[Parameter(Mandatory,ParameterSetName="RemoteDst",Position=1)]
[string]$SrcBase,
[Parameter(Mandatory,ParameterSetName="Local",Position=2)]
[Parameter(Mandatory,ParameterSetName="RemoteSrc",Position=2)]
[Parameter(Mandatory,ParameterSetName="RemoteDst",Position=2)]
[string]$DstBase,
[Parameter(Mandatory,ParameterSetName="RemoteDst")]
[string]$RemoteDst,
[Parameter(Position=4)]
[string]$Path=".",
[switch]$NoPassThru,
[int]$Depth=-1,
[int]$Limit,
[Alias("Do")]
[switch]$NoSimulate
)
Write-Host -ForegroundColor Cyan ( $PSCmdlet | Out-String )
Write-Host -ForegroundColor Yellow ( $PSBoundParameters | Out-String )
function GetLocalPath{
[CmdletBinding(SupportsShouldProcess,ConfirmImpact='Low')]param(
[string]$LocalBase,
[string]$Path = "."
)
return ([System.IO.Path]::GetFullPath((Join-Path $LocalBase $Path),"/"))
}
function GetRemotePath{
[CmdletBinding(SupportsShouldProcess,ConfirmImpact='Low')]param(
[string]$RemoteAddr,
[string]$RemoteBase,
[string]$Path = "."
)
return "$RemoteAddr`:$(
[Management.Automation.WildcardPattern]::Escape(
[System.IO.Path]::GetFullPath((Join-Path $RemoteBase $Path),"/")
) -replace '([&\[\(\)\\])','\$1'
)"
}
function GetSubstituedPath{
[CmdletBinding(SupportsShouldProcess,ConfirmImpact='Low')]param(
[string]$OriginalPath,
[string]$Base,
[string]$ReplaceBase,
[string]$RemotePrefix
)
$local:newPath = $OriginalPath -replace "^$([regex]::Escape($Base))",($ReplaceBase -replace '\$(\d)','\$$1')
if( $RemotePrefix ) {
$newPath = GetRemotePath $RemotePrefix $newPath
}
return $newPath
}
$local:SrcPath = GetLocalPath $SrcBase $Path
$local:DstPath = GetLocalPath $DstBase $Path
$local:LocalPath = [string]::Empty
if( -not $RemoteSrc ) {
$LocalPath = $SrcPath
} else {
$LocalPath = $DstPath
}
function GetSortedDirsDepthFirst {
param([string]$Path,$StopDepth=-1,$CurrentDepth=0)
$local:dirs = Get-ChildItem $Path -Directory |
Sort-Object Name
foreach( $local:d in $dirs ) {
if( $StopDepth -lt 0 -or $CurrentDepth -lt $StopDepth ) {
GetSortedDirsDepthFirst $d.FullName $StopDepth ($CurrentDepth + 1)
}
$d
}
}
$local:limitParam = @{}
if( $Limit -gt 0 ) {
$limitParam.First = $Limit
}
$local:Pairs = @()
if( -not $RemoteSrc ) {
$Pairs = GetSortedDirsDepthFirst $LocalPath -StopDepth $Depth |
Select-Object @limitParam |
ForEach-Object {
[PSCustomObject]([ordered]@{
SrcGB = -1
Src = GetLocalPath $_.FullName
Dst = GetSubstituedPath $_.FullName $SrcPath $DstPath $RemoteDst
})
}
} else {
$Pairs = , ([PSCustomObject]([ordered]@{
Src = GetRemotePath $RemoteSrc $SrcPath
Dst = $DstPath
}))
}
$local:sw = [System.Diagnostics.Stopwatch]::StartNew();
$Pairs | ForEach-Object {
$local:s = $_.Src -replace "'",'${Q}'
$local:d = $_.Dst -replace "'",'\\${Q}'
$local:skip = $false
if( $_.SrcGB ) {
$_.SrcGB = [Math]::Round( (
Get-ChildItem -Recurse -File $_.Src | Measure-Object -Sum Length
).Sum / 1000000000, 2)
if( -not $_.SrcGB ) {
$_.SrcGB = "Skip"
} else {
$_.SrcGB = "$($_.SrcGB) GB"
}
}
Write-Host -ForegroundColor Cyan ($($_ | Format-Table -HideTableHeaders | Out-String).Trim())
$local:exp = "Q=\`"'\`"; rsync -avzh --remove-source-files --progress \`"$s/\`" \`"$d/\`""
$sw.Restart()
if( -not $_.SrcGB -or $_.SrcGB -ne "Skip" ) {
$exp | Out-Host
sh -c $exp | Out-Host
}
Write-Host -Cyan "Cleanup '$s'..."
$exp = "Q=\`"'\`"; find \`"$s\`" -type d -empty -delete"
sh -c $exp | Out-Host
[PSCustomObject]([ordered]@{
PSTypeName = 'RsyncReport'
SrcGB = $_.SrcGB
Elapsed = $sw.Elapsed
Src = $_.Src
Dst = $_.Dst
})
}