Public/Get-RecentSvnFiles.ps1
|
function Get-RecentSvnFiles { <# .SYNOPSIS Lists files committed to Subversion within a recent time window as full local working-copy paths. .DESCRIPTION Runs 'svn log' (verbose, XML) over the requested time range and maps the repository-relative paths of the changed items back onto the current working copy. Only files that were Added, Modified, or Replaced and that still exist on disk are returned, so the output can be piped straight into Find-InvalidUtf8.ps1. .PARAMETER Hours How far back to look, in hours. Defaults to 24. .PARAMETER Path Working-copy path to inspect. Defaults to the current directory. .PARAMETER Action SVN change actions to include. Defaults to A (added), M (modified), R (replaced). 'D' (deleted) is intentionally excluded since those files no longer exist locally. .EXAMPLE Get-RecentSvnFiles .EXAMPLE Get-RecentSvnFiles -Hours 72 | Find-InvalidUtf8 .EXAMPLE Get-RecentSvnFiles -Path .\Public -Hours 8 #> [CmdletBinding()] param( [ValidateRange(1, 100000)] [int]$Hours = 24, [string]$Path = '.', [ValidateSet('A', 'M', 'R', 'D')] [string[]]$Action = @('A', 'M', 'R') ) if (-not (Get-Command svn -ErrorAction SilentlyContinue)) { throw "The 'svn' command-line client was not found on PATH." } $wcPath = (Resolve-Path -LiteralPath $Path -ErrorAction Stop).ProviderPath # Gather working-copy layout so repo paths can be mapped to local paths. [xml]$infoXml = svn info --xml -- $wcPath 2>$null if (-not $infoXml.info.entry) { throw "'$wcPath' does not appear to be an SVN working copy." } $entry = $infoXml.info.entry $repoRoot = [Uri]::UnescapeDataString($entry.repository.root) $wcUrl = [Uri]::UnescapeDataString($entry.url) # Repository-relative prefix of the queried path, e.g. "/trunk/Source/Core". # The log below is scoped to $wcPath, so every changed path lives under this # prefix and maps directly onto $wcPath. $wcRepoRel = $wcUrl.Substring($repoRoot.Length) # SVN accepts an ISO date/time inside {} for a revision boundary. $since = (Get-Date).AddHours(-$Hours).ToString('yyyy-MM-ddTHH:mm:ss') $revRange = "{{{0}}}:HEAD" -f $since [xml]$logXml = svn log -v --xml -r $revRange -- $wcPath 2>$null if (-not $logXml.log.logentry) { Write-Verbose "No commits found in the last $Hours hour(s)." return } $results = [System.Collections.Generic.HashSet[string]]::new( [System.StringComparer]::OrdinalIgnoreCase) foreach ($logentry in $logXml.log.logentry) { foreach ($p in $logentry.paths.path) { if ($Action -notcontains $p.action) { continue } if ($p.kind -and $p.kind -eq 'dir') { continue } $repoPath = $p.'#text' if (-not $repoPath.StartsWith($wcRepoRel, [StringComparison]::OrdinalIgnoreCase)) { continue } $rel = $repoPath.Substring($wcRepoRel.Length).TrimStart('/') $local = Join-Path $wcPath ($rel -replace '/', '\') if (Test-Path -LiteralPath $local -PathType Leaf) { [void]$results.Add((Resolve-Path -LiteralPath $local).ProviderPath) } } } $results | Sort-Object } |